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 0
118 * and we have no reservations about deleting them.
120 EXEC SQL SELECT status, reservations INTO :flag, :resv
121 FROM users WHERE users_id = :id;
122 if ((flag != 0 && flag != 4) || *resv)
125 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
126 WHERE member_id = :id AND member_type = 'USER';
129 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
133 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
134 WHERE acl_id = :id AND acl_type = 'USER';
137 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
138 WHERE acl_id = :id AND acl_type = 'USER';
141 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
142 WHERE acl_id = :id AND acl_type = 'USER';
148 EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
149 EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
154 /* setup_dpob: Take care of keeping track of the post office usage.
156 int setup_dpob(struct query *q, char *argv[], client *cl)
158 EXEC SQL BEGIN DECLARE SECTION;
160 char type[USERS_POTYPE_SIZE];
161 EXEC SQL END DECLARE SECTION;
163 user = *(int *)argv[0];
164 EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
165 WHERE users_id = :user;
169 if (!strcmp(strtrim(type), "POP"))
170 set_pop_usage(id, -1);
175 /* setup_dmac - verify that the machine is no longer being referenced
176 * and may safely be deleted.
179 int setup_dmac(struct query *q, char *argv[], client *cl)
181 EXEC SQL BEGIN DECLARE SECTION;
183 EXEC SQL END DECLARE SECTION;
185 id = *(int *)argv[0];
187 EXEC SQL SELECT status INTO :flag FROM machine
191 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
192 WHERE potype = 'POP' AND pop_id = :id;
195 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
199 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
203 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
207 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
211 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
215 EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
219 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
223 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
227 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
228 WHERE member_type = 'MACHINE' and member_id = :id;
232 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
236 EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id;
242 /* setup_asnt - verify that the data entered for the subnet is sane.
243 * In particular, make sure that the "low" and "high" addresses are
244 * correctly ordered, i.e., high > low.
247 int setup_asnt(struct query *q, char *argv[], client *cl)
249 int high, low, row, status;
250 char *account_number;
252 /* Check for asnt or usnt. */
253 if (q->type == APPEND)
258 low = atoi(argv[row + 7]);
259 high = atoi(argv[row + 8]);
260 status = atoi(argv[row + 2]);
261 account_number = argv[row + 4];
263 /* Don't allow Private subnets to be created without a valid billing
266 if (status == SNET_STATUS_PRIVATE_10MBPS ||
267 status == SNET_STATUS_PRIVATE_100MBPS ||
268 status == SNET_STATUS_PRIVATE_1000MBPS)
270 EXEC SQL SELECT account_number FROM accountnumbers
271 WHERE account_number = :account_number;
272 if (sqlca.sqlcode == SQL_NO_MATCH)
273 return MR_ACCOUNT_NUMBER;
276 /* Special case 0.0.0.0 and 255.255.255.255 */
277 if (!(low == 0 || low == -1 || high == 0 || high == -1))
281 /* If this is update_subnet, we're done. */
285 /* For an add_subnet query, allocate and fill in a new snet_id */
286 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
292 /* setup_dsnt - verify that the subnet is no longer being referenced
293 * and may safely be deleted.
296 int setup_dsnt(struct query *q, char *argv[], client *cl)
298 EXEC SQL BEGIN DECLARE SECTION;
300 EXEC SQL END DECLARE SECTION;
302 id = *(int *)argv[0];
303 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
311 /* setup_dclu - verify that the cluster is no longer being referenced
312 * and may safely be deleted.
315 int setup_dclu(struct query *q, char *argv[], client *cl)
317 EXEC SQL BEGIN DECLARE SECTION;
319 EXEC SQL END DECLARE SECTION;
321 id = *(int *)argv[0];
322 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
326 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
336 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
337 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
338 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
339 * a -1 there. Remember that this is also used for ulis, with the indexes
340 * at 6 & 7. Also check that the list name does not contain uppercase
341 * characters, control characters, @, or :.
343 * Newlines in list descriptions do bad things to the aliases file
344 * moira generates, so make sure the description doesn't contain any, too.
347 static int badlistchars[] = {
348 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
349 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
350 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
351 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
353 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
354 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
355 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
356 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
366 int setup_alis(struct query *q, char *argv[], client *cl)
368 EXEC SQL BEGIN DECLARE SECTION;
371 EXEC SQL END DECLARE SECTION;
375 if (!strcmp(q->shortname, "alis"))
377 else if (!strcmp(q->shortname, "ulis"))
382 desc = argv[9 + idx];
383 else if (q->version == 3)
384 desc = argv[10 + idx];
385 else if (q->version >= 4)
386 desc = argv[12 + idx];
390 EXEC SQL BEGIN DECLARE SECTION;
391 int lid = *(int *)argv[0];
392 EXEC SQL END DECLARE SECTION;
394 if (acl_access_check(lid, cl))
398 for (p = (unsigned char *) name; *p; p++)
400 if (badlistchars[*p])
404 for (p = (unsigned char *) desc; *p; p++)
410 /* Check that it doesn't conflict with a pre-existing weirdly-cased
412 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
413 WHERE LOWER(name) = :name AND name != :name;
417 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
419 if (atoi(argv[5 + idx]))
421 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
423 EXEC SQL SELECT value INTO :ngid FROM numvalues
427 sprintf(argv[6 + idx], "%d", ngid);
430 strcpy(argv[6 + idx], "-1");
433 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
440 /* setup_dlis - verify that the list is no longer being referenced
441 * and may safely be deleted.
444 int setup_dlis(struct query *q, char *argv[], client *cl)
447 EXEC SQL BEGIN DECLARE SECTION;
449 EXEC SQL END DECLARE SECTION;
451 id = *(int *)argv[0];
453 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
454 WHERE member_id = :id AND member_type = 'LIST';
458 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
459 WHERE member_id = :id AND member_type = 'LIST';
463 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
468 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
472 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
476 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
477 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
481 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
482 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
486 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
487 WHERE acl_id = :id AND acl_type = 'LIST';
491 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
492 WHERE entity_id = :id AND type = 'GROUP';
496 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
497 WHERE acl_id = :id AND acl_type = 'LIST';
501 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
502 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
503 OR z.sub_type = 'LIST' AND z.sub_id = :id
504 OR z.iws_type = 'LIST' AND z.iws_id = :id
505 OR z.iui_type = 'LIST' AND z.iui_id = :id
506 OR z.owner_type = 'LIST' and z.owner_id = :id;
510 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
511 WHERE lpc_acl = :id OR ac = :id;
515 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
516 WHERE owner_type = 'LIST' AND owner_id = :id
521 EXEC SQL SELECT count(name) INTO :cnt FROM containers
522 WHERE acl_id = :id AND acl_type = 'LIST';
526 EXEC SQL SELECT count(name) INTO :cnt FROM containers
527 WHERE memacl_id = :id AND memacl_type = 'LIST';
535 /* setup_dsin - verify that the service is no longer being referenced
536 * and may safely be deleted.
539 int setup_dsin(struct query *q, char *argv[], client *cl)
541 EXEC SQL BEGIN DECLARE SECTION;
544 EXEC SQL END DECLARE SECTION;
547 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
548 WHERE service = UPPER(:svrname);
552 EXEC SQL SELECT inprogress INTO :ec FROM servers
553 WHERE name = UPPER(:svrname);
563 /* setup_dshi - verify that the service-host is no longer being referenced
564 * and may safely be deleted.
567 int setup_dshi(struct query *q, char *argv[], client *cl)
569 EXEC SQL BEGIN DECLARE SECTION;
572 EXEC SQL END DECLARE SECTION;
575 id = *(int *)argv[1];
577 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
578 WHERE service = UPPER(:svrname) AND mach_id = :id;
589 ** setup_add_filesys - verify existance of referenced file systems
595 ** argv[5] - rwaccess
600 ** - for type = NFS/IMAP:
601 ** * extract directory prefix from name
602 ** * verify mach_id/dir in nfsphys
603 ** * verify rwaccess in {r, w, R, W}
605 ** Side effect: sets variable _var_phys_id to the ID of the physical
606 ** filesystem (nfsphys_id for NFS, 0 for RVD)
609 ** MR_NFS - specified directory not exported
610 ** MR_FILESYS_ACCESS - invalid filesys access
614 EXEC SQL BEGIN DECLARE SECTION;
616 EXEC SQL END DECLARE SECTION;
618 int setup_afil(struct query *q, char *argv[], client *cl)
622 EXEC SQL BEGIN DECLARE SECTION;
624 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
625 EXEC SQL END DECLARE SECTION;
628 mach_id = *(int *)argv[2];
633 sprintf(ftype, "fs_access_%s", type);
634 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
635 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
639 return MR_FILESYS_ACCESS;
641 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
644 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
645 return check_nfs(mach_id, name, rwaccess);
651 /* Verify the arguments, depending on the FStype. Also, if this is an
652 * NFS filesystem, then update any quotas for that filesystem to reflect
656 int setup_ufil(struct query *q, char *argv[], client *cl)
660 EXEC SQL BEGIN DECLARE SECTION;
661 int fid, total, who, ok;
662 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
663 short int total_null;
664 EXEC SQL END DECLARE SECTION;
668 mach_id = *(int *)argv[3];
671 fid = *(int *)argv[0];
675 sprintf(ftype, "fs_access_%s", type);
676 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
677 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
681 return MR_FILESYS_ACCESS;
683 EXEC SQL SELECT type INTO :ftype FROM filesys
684 WHERE filsys_id = :fid;
688 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
690 status = check_nfs(mach_id, name, access);
691 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
692 WHERE filsys_id = :fid;
697 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
698 && strcmp(strtrim(ftype), "ERR"))
701 EXEC SQL DELETE FROM quota
702 WHERE type = 'ANY' AND filsys_id = :fid;
703 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
704 WHERE filsys_id = :fid AND phys_id != 0;
707 if (!total_null && (total != 0))
709 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
710 type, modtime, modby, modwith)
711 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
718 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
726 /* Find the NFS physical partition that the named directory is on.
727 * This is done by comparing the dir against the mount point of the
728 * partition. To make sure we get the correct match when there is
729 * more than one, we sort the query in reverse order by dir name.
732 int check_nfs(int mach_id, char *name, char *access)
734 EXEC SQL BEGIN DECLARE SECTION;
735 char dir[NFSPHYS_DIR_SIZE];
737 EXEC SQL END DECLARE SECTION;
743 EXEC SQL DECLARE csr101 CURSOR FOR
744 SELECT nfsphys_id, dir FROM nfsphys
749 EXEC SQL OPEN csr101;
754 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
771 EXEC SQL CLOSE csr101;
778 /* setup_dfil: free any quota records and fsgroup info associated with
779 * a filesystem when it is deleted. Also adjust the allocation numbers.
782 int setup_dfil(struct query *q, char **argv, client *cl)
784 EXEC SQL BEGIN DECLARE SECTION;
785 int id, total, phys_id;
787 EXEC SQL END DECLARE SECTION;
789 id = *(int *)argv[0];
790 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
791 WHERE filsys_id = :id;
796 /** What if there are multiple phys_id's per f/s? (bad data) **/
797 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
798 WHERE filsys_id = :id;
799 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
800 WHERE nfsphys_id = :phys_id;
803 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
804 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
805 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
812 /* setup_dnfp: check to see that the nfs physical partition does not have
813 * any filesystems assigned to it before allowing it to be deleted.
816 int setup_dnfp(struct query *q, char **argv, client *cl)
818 EXEC SQL BEGIN DECLARE SECTION;
821 EXEC SQL END DECLARE SECTION;
823 id = *(int *)argv[0];
825 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
826 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
827 AND np.mach_id = :id AND np.dir = :dir;
836 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
837 * argv[0] = filsys_id
838 * argv[1] = type if "update_quota" or "delete_quota"
839 * argv[2 or 1] = users_id or list_id
842 int setup_dqot(struct query *q, char **argv, client *cl)
844 EXEC SQL BEGIN DECLARE SECTION;
845 int quota, fs, id, physid;
847 EXEC SQL END DECLARE SECTION;
849 fs = *(int *)argv[0];
850 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
853 id = *(int *)argv[2];
858 id = *(int *)argv[1];
861 EXEC SQL SELECT quota INTO :quota FROM quota
862 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
863 EXEC SQL SELECT phys_id INTO :physid FROM filesys
864 WHERE filsys_id = :fs;
865 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
866 WHERE nfsphys_id = :physid;
875 * This routine fetches an appropriate value from the numvalues table.
876 * It is a little hack to get around the fact that SQL doesn't let you
877 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
879 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
880 * from within a setup_...() routine with the appropriate arguments.
882 * Correct functioning of this routine may depend on the assumption
883 * that this query is an APPEND.
886 int prefetch_value(struct query *q, char **argv, client *cl)
888 EXEC SQL BEGIN DECLARE SECTION;
889 char *name = q->validate->object_id;
891 EXEC SQL END DECLARE SECTION;
892 int status, limit, argc;
894 /* set next object id, limiting it if necessary */
895 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
896 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
899 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
902 /* fetch object id */
903 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
906 if (sqlca.sqlerrd[2] != 1)
909 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
910 sprintf(argv[argc], "%d", value);
915 /* prefetch_filesys():
916 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
917 * Appends the filsys_id and the phys_id to the argv so they can be
918 * referenced in an INSERT into a table other than filesys. Also
919 * see comments at prefetch_value().
921 * Assumes the existence of a row where filsys_id = argv[0], since a
922 * filesys label has already been resolved to a filsys_id.
924 int prefetch_filesys(struct query *q, char **argv, client *cl)
926 EXEC SQL BEGIN DECLARE SECTION;
928 EXEC SQL END DECLARE SECTION;
931 fid = *(int *)argv[0];
932 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
936 argc = q->argc + q->vcnt;
937 sprintf(argv[argc++], "%d", phid);
938 sprintf(argv[argc], "%d", fid);
947 int setup_ahst(struct query *q, char **argv, client *cl)
949 EXEC SQL BEGIN DECLARE SECTION;
950 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
951 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
952 int value, id, ssaddr, smask, shigh, slow, cnt;
953 unsigned int saddr, mask, high, low;
954 EXEC SQL END DECLARE SECTION;
958 id = *(int *)argv[0];
960 if (!strcmp(q->shortname, "uhst"))
963 EXEC SQL SELECT name, vendor, model, os
964 INTO :oldname, :vendor, :model, :os
965 FROM machine WHERE mach_id = :id;
972 else if (q->version >= 6 && q->version < 8)
977 /* Sanity check name, vendor, model, and os. */
978 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
979 !hostname_check(argv[row]))
981 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
982 !hostinfo_check(argv[row + 1], 0))
984 if ((row == 0 || strcasecmp(argv[3], model)) &&
985 !hostinfo_check(argv[row + 2], 1))
987 if ((row == 0 || strcasecmp(argv[4], os)) &&
988 !hostinfo_check(argv[row + 3], 0))
991 /* check for duplicate name */
993 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
994 WHERE name = UPPER(:name);
1001 if (!strcmp(argv[9 + row + idx], "unassigned"))
1003 else if (!strcmp(argv[9 + row + idx], "unique"))
1005 if (*(int *)argv[8 + row + idx] == 0)
1012 value = ntohl(inet_addr(argv[9 + row + idx]));
1021 * an address or unique was specified.
1023 id = *(int *)argv[8 + row + idx];
1024 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1025 :shigh, :slow FROM subnet WHERE snet_id = :id;
1028 saddr = (unsigned) ssaddr;
1029 mask = (unsigned) smask;
1030 high = (unsigned) shigh;
1031 low = (unsigned) slow;
1035 * someone specified an IP address for the host record
1037 if ((value & mask) != saddr || value < low || value > high)
1040 * run the address argument through inet_addr(). This
1041 * has the effect that any out of bounds host addrs will
1042 * be converted to a valid host addr. We do this now
1043 * so that the uniqueness check works. We should also
1044 * link in an inet_addr() that returns an error for
1047 addr.s_addr = inet_addr(argv[9 + row + idx]);
1048 name = inet_ntoa(addr);
1049 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1050 WHERE address = :name;
1056 * make IP address is unique. If this a modify request
1057 * (row == 1), then we expect one record to exist.
1059 if (row == 0 || (row == 1 && cnt > 1))
1061 if (row == 1 && cnt == 1)
1063 EXEC SQL SELECT mach_id INTO :id FROM machine
1064 WHERE address = :name;
1065 if (id != *(int *)argv[0])
1073 * a "unique" address was specified. Walk through the
1074 * range specified in the network record, return
1075 * error if no room left.
1077 for (id = low; id <= high; id++)
1079 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1081 addr.s_addr = htonl(id);
1082 name = inet_ntoa(addr);
1083 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1084 WHERE address = :name;
1096 * we have an address in value. Convert it to a string and store it.
1098 addr.s_addr = htonl(value);
1099 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1102 strcpy(argv[9 + row + idx], "unassigned");
1104 /* status checking */
1105 value = atoi(argv[7 + row + idx]);
1106 if (row == 0 && !(value == 1 || value == 0))
1110 id = *(int *)argv[0];
1111 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1116 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1117 WHERE mach_id = :id;
1122 * If this is an update_host query, we're done.
1128 * For an add_host query, allocate and fill in a new machine id,
1129 * and then insert the creator id.
1131 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1134 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1142 int setup_ahal(struct query *q, char **argv, client *cl)
1144 EXEC SQL BEGIN DECLARE SECTION;
1147 EXEC SQL END DECLARE SECTION;
1151 if (!hostname_check(argv[0]))
1154 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1155 name = UPPER(:name);
1164 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1167 int setup_uhha(struct query *q, char **argv, client *cl)
1169 EXEC SQL BEGIN DECLARE SECTION;
1170 char *hwaddr = argv[1];
1172 EXEC SQL END DECLARE SECTION;
1175 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1177 for (p = hwaddr; *p; p++)
1184 if (p != hwaddr + 12)
1187 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1188 FROM machine WHERE hwaddr = :hwaddr;
1190 return MR_NOT_UNIQUE;
1196 /* setup_aprn(): Make sure name/duplexname don't conflict with
1197 * anything. If [ANY] was specified for the spooling host, pick the
1198 * least loaded print server that serves this kind of printer.
1200 int setup_aprn(struct query *q, char **argv, client *cl)
1204 EXEC SQL BEGIN DECLARE SECTION;
1205 int mid, usage, count;
1206 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1207 EXEC SQL END DECLARE SECTION;
1209 /* Check for aprn or uprn. */
1210 if (q->type == APPEND)
1215 name = argv[PRN_NAME + row];
1216 duplexname = argv[PRN_DUPLEXNAME + row];
1223 if (q->type == APPEND)
1225 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1226 WHERE name = :name OR duplexname = :name;
1230 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1231 WHERE ( name = :name OR duplexname = :name )
1232 AND name != :oldname;
1237 return MR_NOT_UNIQUE;
1242 if (q->type == APPEND)
1244 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1245 WHERE name = :duplexname OR duplexname = :duplexname;
1249 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1250 WHERE ( name = :duplexname OR duplexname = :duplexname )
1251 AND name != :oldname;
1257 return MR_NOT_UNIQUE;
1260 if (!strcmp(name, duplexname))
1261 return MR_NOT_UNIQUE;
1263 mid = *(int *)argv[PRN_RM + row];
1266 EXEC SQL DECLARE csr_rm CURSOR FOR
1267 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1269 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1271 AND ps.printer_types = s.string_id;
1274 EXEC SQL OPEN csr_rm;
1280 EXEC SQL FETCH csr_rm INTO :mid, :types;
1284 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1286 if (!strcasecmp(argv[PRN_TYPE + row], p))
1288 EXEC SQL SELECT COUNT(name) INTO :usage
1289 FROM printers WHERE rm = :mid;
1291 if (best < 0 || usage < best)
1294 *(int *)argv[PRN_RM + row] = mid;
1300 EXEC SQL CLOSE csr_rm;
1309 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1310 WHERE mach_id = :mid;
1318 int setup_dpsv(struct query *q, char **argv, client *cl)
1321 EXEC SQL BEGIN DECLARE SECTION;
1323 EXEC SQL END DECLARE SECTION;
1325 id = *(int *)argv[0];
1327 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1335 int setup_dcon(struct query *q, char *argv[], client *cl)
1337 EXEC SQL BEGIN DECLARE SECTION;
1339 char containername[CONTAINERS_NAME_SIZE];
1340 EXEC SQL END DECLARE SECTION;
1342 id = *(int *)argv[0];
1343 /* check to see if there are machines in this container */
1344 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1349 /* check to see if there are subcontainers in this container */
1351 /* get the container name */
1353 EXEC SQL SELECT name INTO :containername
1357 /* trim off the trailing spaces */
1358 strcpy(containername, strtrim(containername));
1360 EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1361 WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
1371 int setup_scli(struct query *q, char *argv[], client *cl)
1373 EXEC SQL BEGIN DECLARE SECTION;
1374 int cnt_id, list_id;
1375 EXEC SQL END DECLARE SECTION;
1377 cnt_id = *(int *)argv[0];
1378 /* Check if someone has already set the list for this container */
1379 EXEC SQL SELECT list_id INTO :list_id FROM containers
1380 WHERE cnt_id = :cnt_id;
1391 * validate the rfc1035/rfc1123-ness of a hostname
1394 int hostname_check(char *name)
1399 /* Sanity check name: must contain only letters, numerals, and
1400 * hyphen, and not start or end with a hyphen. Also make sure no
1401 * label (the thing the .s seperate) is longer than 63 characters,
1405 for (p = name, count = 0; *p; p++)
1408 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1409 (*p == '-' && p[1] == '.'))
1420 if (*(p - 1) == '-')
1425 int hostinfo_check(char *info, int num)
1432 /* Sanity check host hostinfo: must start with a letter (or number
1433 * if num is true), contain only letters, numerals, and hyphen, and
1434 * not end with a hyphen.
1437 if (!isalpha(*info) && (!num || !isdigit(*info)))
1439 for (p = info; *p; p++)
1441 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1442 (*p == '-' && p[1] == '.'))
1445 if (!isalnum(*(p - 1)))
1449 int setup_acon(struct query *q, char *argv[], client *cl)
1451 EXEC SQL BEGIN DECLARE SECTION;
1452 char containername[CONTAINERS_NAME_SIZE];
1453 EXEC SQL END DECLARE SECTION;
1457 memset(containername, 0, sizeof(containername));
1458 strcpy(containername, argv[0]);
1459 ptr = strrchr(containername, '/');
1460 /* sub container, check for parents */
1464 EXEC SQL SELECT * FROM containers
1465 WHERE lower(name) = lower(:containername);
1466 if (sqlca.sqlerrd[2] != 1)
1467 return MR_CONTAINER_NO_PARENT;
1470 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)