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)
269 EXEC SQL SELECT account_number FROM accountnumbers
270 WHERE account_number = :account_number;
271 if (sqlca.sqlcode == SQL_NO_MATCH)
272 return MR_ACCOUNT_NUMBER;
275 /* Special case 0.0.0.0 and 255.255.255.255 */
276 if (!(low == 0 || low == -1 || high == 0 || high == -1))
280 /* If this is update_subnet, we're done. */
284 /* For an add_subnet query, allocate and fill in a new snet_id */
285 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
291 /* setup_dsnt - verify that the subnet is no longer being referenced
292 * and may safely be deleted.
295 int setup_dsnt(struct query *q, char *argv[], client *cl)
297 EXEC SQL BEGIN DECLARE SECTION;
299 EXEC SQL END DECLARE SECTION;
301 id = *(int *)argv[0];
302 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
310 /* setup_dclu - verify that the cluster is no longer being referenced
311 * and may safely be deleted.
314 int setup_dclu(struct query *q, char *argv[], client *cl)
316 EXEC SQL BEGIN DECLARE SECTION;
318 EXEC SQL END DECLARE SECTION;
320 id = *(int *)argv[0];
321 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
325 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
335 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
336 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
337 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
338 * a -1 there. Remember that this is also used for ulis, with the indexes
339 * at 6 & 7. Also check that the list name does not contain uppercase
340 * characters, control characters, @, or :.
342 * Newlines in list descriptions do bad things to the aliases file
343 * moira generates, so make sure the description doesn't contain any, too.
346 static int badlistchars[] = {
347 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
348 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
349 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
351 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
353 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
354 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
355 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
365 int setup_alis(struct query *q, char *argv[], client *cl)
367 EXEC SQL BEGIN DECLARE SECTION;
370 EXEC SQL END DECLARE SECTION;
374 if (!strcmp(q->shortname, "alis"))
376 else if (!strcmp(q->shortname, "ulis"))
381 desc = argv[9 + idx];
382 else if (q->version == 3)
383 desc = argv[10 + idx];
384 else if (q->version >= 4)
385 desc = argv[12 + idx];
389 EXEC SQL BEGIN DECLARE SECTION;
390 int lid = *(int *)argv[0];
391 EXEC SQL END DECLARE SECTION;
393 if (acl_access_check(lid, cl))
397 for (p = (unsigned char *) name; *p; p++)
399 if (badlistchars[*p])
403 for (p = (unsigned char *) desc; *p; p++)
409 /* Check that it doesn't conflict with a pre-existing weirdly-cased
411 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
412 WHERE LOWER(name) = :name AND name != :name;
416 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
418 if (atoi(argv[5 + idx]))
420 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
422 EXEC SQL SELECT value INTO :ngid FROM numvalues
426 sprintf(argv[6 + idx], "%d", ngid);
429 strcpy(argv[6 + idx], "-1");
432 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
439 /* setup_dlis - verify that the list is no longer being referenced
440 * and may safely be deleted.
443 int setup_dlis(struct query *q, char *argv[], client *cl)
446 EXEC SQL BEGIN DECLARE SECTION;
448 EXEC SQL END DECLARE SECTION;
450 id = *(int *)argv[0];
452 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
453 WHERE member_id = :id AND member_type = 'LIST';
457 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
458 WHERE member_id = :id AND member_type = 'LIST';
462 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
467 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
471 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
475 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
476 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
480 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
481 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
485 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
486 WHERE acl_id = :id AND acl_type = 'LIST';
490 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
491 WHERE entity_id = :id AND type = 'GROUP';
495 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
496 WHERE acl_id = :id AND acl_type = 'LIST';
500 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
501 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
502 OR z.sub_type = 'LIST' AND z.sub_id = :id
503 OR z.iws_type = 'LIST' AND z.iws_id = :id
504 OR z.iui_type = 'LIST' AND z.iui_id = :id
505 OR z.owner_type = 'LIST' and z.owner_id = :id;
509 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
510 WHERE lpc_acl = :id OR ac = :id;
514 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
515 WHERE owner_type = 'LIST' AND owner_id = :id
520 EXEC SQL SELECT count(name) INTO :cnt FROM containers
521 WHERE acl_id = :id AND acl_type = 'LIST';
525 EXEC SQL SELECT count(name) INTO :cnt FROM containers
526 WHERE memacl_id = :id AND memacl_type = 'LIST';
534 /* setup_dsin - verify that the service is no longer being referenced
535 * and may safely be deleted.
538 int setup_dsin(struct query *q, char *argv[], client *cl)
540 EXEC SQL BEGIN DECLARE SECTION;
543 EXEC SQL END DECLARE SECTION;
546 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
547 WHERE service = UPPER(:svrname);
551 EXEC SQL SELECT inprogress INTO :ec FROM servers
552 WHERE name = UPPER(:svrname);
562 /* setup_dshi - verify that the service-host is no longer being referenced
563 * and may safely be deleted.
566 int setup_dshi(struct query *q, char *argv[], client *cl)
568 EXEC SQL BEGIN DECLARE SECTION;
571 EXEC SQL END DECLARE SECTION;
574 id = *(int *)argv[1];
576 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
577 WHERE service = UPPER(:svrname) AND mach_id = :id;
588 ** setup_add_filesys - verify existance of referenced file systems
594 ** argv[5] - rwaccess
599 ** - for type = NFS/IMAP:
600 ** * extract directory prefix from name
601 ** * verify mach_id/dir in nfsphys
602 ** * verify rwaccess in {r, w, R, W}
604 ** Side effect: sets variable _var_phys_id to the ID of the physical
605 ** filesystem (nfsphys_id for NFS, 0 for RVD)
608 ** MR_NFS - specified directory not exported
609 ** MR_FILESYS_ACCESS - invalid filesys access
613 EXEC SQL BEGIN DECLARE SECTION;
615 EXEC SQL END DECLARE SECTION;
617 int setup_afil(struct query *q, char *argv[], client *cl)
621 EXEC SQL BEGIN DECLARE SECTION;
623 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
624 EXEC SQL END DECLARE SECTION;
627 mach_id = *(int *)argv[2];
632 sprintf(ftype, "fs_access_%s", type);
633 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
634 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
638 return MR_FILESYS_ACCESS;
640 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
643 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
644 return check_nfs(mach_id, name, rwaccess);
650 /* Verify the arguments, depending on the FStype. Also, if this is an
651 * NFS filesystem, then update any quotas for that filesystem to reflect
655 int setup_ufil(struct query *q, char *argv[], client *cl)
659 EXEC SQL BEGIN DECLARE SECTION;
660 int fid, total, who, ok;
661 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
662 short int total_null;
663 EXEC SQL END DECLARE SECTION;
667 mach_id = *(int *)argv[3];
670 fid = *(int *)argv[0];
674 sprintf(ftype, "fs_access_%s", type);
675 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
676 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
680 return MR_FILESYS_ACCESS;
682 EXEC SQL SELECT type INTO :ftype FROM filesys
683 WHERE filsys_id = :fid;
687 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
689 status = check_nfs(mach_id, name, access);
690 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
691 WHERE filsys_id = :fid;
696 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
697 && strcmp(strtrim(ftype), "ERR"))
700 EXEC SQL DELETE FROM quota
701 WHERE type = 'ANY' AND filsys_id = :fid;
702 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
703 WHERE filsys_id = :fid AND phys_id != 0;
706 if (!total_null && (total != 0))
708 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
709 type, modtime, modby, modwith)
710 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
717 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
725 /* Find the NFS physical partition that the named directory is on.
726 * This is done by comparing the dir against the mount point of the
727 * partition. To make sure we get the correct match when there is
728 * more than one, we sort the query in reverse order by dir name.
731 int check_nfs(int mach_id, char *name, char *access)
733 EXEC SQL BEGIN DECLARE SECTION;
734 char dir[NFSPHYS_DIR_SIZE];
736 EXEC SQL END DECLARE SECTION;
742 EXEC SQL DECLARE csr101 CURSOR FOR
743 SELECT nfsphys_id, dir FROM nfsphys
748 EXEC SQL OPEN csr101;
753 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
770 EXEC SQL CLOSE csr101;
777 /* setup_dfil: free any quota records and fsgroup info associated with
778 * a filesystem when it is deleted. Also adjust the allocation numbers.
781 int setup_dfil(struct query *q, char **argv, client *cl)
783 EXEC SQL BEGIN DECLARE SECTION;
784 int id, total, phys_id;
786 EXEC SQL END DECLARE SECTION;
788 id = *(int *)argv[0];
789 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
790 WHERE filsys_id = :id;
795 /** What if there are multiple phys_id's per f/s? (bad data) **/
796 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
797 WHERE filsys_id = :id;
798 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
799 WHERE nfsphys_id = :phys_id;
802 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
803 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
804 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
811 /* setup_dnfp: check to see that the nfs physical partition does not have
812 * any filesystems assigned to it before allowing it to be deleted.
815 int setup_dnfp(struct query *q, char **argv, client *cl)
817 EXEC SQL BEGIN DECLARE SECTION;
820 EXEC SQL END DECLARE SECTION;
822 id = *(int *)argv[0];
824 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
825 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
826 AND np.mach_id = :id AND np.dir = :dir;
835 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
836 * argv[0] = filsys_id
837 * argv[1] = type if "update_quota" or "delete_quota"
838 * argv[2 or 1] = users_id or list_id
841 int setup_dqot(struct query *q, char **argv, client *cl)
843 EXEC SQL BEGIN DECLARE SECTION;
844 int quota, fs, id, physid;
846 EXEC SQL END DECLARE SECTION;
848 fs = *(int *)argv[0];
849 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
852 id = *(int *)argv[2];
857 id = *(int *)argv[1];
860 EXEC SQL SELECT quota INTO :quota FROM quota
861 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
862 EXEC SQL SELECT phys_id INTO :physid FROM filesys
863 WHERE filsys_id = :fs;
864 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
865 WHERE nfsphys_id = :physid;
874 * This routine fetches an appropriate value from the numvalues table.
875 * It is a little hack to get around the fact that SQL doesn't let you
876 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
878 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
879 * from within a setup_...() routine with the appropriate arguments.
881 * Correct functioning of this routine may depend on the assumption
882 * that this query is an APPEND.
885 int prefetch_value(struct query *q, char **argv, client *cl)
887 EXEC SQL BEGIN DECLARE SECTION;
888 char *name = q->validate->object_id;
890 EXEC SQL END DECLARE SECTION;
891 int status, limit, argc;
893 /* set next object id, limiting it if necessary */
894 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
895 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
898 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
901 /* fetch object id */
902 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
905 if (sqlca.sqlerrd[2] != 1)
908 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
909 sprintf(argv[argc], "%d", value);
914 /* prefetch_filesys():
915 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
916 * Appends the filsys_id and the phys_id to the argv so they can be
917 * referenced in an INSERT into a table other than filesys. Also
918 * see comments at prefetch_value().
920 * Assumes the existence of a row where filsys_id = argv[0], since a
921 * filesys label has already been resolved to a filsys_id.
923 int prefetch_filesys(struct query *q, char **argv, client *cl)
925 EXEC SQL BEGIN DECLARE SECTION;
927 EXEC SQL END DECLARE SECTION;
930 fid = *(int *)argv[0];
931 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
935 argc = q->argc + q->vcnt;
936 sprintf(argv[argc++], "%d", phid);
937 sprintf(argv[argc], "%d", fid);
946 int setup_ahst(struct query *q, char **argv, client *cl)
948 EXEC SQL BEGIN DECLARE SECTION;
949 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
950 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
951 int value, id, ssaddr, smask, shigh, slow, cnt;
952 unsigned int saddr, mask, high, low;
953 EXEC SQL END DECLARE SECTION;
957 id = *(int *)argv[0];
959 if (!strcmp(q->shortname, "uhst"))
962 EXEC SQL SELECT name, vendor, model, os
963 INTO :oldname, :vendor, :model, :os
964 FROM machine WHERE mach_id = :id;
971 else if (q->version >= 6 && q->version < 8)
976 /* Sanity check name, vendor, model, and os. */
977 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
978 !hostname_check(argv[row]))
980 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
981 !hostinfo_check(argv[row + 1], 0))
983 if ((row == 0 || strcasecmp(argv[3], model)) &&
984 !hostinfo_check(argv[row + 2], 1))
986 if ((row == 0 || strcasecmp(argv[4], os)) &&
987 !hostinfo_check(argv[row + 3], 0))
990 /* check for duplicate name */
992 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
993 WHERE name = UPPER(:name);
1000 if (!strcmp(argv[9 + row + idx], "unassigned"))
1002 else if (!strcmp(argv[9 + row + idx], "unique"))
1004 if (*(int *)argv[8 + row + idx] == 0)
1011 value = ntohl(inet_addr(argv[9 + row + idx]));
1020 * an address or unique was specified.
1022 id = *(int *)argv[8 + row + idx];
1023 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1024 :shigh, :slow FROM subnet WHERE snet_id = :id;
1027 saddr = (unsigned) ssaddr;
1028 mask = (unsigned) smask;
1029 high = (unsigned) shigh;
1030 low = (unsigned) slow;
1034 * someone specified an IP address for the host record
1036 if ((value & mask) != saddr || value < low || value > high)
1039 * run the address argument through inet_addr(). This
1040 * has the effect that any out of bounds host addrs will
1041 * be converted to a valid host addr. We do this now
1042 * so that the uniqueness check works. We should also
1043 * link in an inet_addr() that returns an error for
1046 addr.s_addr = inet_addr(argv[9 + row + idx]);
1047 name = inet_ntoa(addr);
1048 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1049 WHERE address = :name;
1055 * make IP address is unique. If this a modify request
1056 * (row == 1), then we expect one record to exist.
1058 if (row == 0 || (row == 1 && cnt > 1))
1060 if (row == 1 && cnt == 1)
1062 EXEC SQL SELECT mach_id INTO :id FROM machine
1063 WHERE address = :name;
1064 if (id != *(int *)argv[0])
1072 * a "unique" address was specified. Walk through the
1073 * range specified in the network record, return
1074 * error if no room left.
1076 for (id = low; id <= high; id++)
1078 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1080 addr.s_addr = htonl(id);
1081 name = inet_ntoa(addr);
1082 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1083 WHERE address = :name;
1095 * we have an address in value. Convert it to a string and store it.
1097 addr.s_addr = htonl(value);
1098 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1101 strcpy(argv[9 + row + idx], "unassigned");
1103 /* status checking */
1104 value = atoi(argv[7 + row + idx]);
1105 if (row == 0 && !(value == 1 || value == 0))
1109 id = *(int *)argv[0];
1110 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1115 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1116 WHERE mach_id = :id;
1121 * If this is an update_host query, we're done.
1127 * For an add_host query, allocate and fill in a new machine id,
1128 * and then insert the creator id.
1130 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1133 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1141 int setup_ahal(struct query *q, char **argv, client *cl)
1143 EXEC SQL BEGIN DECLARE SECTION;
1146 EXEC SQL END DECLARE SECTION;
1150 if (!hostname_check(argv[0]))
1153 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1154 name = UPPER(:name);
1163 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1166 int setup_uhha(struct query *q, char **argv, client *cl)
1168 EXEC SQL BEGIN DECLARE SECTION;
1169 char *hwaddr = argv[1];
1171 EXEC SQL END DECLARE SECTION;
1174 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1176 for (p = hwaddr; *p; p++)
1183 if (p != hwaddr + 12)
1186 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1187 FROM machine WHERE hwaddr = :hwaddr;
1189 return MR_NOT_UNIQUE;
1195 /* setup_aprn(): Make sure name/duplexname don't conflict with
1196 * anything. If [ANY] was specified for the spooling host, pick the
1197 * least loaded print server that serves this kind of printer.
1199 int setup_aprn(struct query *q, char **argv, client *cl)
1203 EXEC SQL BEGIN DECLARE SECTION;
1204 int mid, usage, count;
1205 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1206 EXEC SQL END DECLARE SECTION;
1208 /* Check for aprn or uprn. */
1209 if (q->type == APPEND)
1214 name = argv[PRN_NAME + row];
1215 duplexname = argv[PRN_DUPLEXNAME + row];
1222 if (q->type == APPEND)
1224 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1225 WHERE name = :name OR duplexname = :name;
1229 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1230 WHERE ( name = :name OR duplexname = :name )
1231 AND name != :oldname;
1236 return MR_NOT_UNIQUE;
1241 if (q->type == APPEND)
1243 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1244 WHERE name = :duplexname OR duplexname = :duplexname;
1248 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1249 WHERE ( name = :duplexname OR duplexname = :duplexname )
1250 AND name != :oldname;
1256 return MR_NOT_UNIQUE;
1259 if (!strcmp(name, duplexname))
1260 return MR_NOT_UNIQUE;
1262 mid = *(int *)argv[PRN_RM + row];
1265 EXEC SQL DECLARE csr_rm CURSOR FOR
1266 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1268 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1270 AND ps.printer_types = s.string_id;
1273 EXEC SQL OPEN csr_rm;
1279 EXEC SQL FETCH csr_rm INTO :mid, :types;
1283 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1285 if (!strcasecmp(argv[PRN_TYPE + row], p))
1287 EXEC SQL SELECT COUNT(name) INTO :usage
1288 FROM printers WHERE rm = :mid;
1290 if (best < 0 || usage < best)
1293 *(int *)argv[PRN_RM + row] = mid;
1299 EXEC SQL CLOSE csr_rm;
1308 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1309 WHERE mach_id = :mid;
1317 int setup_dpsv(struct query *q, char **argv, client *cl)
1320 EXEC SQL BEGIN DECLARE SECTION;
1322 EXEC SQL END DECLARE SECTION;
1324 id = *(int *)argv[0];
1326 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1334 int setup_dcon(struct query *q, char *argv[], client *cl)
1336 EXEC SQL BEGIN DECLARE SECTION;
1338 char containername[CONTAINERS_NAME_SIZE];
1339 EXEC SQL END DECLARE SECTION;
1341 id = *(int *)argv[0];
1342 /* check to see if there are machines in this container */
1343 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1348 /* check to see if there are subcontainers in this container */
1350 /* get the container name */
1352 EXEC SQL SELECT name INTO :containername
1356 /* trim off the trailing spaces */
1357 strcpy(containername, strtrim(containername));
1359 EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1360 WHERE name LIKE :containername || '/' || '%';
1371 * validate the rfc1035/rfc1123-ness of a hostname
1374 int hostname_check(char *name)
1379 /* Sanity check name: must contain only letters, numerals, and
1380 * hyphen, and not start or end with a hyphen. Also make sure no
1381 * label (the thing the .s seperate) is longer than 63 characters,
1385 for (p = name, count = 0; *p; p++)
1388 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1389 (*p == '-' && p[1] == '.'))
1400 if (*(p - 1) == '-')
1405 int hostinfo_check(char *info, int num)
1412 /* Sanity check host hostinfo: must start with a letter (or number
1413 * if num is true), contain only letters, numerals, and hyphen, and
1414 * not end with a hyphen.
1417 if (!isalpha(*info) && (!num || !isdigit(*info)))
1419 for (p = info; *p; p++)
1421 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1422 (*p == '-' && p[1] == '.'))
1425 if (!isalnum(*(p - 1)))