5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
10 #include <mit-copyright.h>
11 #include "mr_server.h"
15 #include <arpa/inet.h>
16 #include <netinet/in.h>
22 EXEC SQL INCLUDE sqlca;
27 extern int dbms_errno, mr_errcode;
29 EXEC SQL BEGIN DECLARE SECTION;
30 extern char stmt_buf[];
31 EXEC SQL END DECLARE SECTION;
33 EXEC SQL WHENEVER SQLERROR DO dbmserr();
35 int hostname_check(char *name);
36 int hostinfo_check(char *name, int num);
37 int prefetch_value(struct query *q, char **argv, client *cl);
38 int check_nfs(int mach_idx, char *name, char *access);
42 /* Setup routine for add_user
44 * Inputs: argv[0] - login
49 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
50 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
53 int setup_ausr(struct query *q, char *argv[], client *cl)
56 EXEC SQL BEGIN DECLARE SECTION;
58 EXEC SQL END DECLARE SECTION;
60 if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
67 if (strlen(argv[row + 3]) + strlen(argv[row + 4]) +
68 strlen(argv[row + 5]) + 2 > USERS_FULLNAME_SIZE)
69 return MR_ARG_TOO_LONG;
73 if (strlen(argv[row + 2]) + strlen(argv[row + 3]) +
74 strlen(argv[row + 4]) + 2 > USERS_FULLNAME_SIZE)
75 return MR_ARG_TOO_LONG;
78 if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1)
80 if ((err = set_next_object_id("unix_uid", USERS_TABLE, 1)))
82 EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'unix_uid';
83 if (sqlca.sqlerrd[2] != 1)
85 sprintf(argv[row], "%d", nuid);
88 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1)
89 sprintf(argv[0], "#%s", argv[row]);
91 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
94 /* If this is an UPDATE query, we're done. */
98 /* For an add query, we need to fill in the creator id. */
99 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
104 /* setup_dusr - verify that the user is no longer being referenced
105 * and may safely be deleted.
108 int setup_dusr(struct query *q, char *argv[], client *cl)
110 EXEC SQL BEGIN DECLARE SECTION;
112 char resv[USERS_RESERVATIONS_SIZE];
113 EXEC SQL END DECLARE SECTION;
115 id = *(int *)argv[0];
117 /* For now, only allow users to be deleted if their status is
118 * one of 0, 4, or 8 (the various registerable statuses)
119 * and we have no reservations about deleting them.
121 EXEC SQL SELECT status, reservations INTO :flag, :resv
122 FROM users WHERE users_id = :id;
123 if ((flag != 0 && flag != 4 && flag != 8) || *resv)
126 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
127 WHERE member_id = :id AND member_type = 'USER';
130 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
134 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
135 WHERE acl_id = :id AND acl_type = 'USER';
138 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
139 WHERE acl_id = :id AND acl_type = 'USER';
142 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
143 WHERE acl_id = :id AND acl_type = 'USER';
149 EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
150 EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
155 /* setup_dpob: Take care of keeping track of the post office usage.
157 int setup_dpob(struct query *q, char *argv[], client *cl)
159 EXEC SQL BEGIN DECLARE SECTION;
161 char type[USERS_POTYPE_SIZE];
162 EXEC SQL END DECLARE SECTION;
164 user = *(int *)argv[0];
165 EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
166 WHERE users_id = :user;
170 if (!strcmp(strtrim(type), "POP"))
171 set_pop_usage(id, -1);
176 /* setup_dmac - verify that the machine is no longer being referenced
177 * and may safely be deleted.
180 int setup_dmac(struct query *q, char *argv[], client *cl)
182 EXEC SQL BEGIN DECLARE SECTION;
184 EXEC SQL END DECLARE SECTION;
186 id = *(int *)argv[0];
188 EXEC SQL SELECT status INTO :flag FROM machine
192 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
193 WHERE potype = 'POP' AND pop_id = :id;
196 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
200 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
204 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
208 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
212 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
216 EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
220 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
224 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
228 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
229 WHERE member_type = 'MACHINE' and member_id = :id;
233 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
237 EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id;
243 /* setup_asnt - verify that the data entered for the subnet is sane.
244 * In particular, make sure that the "low" and "high" addresses are
245 * correctly ordered, i.e., high > low.
248 int setup_asnt(struct query *q, char *argv[], client *cl)
250 int high, low, row, status;
251 char *account_number;
253 /* Check for asnt or usnt. */
254 if (q->type == APPEND)
259 low = atoi(argv[row + 7]);
260 high = atoi(argv[row + 8]);
261 status = atoi(argv[row + 2]);
262 account_number = argv[row + 4];
264 /* Don't allow Private subnets to be created without a valid billing
267 if (status == SNET_STATUS_PRIVATE_10MBPS ||
268 status == SNET_STATUS_PRIVATE_100MBPS ||
269 status == SNET_STATUS_PRIVATE_1000MBPS)
271 EXEC SQL SELECT account_number FROM accountnumbers
272 WHERE account_number = :account_number;
273 if (sqlca.sqlcode == SQL_NO_MATCH)
274 return MR_ACCOUNT_NUMBER;
277 /* Special case 0.0.0.0 and 255.255.255.255 */
278 if (!(low == 0 || low == -1 || high == 0 || high == -1))
282 /* If this is update_subnet, we're done. */
286 /* For an add_subnet query, allocate and fill in a new snet_id */
287 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
293 /* setup_dsnt - verify that the subnet is no longer being referenced
294 * and may safely be deleted.
297 int setup_dsnt(struct query *q, char *argv[], client *cl)
299 EXEC SQL BEGIN DECLARE SECTION;
301 EXEC SQL END DECLARE SECTION;
303 id = *(int *)argv[0];
304 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
312 /* setup_dclu - verify that the cluster is no longer being referenced
313 * and may safely be deleted.
316 int setup_dclu(struct query *q, char *argv[], client *cl)
318 EXEC SQL BEGIN DECLARE SECTION;
320 EXEC SQL END DECLARE SECTION;
322 id = *(int *)argv[0];
323 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
327 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
337 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
338 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
339 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
340 * a -1 there. Remember that this is also used for ulis, with the indexes
341 * at 6 & 7. Also check that the list name does not contain uppercase
342 * characters, control characters, @, or :.
344 * Newlines in list descriptions do bad things to the aliases file
345 * moira generates, so make sure the description doesn't contain any, too.
348 static int badlistchars[] = {
349 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
350 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
351 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
352 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
353 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
354 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
355 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
357 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
358 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
359 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
360 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
361 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
362 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
363 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
364 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
367 int setup_alis(struct query *q, char *argv[], client *cl)
369 EXEC SQL BEGIN DECLARE SECTION;
372 EXEC SQL END DECLARE SECTION;
376 if (!strcmp(q->shortname, "alis"))
378 else if (!strcmp(q->shortname, "ulis"))
383 desc = argv[9 + idx];
384 else if (q->version == 3)
385 desc = argv[10 + idx];
386 else if (q->version >= 4)
387 desc = argv[12 + idx];
391 EXEC SQL BEGIN DECLARE SECTION;
392 int lid = *(int *)argv[0];
393 EXEC SQL END DECLARE SECTION;
395 if (acl_access_check(lid, cl))
399 for (p = (unsigned char *) name; *p; p++)
401 if (badlistchars[*p])
405 for (p = (unsigned char *) desc; *p; p++)
411 /* Check that it doesn't conflict with a pre-existing weirdly-cased
413 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
414 WHERE LOWER(name) = :name AND name != :name;
418 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
420 if (atoi(argv[5 + idx]))
422 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
424 EXEC SQL SELECT value INTO :ngid FROM numvalues
428 sprintf(argv[6 + idx], "%d", ngid);
431 strcpy(argv[6 + idx], "-1");
434 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
441 /* setup_dlis - verify that the list is no longer being referenced
442 * and may safely be deleted.
445 int setup_dlis(struct query *q, char *argv[], client *cl)
448 EXEC SQL BEGIN DECLARE SECTION;
450 EXEC SQL END DECLARE SECTION;
452 id = *(int *)argv[0];
454 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
455 WHERE member_id = :id AND member_type = 'LIST';
459 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
460 WHERE member_id = :id AND member_type = 'LIST';
464 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
469 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
473 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
477 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
478 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
482 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
483 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
487 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
488 WHERE acl_id = :id AND acl_type = 'LIST';
492 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
493 WHERE entity_id = :id AND type = 'GROUP';
497 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
498 WHERE acl_id = :id AND acl_type = 'LIST';
502 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
503 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
504 OR z.sub_type = 'LIST' AND z.sub_id = :id
505 OR z.iws_type = 'LIST' AND z.iws_id = :id
506 OR z.iui_type = 'LIST' AND z.iui_id = :id
507 OR z.owner_type = 'LIST' and z.owner_id = :id;
511 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
512 WHERE lpc_acl = :id OR ac = :id;
516 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
517 WHERE owner_type = 'LIST' AND owner_id = :id
522 EXEC SQL SELECT count(name) INTO :cnt FROM containers
523 WHERE acl_id = :id AND acl_type = 'LIST';
527 EXEC SQL SELECT count(name) INTO :cnt FROM containers
528 WHERE memacl_id = :id AND memacl_type = 'LIST';
536 /* setup_dsin - verify that the service is no longer being referenced
537 * and may safely be deleted.
540 int setup_dsin(struct query *q, char *argv[], client *cl)
542 EXEC SQL BEGIN DECLARE SECTION;
545 EXEC SQL END DECLARE SECTION;
548 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
549 WHERE service = UPPER(:svrname);
553 EXEC SQL SELECT inprogress INTO :ec FROM servers
554 WHERE name = UPPER(:svrname);
564 /* setup_dshi - verify that the service-host is no longer being referenced
565 * and may safely be deleted.
568 int setup_dshi(struct query *q, char *argv[], client *cl)
570 EXEC SQL BEGIN DECLARE SECTION;
573 EXEC SQL END DECLARE SECTION;
576 id = *(int *)argv[1];
578 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
579 WHERE service = UPPER(:svrname) AND mach_id = :id;
590 ** setup_add_filesys - verify existance of referenced file systems
596 ** argv[5] - rwaccess
601 ** - for type = NFS/IMAP:
602 ** * extract directory prefix from name
603 ** * verify mach_id/dir in nfsphys
604 ** * verify rwaccess in {r, w, R, W}
606 ** Side effect: sets variable _var_phys_id to the ID of the physical
607 ** filesystem (nfsphys_id for NFS, 0 for RVD)
610 ** MR_NFS - specified directory not exported
611 ** MR_FILESYS_ACCESS - invalid filesys access
615 EXEC SQL BEGIN DECLARE SECTION;
617 EXEC SQL END DECLARE SECTION;
619 int setup_afil(struct query *q, char *argv[], client *cl)
623 EXEC SQL BEGIN DECLARE SECTION;
625 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
626 EXEC SQL END DECLARE SECTION;
629 mach_id = *(int *)argv[2];
634 sprintf(ftype, "fs_access_%s", type);
635 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
636 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
640 return MR_FILESYS_ACCESS;
642 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
645 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
646 return check_nfs(mach_id, name, rwaccess);
652 /* Verify the arguments, depending on the FStype. Also, if this is an
653 * NFS filesystem, then update any quotas for that filesystem to reflect
657 int setup_ufil(struct query *q, char *argv[], client *cl)
661 EXEC SQL BEGIN DECLARE SECTION;
662 int fid, total, who, ok;
663 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
664 short int total_null;
665 EXEC SQL END DECLARE SECTION;
669 mach_id = *(int *)argv[3];
672 fid = *(int *)argv[0];
676 sprintf(ftype, "fs_access_%s", type);
677 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
678 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
682 return MR_FILESYS_ACCESS;
684 EXEC SQL SELECT type INTO :ftype FROM filesys
685 WHERE filsys_id = :fid;
689 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
691 status = check_nfs(mach_id, name, access);
692 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
693 WHERE filsys_id = :fid;
698 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
699 && strcmp(strtrim(ftype), "ERR"))
702 EXEC SQL DELETE FROM quota
703 WHERE type = 'ANY' AND filsys_id = :fid;
704 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
705 WHERE filsys_id = :fid AND phys_id != 0;
708 if (!total_null && (total != 0))
710 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
711 type, modtime, modby, modwith)
712 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
719 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
727 /* Find the NFS physical partition that the named directory is on.
728 * This is done by comparing the dir against the mount point of the
729 * partition. To make sure we get the correct match when there is
730 * more than one, we sort the query in reverse order by dir name.
733 int check_nfs(int mach_id, char *name, char *access)
735 EXEC SQL BEGIN DECLARE SECTION;
736 char dir[NFSPHYS_DIR_SIZE];
738 EXEC SQL END DECLARE SECTION;
744 EXEC SQL DECLARE csr101 CURSOR FOR
745 SELECT nfsphys_id, dir FROM nfsphys
750 EXEC SQL OPEN csr101;
755 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
772 EXEC SQL CLOSE csr101;
779 /* setup_dfil: free any quota records and fsgroup info associated with
780 * a filesystem when it is deleted. Also adjust the allocation numbers.
783 int setup_dfil(struct query *q, char **argv, client *cl)
785 EXEC SQL BEGIN DECLARE SECTION;
786 int id, total, phys_id;
788 EXEC SQL END DECLARE SECTION;
790 id = *(int *)argv[0];
791 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
792 WHERE filsys_id = :id;
797 /** What if there are multiple phys_id's per f/s? (bad data) **/
798 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
799 WHERE filsys_id = :id;
800 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
801 WHERE nfsphys_id = :phys_id;
804 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
805 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
806 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
813 /* setup_dnfp: check to see that the nfs physical partition does not have
814 * any filesystems assigned to it before allowing it to be deleted.
817 int setup_dnfp(struct query *q, char **argv, client *cl)
819 EXEC SQL BEGIN DECLARE SECTION;
822 EXEC SQL END DECLARE SECTION;
824 id = *(int *)argv[0];
826 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
827 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
828 AND np.mach_id = :id AND np.dir = :dir;
837 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
838 * argv[0] = filsys_id
839 * argv[1] = type if "update_quota" or "delete_quota"
840 * argv[2 or 1] = users_id or list_id
843 int setup_dqot(struct query *q, char **argv, client *cl)
845 EXEC SQL BEGIN DECLARE SECTION;
846 int quota, fs, id, physid;
848 EXEC SQL END DECLARE SECTION;
850 fs = *(int *)argv[0];
851 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
854 id = *(int *)argv[2];
859 id = *(int *)argv[1];
862 EXEC SQL SELECT quota INTO :quota FROM quota
863 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
864 EXEC SQL SELECT phys_id INTO :physid FROM filesys
865 WHERE filsys_id = :fs;
866 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
867 WHERE nfsphys_id = :physid;
876 * This routine fetches an appropriate value from the numvalues table.
877 * It is a little hack to get around the fact that SQL doesn't let you
878 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
880 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
881 * from within a setup_...() routine with the appropriate arguments.
883 * Correct functioning of this routine may depend on the assumption
884 * that this query is an APPEND.
887 int prefetch_value(struct query *q, char **argv, client *cl)
889 EXEC SQL BEGIN DECLARE SECTION;
890 char *name = q->validate->object_id;
892 EXEC SQL END DECLARE SECTION;
893 int status, limit, argc;
895 /* set next object id, limiting it if necessary */
896 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
897 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
900 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
903 /* fetch object id */
904 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
907 if (sqlca.sqlerrd[2] != 1)
910 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
911 sprintf(argv[argc], "%d", value);
916 /* prefetch_filesys():
917 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
918 * Appends the filsys_id and the phys_id to the argv so they can be
919 * referenced in an INSERT into a table other than filesys. Also
920 * see comments at prefetch_value().
922 * Assumes the existence of a row where filsys_id = argv[0], since a
923 * filesys label has already been resolved to a filsys_id.
925 int prefetch_filesys(struct query *q, char **argv, client *cl)
927 EXEC SQL BEGIN DECLARE SECTION;
929 EXEC SQL END DECLARE SECTION;
932 fid = *(int *)argv[0];
933 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
937 argc = q->argc + q->vcnt;
938 sprintf(argv[argc++], "%d", phid);
939 sprintf(argv[argc], "%d", fid);
948 int setup_ahst(struct query *q, char **argv, client *cl)
950 EXEC SQL BEGIN DECLARE SECTION;
951 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
952 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
953 int value, id, ssaddr, smask, shigh, slow, cnt;
954 unsigned int saddr, mask, high, low;
955 EXEC SQL END DECLARE SECTION;
959 id = *(int *)argv[0];
961 if (!strcmp(q->shortname, "uhst"))
964 EXEC SQL SELECT name, vendor, model, os
965 INTO :oldname, :vendor, :model, :os
966 FROM machine WHERE mach_id = :id;
973 else if (q->version >= 6 && q->version < 8)
978 /* Sanity check name, vendor, model, and os. */
979 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
980 !hostname_check(argv[row]))
982 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
983 !hostinfo_check(argv[row + 1], 0))
985 if ((row == 0 || strcasecmp(argv[3], model)) &&
986 !hostinfo_check(argv[row + 2], 1))
988 if ((row == 0 || strcasecmp(argv[4], os)) &&
989 !hostinfo_check(argv[row + 3], 0))
992 /* check for duplicate name */
994 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
995 WHERE name = UPPER(:name);
1002 if (!strcmp(argv[9 + row + idx], "unassigned"))
1004 else if (!strcmp(argv[9 + row + idx], "unique"))
1006 if (*(int *)argv[8 + row + idx] == 0)
1013 value = ntohl(inet_addr(argv[9 + row + idx]));
1022 * an address or unique was specified.
1024 id = *(int *)argv[8 + row + idx];
1025 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1026 :shigh, :slow FROM subnet WHERE snet_id = :id;
1029 saddr = (unsigned) ssaddr;
1030 mask = (unsigned) smask;
1031 high = (unsigned) shigh;
1032 low = (unsigned) slow;
1036 * someone specified an IP address for the host record
1038 if ((value & mask) != saddr || value < low || value > high)
1041 * run the address argument through inet_addr(). This
1042 * has the effect that any out of bounds host addrs will
1043 * be converted to a valid host addr. We do this now
1044 * so that the uniqueness check works. We should also
1045 * link in an inet_addr() that returns an error for
1048 addr.s_addr = inet_addr(argv[9 + row + idx]);
1049 name = inet_ntoa(addr);
1050 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1051 WHERE address = :name;
1057 * make IP address is unique. If this a modify request
1058 * (row == 1), then we expect one record to exist.
1060 if (row == 0 || (row == 1 && cnt > 1))
1062 if (row == 1 && cnt == 1)
1064 EXEC SQL SELECT mach_id INTO :id FROM machine
1065 WHERE address = :name;
1066 if (id != *(int *)argv[0])
1074 * a "unique" address was specified. Walk through the
1075 * range specified in the network record, return
1076 * error if no room left.
1078 for (id = low; id <= high; id++)
1080 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1082 addr.s_addr = htonl(id);
1083 name = inet_ntoa(addr);
1084 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1085 WHERE address = :name;
1097 * we have an address in value. Convert it to a string and store it.
1099 addr.s_addr = htonl(value);
1100 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1103 strcpy(argv[9 + row + idx], "unassigned");
1105 /* status checking */
1106 value = atoi(argv[7 + row + idx]);
1107 if (row == 0 && !(value == 1 || value == 0))
1111 id = *(int *)argv[0];
1112 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1117 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1118 WHERE mach_id = :id;
1123 * If this is an update_host query, we're done.
1129 * For an add_host query, allocate and fill in a new machine id,
1130 * and then insert the creator id.
1132 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1135 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1143 int setup_ahal(struct query *q, char **argv, client *cl)
1145 EXEC SQL BEGIN DECLARE SECTION;
1148 EXEC SQL END DECLARE SECTION;
1152 if (!hostname_check(argv[0]))
1155 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1156 name = UPPER(:name);
1165 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1168 int setup_uhha(struct query *q, char **argv, client *cl)
1170 EXEC SQL BEGIN DECLARE SECTION;
1171 char *hwaddr = argv[1];
1173 EXEC SQL END DECLARE SECTION;
1176 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1178 for (p = hwaddr; *p; p++)
1185 if (p != hwaddr + 12)
1188 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1189 FROM machine WHERE hwaddr = :hwaddr;
1191 return MR_NOT_UNIQUE;
1197 /* setup_aprn(): Make sure name/duplexname don't conflict with
1198 * anything. If [ANY] was specified for the spooling host, pick the
1199 * least loaded print server that serves this kind of printer.
1201 int setup_aprn(struct query *q, char **argv, client *cl)
1205 EXEC SQL BEGIN DECLARE SECTION;
1206 int mid, usage, count;
1207 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1208 EXEC SQL END DECLARE SECTION;
1210 /* Check for aprn or uprn. */
1211 if (q->type == APPEND)
1216 name = argv[PRN_NAME + row];
1217 duplexname = argv[PRN_DUPLEXNAME + row];
1224 if (q->type == APPEND)
1226 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1227 WHERE name = :name OR duplexname = :name;
1231 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1232 WHERE ( name = :name OR duplexname = :name )
1233 AND name != :oldname;
1238 return MR_NOT_UNIQUE;
1243 if (q->type == APPEND)
1245 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1246 WHERE name = :duplexname OR duplexname = :duplexname;
1250 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1251 WHERE ( name = :duplexname OR duplexname = :duplexname )
1252 AND name != :oldname;
1258 return MR_NOT_UNIQUE;
1261 if (!strcmp(name, duplexname))
1262 return MR_NOT_UNIQUE;
1264 mid = *(int *)argv[PRN_RM + row];
1267 EXEC SQL DECLARE csr_rm CURSOR FOR
1268 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1270 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1272 AND ps.printer_types = s.string_id;
1275 EXEC SQL OPEN csr_rm;
1281 EXEC SQL FETCH csr_rm INTO :mid, :types;
1285 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1287 if (!strcasecmp(argv[PRN_TYPE + row], p))
1289 EXEC SQL SELECT COUNT(name) INTO :usage
1290 FROM printers WHERE rm = :mid;
1292 if (best < 0 || usage < best)
1295 *(int *)argv[PRN_RM + row] = mid;
1301 EXEC SQL CLOSE csr_rm;
1310 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1311 WHERE mach_id = :mid;
1319 int setup_dpsv(struct query *q, char **argv, client *cl)
1322 EXEC SQL BEGIN DECLARE SECTION;
1324 EXEC SQL END DECLARE SECTION;
1326 id = *(int *)argv[0];
1328 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1336 int setup_dcon(struct query *q, char *argv[], client *cl)
1338 EXEC SQL BEGIN DECLARE SECTION;
1340 char containername[CONTAINERS_NAME_SIZE];
1341 EXEC SQL END DECLARE SECTION;
1343 id = *(int *)argv[0];
1344 /* check to see if there are machines in this container */
1345 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1350 /* check to see if there are subcontainers in this container */
1352 /* get the container name */
1354 EXEC SQL SELECT name INTO :containername
1358 /* trim off the trailing spaces */
1359 strcpy(containername, strtrim(containername));
1361 EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1362 WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
1372 int setup_scli(struct query *q, char *argv[], client *cl)
1374 EXEC SQL BEGIN DECLARE SECTION;
1375 int cnt_id, list_id;
1376 EXEC SQL END DECLARE SECTION;
1378 cnt_id = *(int *)argv[0];
1379 /* Check if someone has already set the list for this container */
1380 EXEC SQL SELECT list_id INTO :list_id FROM containers
1381 WHERE cnt_id = :cnt_id;
1392 * validate the rfc1035/rfc1123-ness of a hostname
1395 int hostname_check(char *name)
1400 /* Sanity check name: must contain only letters, numerals, and
1401 * hyphen, and not start or end with a hyphen. Also make sure no
1402 * label (the thing the .s seperate) is longer than 63 characters,
1406 for (p = name, count = 0; *p; p++)
1409 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1410 (*p == '-' && p[1] == '.'))
1421 if (*(p - 1) == '-')
1426 int hostinfo_check(char *info, int num)
1433 /* Sanity check host hostinfo: must start with a letter (or number
1434 * if num is true), contain only letters, numerals, and hyphen, and
1435 * not end with a hyphen.
1438 if (!isalpha(*info) && (!num || !isdigit(*info)))
1440 for (p = info; *p; p++)
1442 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1443 (*p == '-' && p[1] == '.'))
1446 if (!isalnum(*(p - 1)))
1450 int setup_acon(struct query *q, char *argv[], client *cl)
1452 EXEC SQL BEGIN DECLARE SECTION;
1453 char containername[CONTAINERS_NAME_SIZE];
1454 EXEC SQL END DECLARE SECTION;
1458 memset(containername, 0, sizeof(containername));
1459 strcpy(containername, argv[0]);
1460 ptr = strrchr(containername, '/');
1461 /* sub container, check for parents */
1465 EXEC SQL SELECT * FROM containers
1466 WHERE lower(name) = lower(:containername);
1467 if (sqlca.sqlerrd[2] != 1)
1468 return MR_CONTAINER_NO_PARENT;
1471 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)