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)
98 /* setup_dusr - verify that the user is no longer being referenced
99 * and may safely be deleted.
102 int setup_dusr(struct query *q, char *argv[], client *cl)
104 EXEC SQL BEGIN DECLARE SECTION;
106 char resv[USERS_RESERVATIONS_SIZE];
107 EXEC SQL END DECLARE SECTION;
109 id = *(int *)argv[0];
111 /* For now, only allow users to be deleted if their status is 0
112 * and we have no reservations about deleting them.
114 EXEC SQL SELECT status, reservations INTO :flag, :resv
115 FROM users WHERE users_id = :id;
116 if ((flag != 0 && flag != 4) || *resv)
119 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
120 WHERE member_id = :id AND member_type = 'USER';
123 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
127 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
128 WHERE acl_id = :id AND acl_type = 'USER';
131 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
132 WHERE acl_id = :id AND acl_type = 'USER';
135 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
136 WHERE acl_id = :id AND acl_type = 'USER';
142 EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
143 EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
148 /* setup_dpob: Take care of keeping track of the post office usage.
150 int setup_dpob(struct query *q, char *argv[], client *cl)
152 EXEC SQL BEGIN DECLARE SECTION;
154 char type[USERS_POTYPE_SIZE];
155 EXEC SQL END DECLARE SECTION;
157 user = *(int *)argv[0];
158 EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
159 WHERE users_id = :user;
163 if (!strcmp(strtrim(type), "POP"))
164 set_pop_usage(id, -1);
169 /* setup_dmac - verify that the machine is no longer being referenced
170 * and may safely be deleted.
173 int setup_dmac(struct query *q, char *argv[], client *cl)
175 EXEC SQL BEGIN DECLARE SECTION;
177 EXEC SQL END DECLARE SECTION;
179 id = *(int *)argv[0];
181 EXEC SQL SELECT status INTO :flag FROM machine
185 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
186 WHERE potype = 'POP' AND pop_id = :id;
189 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
193 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
197 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
201 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
205 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
209 EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
213 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
217 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
222 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
226 EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id;
232 /* setup_asnt - verify that the data entered for the subnet is sane.
233 * In particular, make sure that the "low" and "high" addresses are
234 * correctly ordered, i.e., high > low.
237 int setup_asnt(struct query *q, char *argv[], client *cl)
241 /* Check for asnt or usnt. */
242 if (q->type == APPEND)
247 low = atoi(argv[row + 5]);
248 high = atoi(argv[row + 6]);
250 /* Special case 0.0.0.0 and 255.255.255.255 */
251 if (!(low == 0 || low == -1 || high == 0 || high == -1))
255 /* If this is update_subnet, we're done. */
259 /* For an add_subnet query, allocate and fill in a new snet_id */
260 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
266 /* setup_dsnt - verify that the subnet is no longer being referenced
267 * and may safely be deleted.
270 int setup_dsnt(struct query *q, char *argv[], client *cl)
272 EXEC SQL BEGIN DECLARE SECTION;
274 EXEC SQL END DECLARE SECTION;
276 id = *(int *)argv[0];
277 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
285 /* setup_dclu - verify that the cluster is no longer being referenced
286 * and may safely be deleted.
289 int setup_dclu(struct query *q, char *argv[], client *cl)
291 EXEC SQL BEGIN DECLARE SECTION;
293 EXEC SQL END DECLARE SECTION;
295 id = *(int *)argv[0];
296 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
300 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
310 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
311 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
312 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
313 * a -1 there. Remember that this is also used for ulis, with the indexes
314 * at 6 & 7. Also check that the list name does not contain uppercase
315 * characters, control characters, @, or :.
317 * Newlines in list descriptions do bad things to the aliases file
318 * moira generates, so make sure the description doesn't contain any, too.
321 static int badlistchars[] = {
322 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
323 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
324 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
325 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
326 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
327 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
328 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
329 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
330 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
331 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
332 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
333 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
334 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
335 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
336 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
337 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
340 int setup_alis(struct query *q, char *argv[], client *cl)
342 EXEC SQL BEGIN DECLARE SECTION;
345 EXEC SQL END DECLARE SECTION;
349 if (!strcmp(q->shortname, "alis"))
351 else if (!strcmp(q->shortname, "ulis"))
356 desc = argv[9 + idx];
357 else if (q->version == 3)
358 desc = argv[10 + idx];
359 else if (q->version >= 4)
360 desc = argv[12 + idx];
364 EXEC SQL BEGIN DECLARE SECTION;
365 int lid = *(int *)argv[0];
366 EXEC SQL END DECLARE SECTION;
368 if (acl_access_check(lid, cl))
372 for (p = (unsigned char *) name; *p; p++)
374 if (badlistchars[*p])
378 for (p = (unsigned char *) desc; *p; p++)
384 /* Check that it doesn't conflict with a pre-existing weirdly-cased
386 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
387 WHERE LOWER(name) = :name AND name != :name;
391 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
393 if (atoi(argv[5 + idx]))
395 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
397 EXEC SQL SELECT value INTO :ngid FROM numvalues
401 sprintf(argv[6 + idx], "%d", ngid);
404 strcpy(argv[6 + idx], "-1");
407 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
414 /* setup_dlis - verify that the list is no longer being referenced
415 * and may safely be deleted.
418 int setup_dlis(struct query *q, char *argv[], client *cl)
421 EXEC SQL BEGIN DECLARE SECTION;
423 EXEC SQL END DECLARE SECTION;
425 id = *(int *)argv[0];
427 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
428 WHERE member_id = :id AND member_type = 'LIST';
432 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
433 WHERE member_id = :id AND member_type = 'LIST';
437 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
442 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
446 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
450 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
451 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
455 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
456 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
460 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
461 WHERE acl_id = :id AND acl_type = 'LIST';
465 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
466 WHERE entity_id = :id AND type = 'GROUP';
470 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
471 WHERE acl_id = :id AND acl_type = 'LIST';
475 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
476 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
477 OR z.sub_type = 'LIST' AND z.sub_id = :id
478 OR z.iws_type = 'LIST' AND z.iws_id = :id
479 OR z.iui_type = 'LIST' AND z.iui_id = :id
480 OR z.owner_type = 'LIST' and z.owner_id = :id;
484 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
485 WHERE lpc_acl = :id OR ac = :id;
489 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
490 WHERE owner_type = 'LIST' AND owner_id = :id
499 /* setup_dsin - verify that the service is no longer being referenced
500 * and may safely be deleted.
503 int setup_dsin(struct query *q, char *argv[], client *cl)
505 EXEC SQL BEGIN DECLARE SECTION;
508 EXEC SQL END DECLARE SECTION;
511 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
512 WHERE service = UPPER(:svrname);
516 EXEC SQL SELECT inprogress INTO :ec FROM servers
517 WHERE name = UPPER(:svrname);
527 /* setup_dshi - verify that the service-host is no longer being referenced
528 * and may safely be deleted.
531 int setup_dshi(struct query *q, char *argv[], client *cl)
533 EXEC SQL BEGIN DECLARE SECTION;
536 EXEC SQL END DECLARE SECTION;
539 id = *(int *)argv[1];
541 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
542 WHERE service = UPPER(:svrname) AND mach_id = :id;
553 ** setup_add_filesys - verify existance of referenced file systems
559 ** argv[5] - rwaccess
564 ** - for type = NFS/IMAP:
565 ** * extract directory prefix from name
566 ** * verify mach_id/dir in nfsphys
567 ** * verify rwaccess in {r, w, R, W}
569 ** Side effect: sets variable _var_phys_id to the ID of the physical
570 ** filesystem (nfsphys_id for NFS, 0 for RVD)
573 ** MR_NFS - specified directory not exported
574 ** MR_FILESYS_ACCESS - invalid filesys access
578 EXEC SQL BEGIN DECLARE SECTION;
580 EXEC SQL END DECLARE SECTION;
582 int setup_afil(struct query *q, char *argv[], client *cl)
586 EXEC SQL BEGIN DECLARE SECTION;
588 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
589 EXEC SQL END DECLARE SECTION;
592 mach_id = *(int *)argv[2];
597 sprintf(ftype, "fs_access_%s", type);
598 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
599 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
603 return MR_FILESYS_ACCESS;
605 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
608 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
609 return check_nfs(mach_id, name, rwaccess);
615 /* Verify the arguments, depending on the FStype. Also, if this is an
616 * NFS filesystem, then update any quotas for that filesystem to reflect
620 int setup_ufil(struct query *q, char *argv[], client *cl)
624 EXEC SQL BEGIN DECLARE SECTION;
625 int fid, total, who, ok;
626 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
627 short int total_null;
628 EXEC SQL END DECLARE SECTION;
632 mach_id = *(int *)argv[3];
635 fid = *(int *)argv[0];
639 sprintf(ftype, "fs_access_%s", type);
640 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
641 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
645 return MR_FILESYS_ACCESS;
647 EXEC SQL SELECT type INTO :ftype FROM filesys
648 WHERE filsys_id = :fid;
652 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
654 status = check_nfs(mach_id, name, access);
655 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
656 WHERE filsys_id = :fid;
661 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
662 && strcmp(strtrim(ftype), "ERR"))
665 EXEC SQL DELETE FROM quota
666 WHERE type = 'ANY' AND filsys_id = :fid;
667 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
668 WHERE filsys_id = :fid AND phys_id != 0;
671 if (!total_null && (total != 0))
673 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
674 type, modtime, modby, modwith)
675 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
682 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
690 /* Find the NFS physical partition that the named directory is on.
691 * This is done by comparing the dir against the mount point of the
692 * partition. To make sure we get the correct match when there is
693 * more than one, we sort the query in reverse order by dir name.
696 int check_nfs(int mach_id, char *name, char *access)
698 EXEC SQL BEGIN DECLARE SECTION;
699 char dir[NFSPHYS_DIR_SIZE];
701 EXEC SQL END DECLARE SECTION;
707 EXEC SQL DECLARE csr101 CURSOR FOR
708 SELECT nfsphys_id, dir FROM nfsphys
713 EXEC SQL OPEN csr101;
718 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
735 EXEC SQL CLOSE csr101;
742 /* setup_dfil: free any quota records and fsgroup info associated with
743 * a filesystem when it is deleted. Also adjust the allocation numbers.
746 int setup_dfil(struct query *q, char **argv, client *cl)
748 EXEC SQL BEGIN DECLARE SECTION;
749 int id, total, phys_id;
751 EXEC SQL END DECLARE SECTION;
753 id = *(int *)argv[0];
754 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
755 WHERE filsys_id = :id;
760 /** What if there are multiple phys_id's per f/s? (bad data) **/
761 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
762 WHERE filsys_id = :id;
763 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
764 WHERE nfsphys_id = :phys_id;
767 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
768 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
769 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
776 /* setup_dnfp: check to see that the nfs physical partition does not have
777 * any filesystems assigned to it before allowing it to be deleted.
780 int setup_dnfp(struct query *q, char **argv, client *cl)
782 EXEC SQL BEGIN DECLARE SECTION;
785 EXEC SQL END DECLARE SECTION;
787 id = *(int *)argv[0];
789 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
790 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
791 AND np.mach_id = :id AND np.dir = :dir;
800 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
801 * argv[0] = filsys_id
802 * argv[1] = type if "update_quota" or "delete_quota"
803 * argv[2 or 1] = users_id or list_id
806 int setup_dqot(struct query *q, char **argv, client *cl)
808 EXEC SQL BEGIN DECLARE SECTION;
809 int quota, fs, id, physid;
811 EXEC SQL END DECLARE SECTION;
813 fs = *(int *)argv[0];
814 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
817 id = *(int *)argv[2];
822 id = *(int *)argv[1];
825 EXEC SQL SELECT quota INTO :quota FROM quota
826 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
827 EXEC SQL SELECT phys_id INTO :physid FROM filesys
828 WHERE filsys_id = :fs;
829 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
830 WHERE nfsphys_id = :physid;
839 * This routine fetches an appropriate value from the numvalues table.
840 * It is a little hack to get around the fact that SQL doesn't let you
841 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
843 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
844 * from within a setup_...() routine with the appropriate arguments.
846 * Correct functioning of this routine may depend on the assumption
847 * that this query is an APPEND.
850 int prefetch_value(struct query *q, char **argv, client *cl)
852 EXEC SQL BEGIN DECLARE SECTION;
853 char *name = q->validate->object_id;
855 EXEC SQL END DECLARE SECTION;
856 int status, limit, argc;
858 /* set next object id, limiting it if necessary */
859 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
860 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
863 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
866 /* fetch object id */
867 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
870 if (sqlca.sqlerrd[2] != 1)
873 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
874 sprintf(argv[argc], "%d", value);
879 /* prefetch_filesys():
880 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
881 * Appends the filsys_id and the phys_id to the argv so they can be
882 * referenced in an INSERT into a table other than filesys. Also
883 * see comments at prefetch_value().
885 * Assumes the existence of a row where filsys_id = argv[0], since a
886 * filesys label has already been resolved to a filsys_id.
888 int prefetch_filesys(struct query *q, char **argv, client *cl)
890 EXEC SQL BEGIN DECLARE SECTION;
892 EXEC SQL END DECLARE SECTION;
895 fid = *(int *)argv[0];
896 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
900 argc = q->argc + q->vcnt;
901 sprintf(argv[argc++], "%d", phid);
902 sprintf(argv[argc], "%d", fid);
911 int setup_ahst(struct query *q, char **argv, client *cl)
913 EXEC SQL BEGIN DECLARE SECTION;
914 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
915 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
916 int value, id, ssaddr, smask, shigh, slow, cnt;
917 unsigned int saddr, mask, high, low;
918 EXEC SQL END DECLARE SECTION;
922 id = *(int *)argv[0];
924 if (!strcmp(q->shortname, "uhst"))
927 EXEC SQL SELECT name, vendor, model, os
928 INTO :oldname, :vendor, :model, :os
929 FROM machine WHERE mach_id = :id;
936 else if (q->version >= 6 && q->version < 8)
941 /* Sanity check name, vendor, model, and os. */
942 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
943 !hostname_check(argv[row]))
945 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
946 !hostinfo_check(argv[row + 1], 0))
948 if ((row == 0 || strcasecmp(argv[3], model)) &&
949 !hostinfo_check(argv[row + 2], 1))
951 if ((row == 0 || strcasecmp(argv[4], os)) &&
952 !hostinfo_check(argv[row + 3], 0))
955 /* check for duplicate name */
957 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
958 WHERE name = UPPER(:name);
965 if (!strcmp(argv[9 + row + idx], "unassigned"))
967 else if (!strcmp(argv[9 + row + idx], "unique"))
969 if (*(int *)argv[8 + row + idx] == 0)
976 value = ntohl(inet_addr(argv[9 + row + idx]));
985 * an address or unique was specified.
987 id = *(int *)argv[8 + row + idx];
988 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
989 :shigh, :slow FROM subnet WHERE snet_id = :id;
992 saddr = (unsigned) ssaddr;
993 mask = (unsigned) smask;
994 high = (unsigned) shigh;
995 low = (unsigned) slow;
999 * someone specified an IP address for the host record
1001 if ((value & mask) != saddr || value < low || value > high)
1004 * run the address argument through inet_addr(). This
1005 * has the effect that any out of bounds host addrs will
1006 * be converted to a valid host addr. We do this now
1007 * so that the uniqueness check works. We should also
1008 * link in an inet_addr() that returns an error for
1011 addr.s_addr = inet_addr(argv[9 + row + idx]);
1012 name = inet_ntoa(addr);
1013 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1014 WHERE address = :name;
1020 * make IP address is unique. If this a modify request
1021 * (row == 1), then we expect one record to exist.
1023 if (row == 0 || (row == 1 && cnt > 1))
1025 if (row == 1 && cnt == 1)
1027 EXEC SQL SELECT mach_id INTO :id FROM machine
1028 WHERE address = :name;
1029 if (id != *(int *)argv[0])
1037 * a "unique" address was specified. Walk through the
1038 * range specified in the network record, return
1039 * error if no room left.
1041 for (id = low; id <= high; id++)
1043 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1045 addr.s_addr = htonl(id);
1046 name = inet_ntoa(addr);
1047 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1048 WHERE address = :name;
1060 * we have an address in value. Convert it to a string and store it.
1062 addr.s_addr = htonl(value);
1063 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1066 strcpy(argv[9 + row + idx], "unassigned");
1068 /* status checking */
1069 value = atoi(argv[7 + row + idx]);
1070 if (row == 0 && !(value == 1 || value == 0))
1074 id = *(int *)argv[0];
1075 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1080 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1081 WHERE mach_id = :id;
1086 * If this is an update_host query, we're done.
1092 * For an add_host query, allocate and fill in a new machine id,
1093 * and then insert the creator id.
1095 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1098 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1106 int setup_ahal(struct query *q, char **argv, client *cl)
1108 EXEC SQL BEGIN DECLARE SECTION;
1111 EXEC SQL END DECLARE SECTION;
1115 if (!hostname_check(argv[0]))
1118 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1119 name = UPPER(:name);
1128 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1131 int setup_uhha(struct query *q, char **argv, client *cl)
1133 EXEC SQL BEGIN DECLARE SECTION;
1134 char *hwaddr = argv[1];
1136 EXEC SQL END DECLARE SECTION;
1139 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1141 for (p = hwaddr; *p; p++)
1148 if (p != hwaddr + 12)
1151 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1152 FROM machine WHERE hwaddr = :hwaddr;
1154 return MR_NOT_UNIQUE;
1160 /* setup_aprn(): Make sure name/duplexname don't conflict with
1161 * anything. If [ANY] was specified for the spooling host, pick the
1162 * least loaded print server that serves this kind of printer.
1164 int setup_aprn(struct query *q, char **argv, client *cl)
1168 EXEC SQL BEGIN DECLARE SECTION;
1169 int mid, usage, count;
1170 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1171 EXEC SQL END DECLARE SECTION;
1173 /* Check for aprn or uprn. */
1174 if (q->type == APPEND)
1179 name = argv[PRN_NAME + row];
1180 duplexname = argv[PRN_DUPLEXNAME + row];
1187 if (q->type == APPEND)
1189 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1190 WHERE name = :name OR duplexname = :name;
1194 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1195 WHERE ( name = :name OR duplexname = :name )
1196 AND name != :oldname;
1201 return MR_NOT_UNIQUE;
1206 if (q->type == APPEND)
1208 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1209 WHERE name = :duplexname OR duplexname = :duplexname;
1213 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1214 WHERE ( name = :duplexname OR duplexname = :duplexname )
1215 AND name != :oldname;
1221 return MR_NOT_UNIQUE;
1224 if (!strcmp(name, duplexname))
1225 return MR_NOT_UNIQUE;
1227 mid = *(int *)argv[PRN_RM + row];
1230 EXEC SQL DECLARE csr_rm CURSOR FOR
1231 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1233 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1235 AND ps.printer_types = s.string_id;
1238 EXEC SQL OPEN csr_rm;
1244 EXEC SQL FETCH csr_rm INTO :mid, :types;
1248 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1250 if (!strcasecmp(argv[PRN_TYPE + row], p))
1252 EXEC SQL SELECT COUNT(name) INTO :usage
1253 FROM printers WHERE rm = :mid;
1255 if (best < 0 || usage < best)
1258 *(int *)argv[PRN_RM + row] = mid;
1264 EXEC SQL CLOSE csr_rm;
1273 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1274 WHERE mach_id = :mid;
1282 int setup_dpsv(struct query *q, char **argv, client *cl)
1285 EXEC SQL BEGIN DECLARE SECTION;
1287 EXEC SQL END DECLARE SECTION;
1289 id = *(int *)argv[0];
1291 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1299 int setup_dcon(struct query *q, char *argv[], client *cl)
1301 EXEC SQL BEGIN DECLARE SECTION;
1303 char containername[CONTAINERS_NAME_SIZE];
1304 EXEC SQL END DECLARE SECTION;
1306 id = *(int *)argv[0];
1307 /* check to see if there are machines in this container */
1308 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1313 /* check to see if there are subcontainers in this container */
1315 /* get the container name */
1317 EXEC SQL SELECT name INTO :containername
1321 /* trim off the trailing spaces */
1322 strcpy(containername, strtrim(containername));
1324 EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1325 WHERE name LIKE :containername || '/' || '%';
1336 * validate the rfc1035/rfc1123-ness of a hostname
1339 int hostname_check(char *name)
1344 /* Sanity check name: must contain only letters, numerals, and
1345 * hyphen, and not start or end with a hyphen. Also make sure no
1346 * label (the thing the .s seperate) is longer than 63 characters,
1350 for (p = name, count = 0; *p; p++)
1353 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1354 (*p == '-' && p[1] == '.'))
1365 if (*(p - 1) == '-')
1370 int hostinfo_check(char *info, int num)
1377 /* Sanity check host hostinfo: must start with a letter (or number
1378 * if num is true), contain only letters, numerals, and hyphen, and
1379 * not end with a hyphen.
1382 if (!isalpha(*info) && (!num || !isdigit(*info)))
1384 for (p = info; *p; p++)
1386 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1387 (*p == '-' && p[1] == '.'))
1390 if (!isalnum(*(p - 1)))