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;
233 /* setup_dsnt - verify that the subnet is no longer being referenced
234 * and may safely be deleted.
237 int setup_dsnt(struct query *q, char *argv[], client *cl)
239 EXEC SQL BEGIN DECLARE SECTION;
241 EXEC SQL END DECLARE SECTION;
243 id = *(int *)argv[0];
244 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
252 /* setup_dclu - verify that the cluster is no longer being referenced
253 * and may safely be deleted.
256 int setup_dclu(struct query *q, char *argv[], client *cl)
258 EXEC SQL BEGIN DECLARE SECTION;
260 EXEC SQL END DECLARE SECTION;
262 id = *(int *)argv[0];
263 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
267 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
277 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
278 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
279 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
280 * a -1 there. Remember that this is also used for ulis, with the indexes
281 * at 6 & 7. Also check that the list name does not contain uppercase
282 * characters, control characters, @, or :.
284 * Newlines in list descriptions do bad things to the aliases file
285 * moira generates, so make sure the description doesn't contain any, too.
288 static int badlistchars[] = {
289 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
290 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
291 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
292 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
293 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
294 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
295 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
296 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
297 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
298 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
299 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
300 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
301 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
302 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
303 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
304 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
307 int setup_alis(struct query *q, char *argv[], client *cl)
309 EXEC SQL BEGIN DECLARE SECTION;
312 EXEC SQL END DECLARE SECTION;
316 if (!strcmp(q->shortname, "alis"))
318 else if (!strcmp(q->shortname, "ulis"))
323 desc = argv[9 + idx];
324 else if (q->version == 3)
325 desc = argv[10 + idx];
326 else if (q->version >= 4)
327 desc = argv[12 + idx];
331 EXEC SQL BEGIN DECLARE SECTION;
332 int lid = *(int *)argv[0];
333 EXEC SQL END DECLARE SECTION;
335 if (acl_access_check(lid, cl))
339 for (p = (unsigned char *) name; *p; p++)
341 if (badlistchars[*p])
345 for (p = (unsigned char *) desc; *p; p++)
351 /* Check that it doesn't conflict with a pre-existing weirdly-cased
353 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
354 WHERE LOWER(name) = :name AND name != :name;
358 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
360 if (atoi(argv[5 + idx]))
362 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
364 EXEC SQL SELECT value INTO :ngid FROM numvalues
368 sprintf(argv[6 + idx], "%d", ngid);
371 strcpy(argv[6 + idx], "-1");
374 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
381 /* setup_dlis - verify that the list is no longer being referenced
382 * and may safely be deleted.
385 int setup_dlis(struct query *q, char *argv[], client *cl)
388 EXEC SQL BEGIN DECLARE SECTION;
390 EXEC SQL END DECLARE SECTION;
392 id = *(int *)argv[0];
394 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
395 WHERE member_id = :id AND member_type = 'LIST';
399 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
400 WHERE member_id = :id AND member_type = 'LIST';
404 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
409 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
413 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
417 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
418 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
422 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
423 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
427 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
428 WHERE acl_id = :id AND acl_type = 'LIST';
432 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
433 WHERE entity_id = :id AND type = 'GROUP';
437 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
438 WHERE acl_id = :id AND acl_type = 'LIST';
442 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
443 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
444 OR z.sub_type = 'LIST' AND z.sub_id = :id
445 OR z.iws_type = 'LIST' AND z.iws_id = :id
446 OR z.iui_type = 'LIST' AND z.iui_id = :id
447 OR z.owner_type = 'LIST' and z.owner_id = :id;
451 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
452 WHERE lpc_acl = :id OR ac = :id;
456 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
457 WHERE owner_type = 'LIST' AND owner_id = :id
466 /* setup_dsin - verify that the service is no longer being referenced
467 * and may safely be deleted.
470 int setup_dsin(struct query *q, char *argv[], client *cl)
472 EXEC SQL BEGIN DECLARE SECTION;
475 EXEC SQL END DECLARE SECTION;
478 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
479 WHERE service = UPPER(:svrname);
483 EXEC SQL SELECT inprogress INTO :ec FROM servers
484 WHERE name = UPPER(:svrname);
494 /* setup_dshi - verify that the service-host is no longer being referenced
495 * and may safely be deleted.
498 int setup_dshi(struct query *q, char *argv[], client *cl)
500 EXEC SQL BEGIN DECLARE SECTION;
503 EXEC SQL END DECLARE SECTION;
506 id = *(int *)argv[1];
508 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
509 WHERE service = UPPER(:svrname) AND mach_id = :id;
520 ** setup_add_filesys - verify existance of referenced file systems
526 ** argv[5] - rwaccess
531 ** - for type = NFS/IMAP:
532 ** * extract directory prefix from name
533 ** * verify mach_id/dir in nfsphys
534 ** * verify rwaccess in {r, w, R, W}
536 ** Side effect: sets variable _var_phys_id to the ID of the physical
537 ** filesystem (nfsphys_id for NFS, 0 for RVD)
540 ** MR_NFS - specified directory not exported
541 ** MR_FILESYS_ACCESS - invalid filesys access
545 EXEC SQL BEGIN DECLARE SECTION;
547 EXEC SQL END DECLARE SECTION;
549 int setup_afil(struct query *q, char *argv[], client *cl)
553 EXEC SQL BEGIN DECLARE SECTION;
555 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
556 EXEC SQL END DECLARE SECTION;
559 mach_id = *(int *)argv[2];
564 sprintf(ftype, "fs_access_%s", type);
565 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
566 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
570 return MR_FILESYS_ACCESS;
572 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
575 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
576 return check_nfs(mach_id, name, rwaccess);
582 /* Verify the arguments, depending on the FStype. Also, if this is an
583 * NFS filesystem, then update any quotas for that filesystem to reflect
587 int setup_ufil(struct query *q, char *argv[], client *cl)
591 EXEC SQL BEGIN DECLARE SECTION;
592 int fid, total, who, ok;
593 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
594 short int total_null;
595 EXEC SQL END DECLARE SECTION;
599 mach_id = *(int *)argv[3];
602 fid = *(int *)argv[0];
606 sprintf(ftype, "fs_access_%s", type);
607 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
608 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
612 return MR_FILESYS_ACCESS;
614 EXEC SQL SELECT type INTO :ftype FROM filesys
615 WHERE filsys_id = :fid;
619 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
621 status = check_nfs(mach_id, name, access);
622 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
623 WHERE filsys_id = :fid;
628 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
629 && strcmp(strtrim(ftype), "ERR"))
632 EXEC SQL DELETE FROM quota
633 WHERE type = 'ANY' AND filsys_id = :fid;
634 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
635 WHERE filsys_id = :fid AND phys_id != 0;
638 if (!total_null && (total != 0))
640 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
641 type, modtime, modby, modwith)
642 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
649 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
657 /* Find the NFS physical partition that the named directory is on.
658 * This is done by comparing the dir against the mount point of the
659 * partition. To make sure we get the correct match when there is
660 * more than one, we sort the query in reverse order by dir name.
663 int check_nfs(int mach_id, char *name, char *access)
665 EXEC SQL BEGIN DECLARE SECTION;
666 char dir[NFSPHYS_DIR_SIZE];
668 EXEC SQL END DECLARE SECTION;
674 EXEC SQL DECLARE csr101 CURSOR FOR
675 SELECT nfsphys_id, dir FROM nfsphys
680 EXEC SQL OPEN csr101;
685 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
702 EXEC SQL CLOSE csr101;
709 /* setup_dfil: free any quota records and fsgroup info associated with
710 * a filesystem when it is deleted. Also adjust the allocation numbers.
713 int setup_dfil(struct query *q, char **argv, client *cl)
715 EXEC SQL BEGIN DECLARE SECTION;
716 int id, total, phys_id;
718 EXEC SQL END DECLARE SECTION;
720 id = *(int *)argv[0];
721 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
722 WHERE filsys_id = :id;
727 /** What if there are multiple phys_id's per f/s? (bad data) **/
728 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
729 WHERE filsys_id = :id;
730 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
731 WHERE nfsphys_id = :phys_id;
734 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
735 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
736 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
743 /* setup_dnfp: check to see that the nfs physical partition does not have
744 * any filesystems assigned to it before allowing it to be deleted.
747 int setup_dnfp(struct query *q, char **argv, client *cl)
749 EXEC SQL BEGIN DECLARE SECTION;
752 EXEC SQL END DECLARE SECTION;
754 id = *(int *)argv[0];
756 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
757 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
758 AND np.mach_id = :id AND np.dir = :dir;
767 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
768 * argv[0] = filsys_id
769 * argv[1] = type if "update_quota" or "delete_quota"
770 * argv[2 or 1] = users_id or list_id
773 int setup_dqot(struct query *q, char **argv, client *cl)
775 EXEC SQL BEGIN DECLARE SECTION;
776 int quota, fs, id, physid;
778 EXEC SQL END DECLARE SECTION;
780 fs = *(int *)argv[0];
781 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
784 id = *(int *)argv[2];
789 id = *(int *)argv[1];
792 EXEC SQL SELECT quota INTO :quota FROM quota
793 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
794 EXEC SQL SELECT phys_id INTO :physid FROM filesys
795 WHERE filsys_id = :fs;
796 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
797 WHERE nfsphys_id = :physid;
806 * This routine fetches an appropriate value from the numvalues table.
807 * It is a little hack to get around the fact that SQL doesn't let you
808 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
810 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
811 * from within a setup_...() routine with the appropriate arguments.
813 * Correct functioning of this routine may depend on the assumption
814 * that this query is an APPEND.
817 int prefetch_value(struct query *q, char **argv, client *cl)
819 EXEC SQL BEGIN DECLARE SECTION;
820 char *name = q->validate->object_id;
822 EXEC SQL END DECLARE SECTION;
823 int status, limit, argc;
825 /* set next object id, limiting it if necessary */
826 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
827 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
830 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
833 /* fetch object id */
834 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
837 if (sqlca.sqlerrd[2] != 1)
840 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
841 sprintf(argv[argc], "%d", value);
846 /* prefetch_filesys():
847 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
848 * Appends the filsys_id and the phys_id to the argv so they can be
849 * referenced in an INSERT into a table other than filesys. Also
850 * see comments at prefetch_value().
852 * Assumes the existence of a row where filsys_id = argv[0], since a
853 * filesys label has already been resolved to a filsys_id.
855 int prefetch_filesys(struct query *q, char **argv, client *cl)
857 EXEC SQL BEGIN DECLARE SECTION;
859 EXEC SQL END DECLARE SECTION;
862 fid = *(int *)argv[0];
863 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
867 argc = q->argc + q->vcnt;
868 sprintf(argv[argc++], "%d", phid);
869 sprintf(argv[argc], "%d", fid);
878 int setup_ahst(struct query *q, char **argv, client *cl)
880 EXEC SQL BEGIN DECLARE SECTION;
881 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
882 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
883 int value, id, ssaddr, smask, shigh, slow, cnt;
884 unsigned int saddr, mask, high, low;
885 EXEC SQL END DECLARE SECTION;
889 id = *(int *)argv[0];
891 if (!strcmp(q->shortname, "uhst"))
894 EXEC SQL SELECT name, vendor, model, os
895 INTO :oldname, :vendor, :model, :os
896 FROM machine WHERE mach_id = :id;
906 /* Sanity check name, vendor, model, and os. */
907 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
908 !hostname_check(argv[row]))
910 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
911 !hostinfo_check(argv[row + 1], 0))
913 if ((row == 0 || strcasecmp(argv[3], model)) &&
914 !hostinfo_check(argv[row + 2], 1))
916 if ((row == 0 || strcasecmp(argv[4], os)) &&
917 !hostinfo_check(argv[row + 3], 0))
920 /* check for duplicate name */
922 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
923 WHERE name = UPPER(:name);
930 if (!strcmp(argv[9 + row + idx], "unassigned"))
932 else if (!strcmp(argv[9 + row + idx], "unique"))
934 if (*(int *)argv[8 + row + idx] == 0)
941 value = ntohl(inet_addr(argv[9 + row + idx]));
950 * an address or unique was specified.
952 id = *(int *)argv[8 + row + idx];
953 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
954 :shigh, :slow FROM subnet WHERE snet_id = :id;
957 saddr = (unsigned) ssaddr;
958 mask = (unsigned) smask;
959 high = (unsigned) shigh;
960 low = (unsigned) slow;
964 * someone specified an IP address for the host record
966 if ((value & mask) != saddr || value < low || value > high)
969 * run the address argument through inet_addr(). This
970 * has the effect that any out of bounds host addrs will
971 * be converted to a valid host addr. We do this now
972 * so that the uniqueness check works. We should also
973 * link in an inet_addr() that returns an error for
976 addr.s_addr = inet_addr(argv[9 + row + idx]);
977 name = inet_ntoa(addr);
978 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
979 WHERE address = :name;
985 * make IP address is unique. If this a modify request
986 * (row == 1), then we expect one record to exist.
988 if (row == 0 || (row == 1 && cnt > 1))
990 if (row == 1 && cnt == 1)
992 EXEC SQL SELECT mach_id INTO :id FROM machine
993 WHERE address = :name;
994 if (id != *(int *)argv[0])
1002 * a "unique" address was specified. Walk through the
1003 * range specified in the network record, return
1004 * error if no room left.
1006 for (id = low; id <= high; id++)
1008 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1010 addr.s_addr = htonl(id);
1011 name = inet_ntoa(addr);
1012 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1013 WHERE address = :name;
1025 * we have an address in value. Convert it to a string and store it.
1027 addr.s_addr = htonl(value);
1028 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1031 strcpy(argv[9 + row + idx], "unassigned");
1033 /* status checking */
1034 value = atoi(argv[7 + row + idx]);
1035 if (row == 0 && !(value == 1 || value == 0))
1039 id = *(int *)argv[0];
1040 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1045 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1046 WHERE mach_id = :id;
1051 * If this is an update_host query, we're done.
1057 * For an add_host query, allocate and fill in a new machine id,
1058 * and then insert the creator id.
1060 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1063 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1071 int setup_ahal(struct query *q, char **argv, client *cl)
1073 EXEC SQL BEGIN DECLARE SECTION;
1076 EXEC SQL END DECLARE SECTION;
1080 if (!hostname_check(argv[0]))
1083 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1084 name = UPPER(:name);
1093 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1096 int setup_uhha(struct query *q, char **argv, client *cl)
1098 EXEC SQL BEGIN DECLARE SECTION;
1099 char *hwaddr = argv[1];
1101 EXEC SQL END DECLARE SECTION;
1104 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1106 for (p = hwaddr; *p; p++)
1113 if (p != hwaddr + 12)
1116 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1117 FROM machine WHERE hwaddr = :hwaddr;
1119 return MR_NOT_UNIQUE;
1125 /* setup_aprn(): Make sure name/duplexname don't conflict with
1126 * anything. If [ANY] was specified for the spooling host, pick the
1127 * least loaded print server that serves this kind of printer.
1129 int setup_aprn(struct query *q, char **argv, client *cl)
1133 EXEC SQL BEGIN DECLARE SECTION;
1134 int mid, usage, count;
1135 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1136 EXEC SQL END DECLARE SECTION;
1138 /* Check for aprn or uprn. */
1139 if (q->type == APPEND)
1144 name = argv[PRN_NAME + row];
1145 duplexname = argv[PRN_DUPLEXNAME + row];
1152 if (q->type == APPEND)
1154 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1155 WHERE name = :name OR duplexname = :name;
1159 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1160 WHERE ( name = :name OR duplexname = :name )
1161 AND name != :oldname;
1166 return MR_NOT_UNIQUE;
1171 if (q->type == APPEND)
1173 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1174 WHERE name = :duplexname OR duplexname = :duplexname;
1178 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1179 WHERE ( name = :duplexname OR duplexname = :duplexname )
1180 AND name != :oldname;
1186 return MR_NOT_UNIQUE;
1189 if (!strcmp(name, duplexname))
1190 return MR_NOT_UNIQUE;
1192 mid = *(int *)argv[PRN_RM + row];
1195 EXEC SQL DECLARE csr_rm CURSOR FOR
1196 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1198 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1200 AND ps.printer_types = s.string_id;
1203 EXEC SQL OPEN csr_rm;
1209 EXEC SQL FETCH csr_rm INTO :mid, :types;
1213 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1215 if (!strcasecmp(argv[PRN_TYPE + row], p))
1217 EXEC SQL SELECT COUNT(name) INTO :usage
1218 FROM printers WHERE rm = :mid;
1220 if (best < 0 || usage < best)
1223 *(int *)argv[PRN_RM + row] = mid;
1229 EXEC SQL CLOSE csr_rm;
1238 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1239 WHERE mach_id = :mid;
1247 int setup_dpsv(struct query *q, char **argv, client *cl)
1250 EXEC SQL BEGIN DECLARE SECTION;
1252 EXEC SQL END DECLARE SECTION;
1254 id = *(int *)argv[0];
1256 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1264 int setup_dcon(struct query *q, char *argv[], client *cl)
1266 EXEC SQL BEGIN DECLARE SECTION;
1268 char containername[CONTAINERS_NAME_SIZE];
1269 EXEC SQL END DECLARE SECTION;
1271 id = *(int *)argv[0];
1272 /* check to see if there are machines in this container */
1273 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1278 /* check to see if there are subcontainers in this container */
1280 /* get the container name */
1282 EXEC SQL SELECT name INTO :containername
1286 /* trim off the trailing spaces */
1287 strcpy(containername, strtrim(containername));
1289 EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1290 WHERE name LIKE :containername || '/' || '%';
1301 * validate the rfc1035/rfc1123-ness of a hostname
1304 int hostname_check(char *name)
1309 /* Sanity check name: must contain only letters, numerals, and
1310 * hyphen, and not start or end with a hyphen. Also make sure no
1311 * label (the thing the .s seperate) is longer than 63 characters,
1315 for (p = name, count = 0; *p; p++)
1318 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1319 (*p == '-' && p[1] == '.'))
1330 if (*(p - 1) == '-')
1335 int hostinfo_check(char *info, int num)
1342 /* Sanity check host hostinfo: must start with a letter (or number
1343 * if num is true), contain only letters, numerals, and hyphen, and
1344 * not end with a hyphen.
1347 if (!isalpha(*info) && (!num || !isdigit(*info)))
1349 for (p = info; *p; p++)
1351 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1352 (*p == '-' && p[1] == '.'))
1355 if (!isalnum(*(p - 1)))