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
228 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
232 EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id;
238 /* setup_asnt - verify that the data entered for the subnet is sane.
239 * In particular, make sure that the "low" and "high" addresses are
240 * correctly ordered, i.e., high > low.
243 int setup_asnt(struct query *q, char *argv[], client *cl)
245 int high, low, row, status;
246 char *account_number;
248 /* Check for asnt or usnt. */
249 if (q->type == APPEND)
254 low = atoi(argv[row + 7]);
255 high = atoi(argv[row + 8]);
256 status = atoi(argv[row + 2]);
257 account_number = argv[row + 4];
259 /* Don't allow Private subnets to be created without a valid billing
262 if (status == SNET_STATUS_PRIVATE_10MBPS ||
263 status == SNET_STATUS_PRIVATE_100MBPS)
265 EXEC SQL SELECT account_number FROM accountnumbers
266 WHERE account_number = :account_number;
267 if (sqlca.sqlcode == SQL_NO_MATCH)
268 return MR_ACCOUNT_NUMBER;
271 /* Special case 0.0.0.0 and 255.255.255.255 */
272 if (!(low == 0 || low == -1 || high == 0 || high == -1))
276 /* If this is update_subnet, we're done. */
280 /* For an add_subnet query, allocate and fill in a new snet_id */
281 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
287 /* setup_dsnt - verify that the subnet is no longer being referenced
288 * and may safely be deleted.
291 int setup_dsnt(struct query *q, char *argv[], client *cl)
293 EXEC SQL BEGIN DECLARE SECTION;
295 EXEC SQL END DECLARE SECTION;
297 id = *(int *)argv[0];
298 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
306 /* setup_dclu - verify that the cluster is no longer being referenced
307 * and may safely be deleted.
310 int setup_dclu(struct query *q, char *argv[], client *cl)
312 EXEC SQL BEGIN DECLARE SECTION;
314 EXEC SQL END DECLARE SECTION;
316 id = *(int *)argv[0];
317 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
321 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
331 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
332 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
333 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
334 * a -1 there. Remember that this is also used for ulis, with the indexes
335 * at 6 & 7. Also check that the list name does not contain uppercase
336 * characters, control characters, @, or :.
338 * Newlines in list descriptions do bad things to the aliases file
339 * moira generates, so make sure the description doesn't contain any, too.
342 static int badlistchars[] = {
343 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
344 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
345 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
346 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
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, 0, /* P - _ */
349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
351 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
353 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
354 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
361 int setup_alis(struct query *q, char *argv[], client *cl)
363 EXEC SQL BEGIN DECLARE SECTION;
366 EXEC SQL END DECLARE SECTION;
370 if (!strcmp(q->shortname, "alis"))
372 else if (!strcmp(q->shortname, "ulis"))
377 desc = argv[9 + idx];
378 else if (q->version == 3)
379 desc = argv[10 + idx];
380 else if (q->version >= 4)
381 desc = argv[12 + idx];
385 EXEC SQL BEGIN DECLARE SECTION;
386 int lid = *(int *)argv[0];
387 EXEC SQL END DECLARE SECTION;
389 if (acl_access_check(lid, cl))
393 for (p = (unsigned char *) name; *p; p++)
395 if (badlistchars[*p])
399 for (p = (unsigned char *) desc; *p; p++)
405 /* Check that it doesn't conflict with a pre-existing weirdly-cased
407 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
408 WHERE LOWER(name) = :name AND name != :name;
412 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
414 if (atoi(argv[5 + idx]))
416 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
418 EXEC SQL SELECT value INTO :ngid FROM numvalues
422 sprintf(argv[6 + idx], "%d", ngid);
425 strcpy(argv[6 + idx], "-1");
428 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
435 /* setup_dlis - verify that the list is no longer being referenced
436 * and may safely be deleted.
439 int setup_dlis(struct query *q, char *argv[], client *cl)
442 EXEC SQL BEGIN DECLARE SECTION;
444 EXEC SQL END DECLARE SECTION;
446 id = *(int *)argv[0];
448 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
449 WHERE member_id = :id AND member_type = 'LIST';
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
463 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
467 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
471 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
472 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
476 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
477 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
481 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
482 WHERE acl_id = :id AND acl_type = 'LIST';
486 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
487 WHERE entity_id = :id AND type = 'GROUP';
491 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
492 WHERE acl_id = :id AND acl_type = 'LIST';
496 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
497 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
498 OR z.sub_type = 'LIST' AND z.sub_id = :id
499 OR z.iws_type = 'LIST' AND z.iws_id = :id
500 OR z.iui_type = 'LIST' AND z.iui_id = :id
501 OR z.owner_type = 'LIST' and z.owner_id = :id;
505 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
506 WHERE lpc_acl = :id OR ac = :id;
510 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
511 WHERE owner_type = 'LIST' AND owner_id = :id
516 EXEC SQL SELECT count(name) INTO :cnt FROM containers
517 WHERE acl_id = :id AND acl_type = 'LIST';
521 EXEC SQL SELECT count(name) INTO :cnt FROM containers
522 WHERE memacl_id = :id AND memacl_type = 'LIST';
530 /* setup_dsin - verify that the service is no longer being referenced
531 * and may safely be deleted.
534 int setup_dsin(struct query *q, char *argv[], client *cl)
536 EXEC SQL BEGIN DECLARE SECTION;
539 EXEC SQL END DECLARE SECTION;
542 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
543 WHERE service = UPPER(:svrname);
547 EXEC SQL SELECT inprogress INTO :ec FROM servers
548 WHERE name = UPPER(:svrname);
558 /* setup_dshi - verify that the service-host is no longer being referenced
559 * and may safely be deleted.
562 int setup_dshi(struct query *q, char *argv[], client *cl)
564 EXEC SQL BEGIN DECLARE SECTION;
567 EXEC SQL END DECLARE SECTION;
570 id = *(int *)argv[1];
572 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
573 WHERE service = UPPER(:svrname) AND mach_id = :id;
584 ** setup_add_filesys - verify existance of referenced file systems
590 ** argv[5] - rwaccess
595 ** - for type = NFS/IMAP:
596 ** * extract directory prefix from name
597 ** * verify mach_id/dir in nfsphys
598 ** * verify rwaccess in {r, w, R, W}
600 ** Side effect: sets variable _var_phys_id to the ID of the physical
601 ** filesystem (nfsphys_id for NFS, 0 for RVD)
604 ** MR_NFS - specified directory not exported
605 ** MR_FILESYS_ACCESS - invalid filesys access
609 EXEC SQL BEGIN DECLARE SECTION;
611 EXEC SQL END DECLARE SECTION;
613 int setup_afil(struct query *q, char *argv[], client *cl)
617 EXEC SQL BEGIN DECLARE SECTION;
619 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
620 EXEC SQL END DECLARE SECTION;
623 mach_id = *(int *)argv[2];
628 sprintf(ftype, "fs_access_%s", type);
629 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
630 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
634 return MR_FILESYS_ACCESS;
636 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
639 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
640 return check_nfs(mach_id, name, rwaccess);
646 /* Verify the arguments, depending on the FStype. Also, if this is an
647 * NFS filesystem, then update any quotas for that filesystem to reflect
651 int setup_ufil(struct query *q, char *argv[], client *cl)
655 EXEC SQL BEGIN DECLARE SECTION;
656 int fid, total, who, ok;
657 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
658 short int total_null;
659 EXEC SQL END DECLARE SECTION;
663 mach_id = *(int *)argv[3];
666 fid = *(int *)argv[0];
670 sprintf(ftype, "fs_access_%s", type);
671 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
672 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
676 return MR_FILESYS_ACCESS;
678 EXEC SQL SELECT type INTO :ftype FROM filesys
679 WHERE filsys_id = :fid;
683 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
685 status = check_nfs(mach_id, name, access);
686 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
687 WHERE filsys_id = :fid;
692 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
693 && strcmp(strtrim(ftype), "ERR"))
696 EXEC SQL DELETE FROM quota
697 WHERE type = 'ANY' AND filsys_id = :fid;
698 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
699 WHERE filsys_id = :fid AND phys_id != 0;
702 if (!total_null && (total != 0))
704 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
705 type, modtime, modby, modwith)
706 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
713 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
721 /* Find the NFS physical partition that the named directory is on.
722 * This is done by comparing the dir against the mount point of the
723 * partition. To make sure we get the correct match when there is
724 * more than one, we sort the query in reverse order by dir name.
727 int check_nfs(int mach_id, char *name, char *access)
729 EXEC SQL BEGIN DECLARE SECTION;
730 char dir[NFSPHYS_DIR_SIZE];
732 EXEC SQL END DECLARE SECTION;
738 EXEC SQL DECLARE csr101 CURSOR FOR
739 SELECT nfsphys_id, dir FROM nfsphys
744 EXEC SQL OPEN csr101;
749 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
766 EXEC SQL CLOSE csr101;
773 /* setup_dfil: free any quota records and fsgroup info associated with
774 * a filesystem when it is deleted. Also adjust the allocation numbers.
777 int setup_dfil(struct query *q, char **argv, client *cl)
779 EXEC SQL BEGIN DECLARE SECTION;
780 int id, total, phys_id;
782 EXEC SQL END DECLARE SECTION;
784 id = *(int *)argv[0];
785 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
786 WHERE filsys_id = :id;
791 /** What if there are multiple phys_id's per f/s? (bad data) **/
792 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
793 WHERE filsys_id = :id;
794 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
795 WHERE nfsphys_id = :phys_id;
798 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
799 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
800 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
807 /* setup_dnfp: check to see that the nfs physical partition does not have
808 * any filesystems assigned to it before allowing it to be deleted.
811 int setup_dnfp(struct query *q, char **argv, client *cl)
813 EXEC SQL BEGIN DECLARE SECTION;
816 EXEC SQL END DECLARE SECTION;
818 id = *(int *)argv[0];
820 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
821 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
822 AND np.mach_id = :id AND np.dir = :dir;
831 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
832 * argv[0] = filsys_id
833 * argv[1] = type if "update_quota" or "delete_quota"
834 * argv[2 or 1] = users_id or list_id
837 int setup_dqot(struct query *q, char **argv, client *cl)
839 EXEC SQL BEGIN DECLARE SECTION;
840 int quota, fs, id, physid;
842 EXEC SQL END DECLARE SECTION;
844 fs = *(int *)argv[0];
845 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
848 id = *(int *)argv[2];
853 id = *(int *)argv[1];
856 EXEC SQL SELECT quota INTO :quota FROM quota
857 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
858 EXEC SQL SELECT phys_id INTO :physid FROM filesys
859 WHERE filsys_id = :fs;
860 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
861 WHERE nfsphys_id = :physid;
870 * This routine fetches an appropriate value from the numvalues table.
871 * It is a little hack to get around the fact that SQL doesn't let you
872 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
874 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
875 * from within a setup_...() routine with the appropriate arguments.
877 * Correct functioning of this routine may depend on the assumption
878 * that this query is an APPEND.
881 int prefetch_value(struct query *q, char **argv, client *cl)
883 EXEC SQL BEGIN DECLARE SECTION;
884 char *name = q->validate->object_id;
886 EXEC SQL END DECLARE SECTION;
887 int status, limit, argc;
889 /* set next object id, limiting it if necessary */
890 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
891 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
894 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
897 /* fetch object id */
898 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
901 if (sqlca.sqlerrd[2] != 1)
904 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
905 sprintf(argv[argc], "%d", value);
910 /* prefetch_filesys():
911 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
912 * Appends the filsys_id and the phys_id to the argv so they can be
913 * referenced in an INSERT into a table other than filesys. Also
914 * see comments at prefetch_value().
916 * Assumes the existence of a row where filsys_id = argv[0], since a
917 * filesys label has already been resolved to a filsys_id.
919 int prefetch_filesys(struct query *q, char **argv, client *cl)
921 EXEC SQL BEGIN DECLARE SECTION;
923 EXEC SQL END DECLARE SECTION;
926 fid = *(int *)argv[0];
927 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
931 argc = q->argc + q->vcnt;
932 sprintf(argv[argc++], "%d", phid);
933 sprintf(argv[argc], "%d", fid);
942 int setup_ahst(struct query *q, char **argv, client *cl)
944 EXEC SQL BEGIN DECLARE SECTION;
945 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
946 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
947 int value, id, ssaddr, smask, shigh, slow, cnt;
948 unsigned int saddr, mask, high, low;
949 EXEC SQL END DECLARE SECTION;
953 id = *(int *)argv[0];
955 if (!strcmp(q->shortname, "uhst"))
958 EXEC SQL SELECT name, vendor, model, os
959 INTO :oldname, :vendor, :model, :os
960 FROM machine WHERE mach_id = :id;
967 else if (q->version >= 6 && q->version < 8)
972 /* Sanity check name, vendor, model, and os. */
973 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
974 !hostname_check(argv[row]))
976 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
977 !hostinfo_check(argv[row + 1], 0))
979 if ((row == 0 || strcasecmp(argv[3], model)) &&
980 !hostinfo_check(argv[row + 2], 1))
982 if ((row == 0 || strcasecmp(argv[4], os)) &&
983 !hostinfo_check(argv[row + 3], 0))
986 /* check for duplicate name */
988 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
989 WHERE name = UPPER(:name);
996 if (!strcmp(argv[9 + row + idx], "unassigned"))
998 else if (!strcmp(argv[9 + row + idx], "unique"))
1000 if (*(int *)argv[8 + row + idx] == 0)
1007 value = ntohl(inet_addr(argv[9 + row + idx]));
1016 * an address or unique was specified.
1018 id = *(int *)argv[8 + row + idx];
1019 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1020 :shigh, :slow FROM subnet WHERE snet_id = :id;
1023 saddr = (unsigned) ssaddr;
1024 mask = (unsigned) smask;
1025 high = (unsigned) shigh;
1026 low = (unsigned) slow;
1030 * someone specified an IP address for the host record
1032 if ((value & mask) != saddr || value < low || value > high)
1035 * run the address argument through inet_addr(). This
1036 * has the effect that any out of bounds host addrs will
1037 * be converted to a valid host addr. We do this now
1038 * so that the uniqueness check works. We should also
1039 * link in an inet_addr() that returns an error for
1042 addr.s_addr = inet_addr(argv[9 + row + idx]);
1043 name = inet_ntoa(addr);
1044 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1045 WHERE address = :name;
1051 * make IP address is unique. If this a modify request
1052 * (row == 1), then we expect one record to exist.
1054 if (row == 0 || (row == 1 && cnt > 1))
1056 if (row == 1 && cnt == 1)
1058 EXEC SQL SELECT mach_id INTO :id FROM machine
1059 WHERE address = :name;
1060 if (id != *(int *)argv[0])
1068 * a "unique" address was specified. Walk through the
1069 * range specified in the network record, return
1070 * error if no room left.
1072 for (id = low; id <= high; id++)
1074 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1076 addr.s_addr = htonl(id);
1077 name = inet_ntoa(addr);
1078 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1079 WHERE address = :name;
1091 * we have an address in value. Convert it to a string and store it.
1093 addr.s_addr = htonl(value);
1094 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1097 strcpy(argv[9 + row + idx], "unassigned");
1099 /* status checking */
1100 value = atoi(argv[7 + row + idx]);
1101 if (row == 0 && !(value == 1 || value == 0))
1105 id = *(int *)argv[0];
1106 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1111 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1112 WHERE mach_id = :id;
1117 * If this is an update_host query, we're done.
1123 * For an add_host query, allocate and fill in a new machine id,
1124 * and then insert the creator id.
1126 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1129 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1137 int setup_ahal(struct query *q, char **argv, client *cl)
1139 EXEC SQL BEGIN DECLARE SECTION;
1142 EXEC SQL END DECLARE SECTION;
1146 if (!hostname_check(argv[0]))
1149 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1150 name = UPPER(:name);
1159 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1162 int setup_uhha(struct query *q, char **argv, client *cl)
1164 EXEC SQL BEGIN DECLARE SECTION;
1165 char *hwaddr = argv[1];
1167 EXEC SQL END DECLARE SECTION;
1170 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1172 for (p = hwaddr; *p; p++)
1179 if (p != hwaddr + 12)
1182 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1183 FROM machine WHERE hwaddr = :hwaddr;
1185 return MR_NOT_UNIQUE;
1191 /* setup_aprn(): Make sure name/duplexname don't conflict with
1192 * anything. If [ANY] was specified for the spooling host, pick the
1193 * least loaded print server that serves this kind of printer.
1195 int setup_aprn(struct query *q, char **argv, client *cl)
1199 EXEC SQL BEGIN DECLARE SECTION;
1200 int mid, usage, count;
1201 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1202 EXEC SQL END DECLARE SECTION;
1204 /* Check for aprn or uprn. */
1205 if (q->type == APPEND)
1210 name = argv[PRN_NAME + row];
1211 duplexname = argv[PRN_DUPLEXNAME + row];
1218 if (q->type == APPEND)
1220 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1221 WHERE name = :name OR duplexname = :name;
1225 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1226 WHERE ( name = :name OR duplexname = :name )
1227 AND name != :oldname;
1232 return MR_NOT_UNIQUE;
1237 if (q->type == APPEND)
1239 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1240 WHERE name = :duplexname OR duplexname = :duplexname;
1244 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1245 WHERE ( name = :duplexname OR duplexname = :duplexname )
1246 AND name != :oldname;
1252 return MR_NOT_UNIQUE;
1255 if (!strcmp(name, duplexname))
1256 return MR_NOT_UNIQUE;
1258 mid = *(int *)argv[PRN_RM + row];
1261 EXEC SQL DECLARE csr_rm CURSOR FOR
1262 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1264 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1266 AND ps.printer_types = s.string_id;
1269 EXEC SQL OPEN csr_rm;
1275 EXEC SQL FETCH csr_rm INTO :mid, :types;
1279 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1281 if (!strcasecmp(argv[PRN_TYPE + row], p))
1283 EXEC SQL SELECT COUNT(name) INTO :usage
1284 FROM printers WHERE rm = :mid;
1286 if (best < 0 || usage < best)
1289 *(int *)argv[PRN_RM + row] = mid;
1295 EXEC SQL CLOSE csr_rm;
1304 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1305 WHERE mach_id = :mid;
1313 int setup_dpsv(struct query *q, char **argv, client *cl)
1316 EXEC SQL BEGIN DECLARE SECTION;
1318 EXEC SQL END DECLARE SECTION;
1320 id = *(int *)argv[0];
1322 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1330 int setup_dcon(struct query *q, char *argv[], client *cl)
1332 EXEC SQL BEGIN DECLARE SECTION;
1334 char containername[CONTAINERS_NAME_SIZE];
1335 EXEC SQL END DECLARE SECTION;
1337 id = *(int *)argv[0];
1338 /* check to see if there are machines in this container */
1339 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1344 /* check to see if there are subcontainers in this container */
1346 /* get the container name */
1348 EXEC SQL SELECT name INTO :containername
1352 /* trim off the trailing spaces */
1353 strcpy(containername, strtrim(containername));
1355 EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1356 WHERE name LIKE :containername || '/' || '%';
1367 * validate the rfc1035/rfc1123-ness of a hostname
1370 int hostname_check(char *name)
1375 /* Sanity check name: must contain only letters, numerals, and
1376 * hyphen, and not start or end with a hyphen. Also make sure no
1377 * label (the thing the .s seperate) is longer than 63 characters,
1381 for (p = name, count = 0; *p; p++)
1384 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1385 (*p == '-' && p[1] == '.'))
1396 if (*(p - 1) == '-')
1401 int hostinfo_check(char *info, int num)
1408 /* Sanity check host hostinfo: must start with a letter (or number
1409 * if num is true), contain only letters, numerals, and hyphen, and
1410 * not end with a hyphen.
1413 if (!isalpha(*info) && (!num || !isdigit(*info)))
1415 for (p = info; *p; p++)
1417 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1418 (*p == '-' && p[1] == '.'))
1421 if (!isalnum(*(p - 1)))