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;
229 /* setup_dsnt - verify that the subnet is no longer being referenced
230 * and may safely be deleted.
233 int setup_dsnt(struct query *q, char *argv[], client *cl)
235 EXEC SQL BEGIN DECLARE SECTION;
237 EXEC SQL END DECLARE SECTION;
239 id = *(int *)argv[0];
240 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
248 /* setup_dclu - verify that the cluster is no longer being referenced
249 * and may safely be deleted.
252 int setup_dclu(struct query *q, char *argv[], client *cl)
254 EXEC SQL BEGIN DECLARE SECTION;
256 EXEC SQL END DECLARE SECTION;
258 id = *(int *)argv[0];
259 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
263 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
273 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
274 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
275 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
276 * a -1 there. Remember that this is also used for ulis, with the indexes
277 * at 6 & 7. Also check that the list name does not contain uppercase
278 * characters, control characters, @, or :.
280 * Newlines in list descriptions do bad things to the aliases file
281 * moira generates, so make sure the description doesn't contain any, too.
284 static int badlistchars[] = {
285 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
286 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
287 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
288 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
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, 0, /* P - _ */
291 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
292 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
293 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
294 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
295 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
296 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
303 int setup_alis(struct query *q, char *argv[], client *cl)
305 EXEC SQL BEGIN DECLARE SECTION;
308 EXEC SQL END DECLARE SECTION;
312 if (!strcmp(q->shortname, "alis"))
314 else if (!strcmp(q->shortname, "ulis"))
319 desc = argv[9 + idx];
320 else if (q->version == 3)
321 desc = argv[10 + idx];
322 else if (q->version >= 4)
323 desc = argv[12 + idx];
327 EXEC SQL BEGIN DECLARE SECTION;
328 int lid = *(int *)argv[0];
329 EXEC SQL END DECLARE SECTION;
331 if (acl_access_check(lid, cl))
335 for (p = (unsigned char *) name; *p; p++)
337 if (badlistchars[*p])
341 for (p = (unsigned char *) desc; *p; p++)
347 /* Check that it doesn't conflict with a pre-existing weirdly-cased
349 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
350 WHERE LOWER(name) = :name AND name != :name;
354 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
356 if (atoi(argv[5 + idx]))
358 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
360 EXEC SQL SELECT value INTO :ngid FROM numvalues
364 sprintf(argv[6 + idx], "%d", ngid);
367 strcpy(argv[6 + idx], "-1");
370 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
377 /* setup_dlis - verify that the list is no longer being referenced
378 * and may safely be deleted.
381 int setup_dlis(struct query *q, char *argv[], client *cl)
384 EXEC SQL BEGIN DECLARE SECTION;
386 EXEC SQL END DECLARE SECTION;
388 id = *(int *)argv[0];
390 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
391 WHERE member_id = :id AND member_type = 'LIST';
395 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
396 WHERE member_id = :id AND member_type = 'LIST';
400 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
405 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
409 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
413 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
414 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
418 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
419 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
423 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
424 WHERE acl_id = :id AND acl_type = 'LIST';
428 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
429 WHERE entity_id = :id AND type = 'GROUP';
433 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
434 WHERE acl_id = :id AND acl_type = 'LIST';
438 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
439 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
440 OR z.sub_type = 'LIST' AND z.sub_id = :id
441 OR z.iws_type = 'LIST' AND z.iws_id = :id
442 OR z.iui_type = 'LIST' AND z.iui_id = :id
443 OR z.owner_type = 'LIST' and z.owner_id = :id;
447 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
448 WHERE lpc_acl = :id OR ac = :id;
452 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
453 WHERE owner_type = 'LIST' AND owner_id = :id
462 /* setup_dsin - verify that the service is no longer being referenced
463 * and may safely be deleted.
466 int setup_dsin(struct query *q, char *argv[], client *cl)
468 EXEC SQL BEGIN DECLARE SECTION;
471 EXEC SQL END DECLARE SECTION;
474 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
475 WHERE service = UPPER(:svrname);
479 EXEC SQL SELECT inprogress INTO :ec FROM servers
480 WHERE name = UPPER(:svrname);
490 /* setup_dshi - verify that the service-host is no longer being referenced
491 * and may safely be deleted.
494 int setup_dshi(struct query *q, char *argv[], client *cl)
496 EXEC SQL BEGIN DECLARE SECTION;
499 EXEC SQL END DECLARE SECTION;
502 id = *(int *)argv[1];
504 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
505 WHERE service = UPPER(:svrname) AND mach_id = :id;
516 ** setup_add_filesys - verify existance of referenced file systems
522 ** argv[5] - rwaccess
527 ** - for type = NFS/IMAP:
528 ** * extract directory prefix from name
529 ** * verify mach_id/dir in nfsphys
530 ** * verify rwaccess in {r, w, R, W}
532 ** Side effect: sets variable _var_phys_id to the ID of the physical
533 ** filesystem (nfsphys_id for NFS, 0 for RVD)
536 ** MR_NFS - specified directory not exported
537 ** MR_FILESYS_ACCESS - invalid filesys access
541 EXEC SQL BEGIN DECLARE SECTION;
543 EXEC SQL END DECLARE SECTION;
545 int setup_afil(struct query *q, char *argv[], client *cl)
549 EXEC SQL BEGIN DECLARE SECTION;
551 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
552 EXEC SQL END DECLARE SECTION;
555 mach_id = *(int *)argv[2];
560 sprintf(ftype, "fs_access_%s", type);
561 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
562 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
566 return MR_FILESYS_ACCESS;
568 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
571 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
572 return check_nfs(mach_id, name, rwaccess);
578 /* Verify the arguments, depending on the FStype. Also, if this is an
579 * NFS filesystem, then update any quotas for that filesystem to reflect
583 int setup_ufil(struct query *q, char *argv[], client *cl)
587 EXEC SQL BEGIN DECLARE SECTION;
588 int fid, total, who, ok;
589 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
590 short int total_null;
591 EXEC SQL END DECLARE SECTION;
595 mach_id = *(int *)argv[3];
598 fid = *(int *)argv[0];
602 sprintf(ftype, "fs_access_%s", type);
603 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
604 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
608 return MR_FILESYS_ACCESS;
610 EXEC SQL SELECT type INTO :ftype FROM filesys
611 WHERE filsys_id = :fid;
615 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
617 status = check_nfs(mach_id, name, access);
618 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
619 WHERE filsys_id = :fid;
624 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
625 && strcmp(strtrim(ftype), "ERR"))
628 EXEC SQL DELETE FROM quota
629 WHERE type = 'ANY' AND filsys_id = :fid;
630 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
631 WHERE filsys_id = :fid AND phys_id != 0;
634 if (!total_null && (total != 0))
636 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
637 type, modtime, modby, modwith)
638 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
645 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
653 /* Find the NFS physical partition that the named directory is on.
654 * This is done by comparing the dir against the mount point of the
655 * partition. To make sure we get the correct match when there is
656 * more than one, we sort the query in reverse order by dir name.
659 int check_nfs(int mach_id, char *name, char *access)
661 EXEC SQL BEGIN DECLARE SECTION;
662 char dir[NFSPHYS_DIR_SIZE];
664 EXEC SQL END DECLARE SECTION;
670 EXEC SQL DECLARE csr101 CURSOR FOR
671 SELECT nfsphys_id, dir FROM nfsphys
676 EXEC SQL OPEN csr101;
681 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
698 EXEC SQL CLOSE csr101;
705 /* setup_dfil: free any quota records and fsgroup info associated with
706 * a filesystem when it is deleted. Also adjust the allocation numbers.
709 int setup_dfil(struct query *q, char **argv, client *cl)
711 EXEC SQL BEGIN DECLARE SECTION;
712 int id, total, phys_id;
714 EXEC SQL END DECLARE SECTION;
716 id = *(int *)argv[0];
717 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
718 WHERE filsys_id = :id;
723 /** What if there are multiple phys_id's per f/s? (bad data) **/
724 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
725 WHERE filsys_id = :id;
726 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
727 WHERE nfsphys_id = :phys_id;
730 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
731 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
732 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
739 /* setup_dnfp: check to see that the nfs physical partition does not have
740 * any filesystems assigned to it before allowing it to be deleted.
743 int setup_dnfp(struct query *q, char **argv, client *cl)
745 EXEC SQL BEGIN DECLARE SECTION;
748 EXEC SQL END DECLARE SECTION;
750 id = *(int *)argv[0];
752 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
753 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
754 AND np.mach_id = :id AND np.dir = :dir;
763 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
764 * argv[0] = filsys_id
765 * argv[1] = type if "update_quota" or "delete_quota"
766 * argv[2 or 1] = users_id or list_id
769 int setup_dqot(struct query *q, char **argv, client *cl)
771 EXEC SQL BEGIN DECLARE SECTION;
772 int quota, fs, id, physid;
774 EXEC SQL END DECLARE SECTION;
776 fs = *(int *)argv[0];
777 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
780 id = *(int *)argv[2];
785 id = *(int *)argv[1];
788 EXEC SQL SELECT quota INTO :quota FROM quota
789 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
790 EXEC SQL SELECT phys_id INTO :physid FROM filesys
791 WHERE filsys_id = :fs;
792 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
793 WHERE nfsphys_id = :physid;
802 * This routine fetches an appropriate value from the numvalues table.
803 * It is a little hack to get around the fact that SQL doesn't let you
804 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
806 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
807 * from within a setup_...() routine with the appropriate arguments.
809 * Correct functioning of this routine may depend on the assumption
810 * that this query is an APPEND.
813 int prefetch_value(struct query *q, char **argv, client *cl)
815 EXEC SQL BEGIN DECLARE SECTION;
816 char *name = q->validate->object_id;
818 EXEC SQL END DECLARE SECTION;
819 int status, limit, argc;
821 /* set next object id, limiting it if necessary */
822 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
823 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
826 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
829 /* fetch object id */
830 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
833 if (sqlca.sqlerrd[2] != 1)
836 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
837 sprintf(argv[argc], "%d", value);
842 /* prefetch_filesys():
843 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
844 * Appends the filsys_id and the phys_id to the argv so they can be
845 * referenced in an INSERT into a table other than filesys. Also
846 * see comments at prefetch_value().
848 * Assumes the existence of a row where filsys_id = argv[0], since a
849 * filesys label has already been resolved to a filsys_id.
851 int prefetch_filesys(struct query *q, char **argv, client *cl)
853 EXEC SQL BEGIN DECLARE SECTION;
855 EXEC SQL END DECLARE SECTION;
858 fid = *(int *)argv[0];
859 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
863 argc = q->argc + q->vcnt;
864 sprintf(argv[argc++], "%d", phid);
865 sprintf(argv[argc], "%d", fid);
874 int setup_ahst(struct query *q, char **argv, client *cl)
876 EXEC SQL BEGIN DECLARE SECTION;
877 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
878 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
879 int value, id, ssaddr, smask, shigh, slow, cnt;
880 unsigned int saddr, mask, high, low;
881 EXEC SQL END DECLARE SECTION;
885 id = *(int *)argv[0];
887 if (!strcmp(q->shortname, "uhst"))
890 EXEC SQL SELECT name, vendor, model, os
891 INTO :oldname, :vendor, :model, :os
892 FROM machine WHERE mach_id = :id;
902 /* Sanity check name, vendor, model, and os. */
903 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
904 !hostname_check(argv[row]))
906 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
907 !hostinfo_check(argv[row + 1], 0))
909 if ((row == 0 || strcasecmp(argv[3], model)) &&
910 !hostinfo_check(argv[row + 2], 1))
912 if ((row == 0 || strcasecmp(argv[4], os)) &&
913 !hostinfo_check(argv[row + 3], 0))
916 /* check for duplicate name */
918 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
919 WHERE name = UPPER(:name);
926 if (!strcmp(argv[9 + row + idx], "unassigned"))
928 else if (!strcmp(argv[9 + row + idx], "unique"))
930 if (*(int *)argv[8 + row + idx] == 0)
937 value = ntohl(inet_addr(argv[9 + row + idx]));
946 * an address or unique was specified.
948 id = *(int *)argv[8 + row + idx];
949 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
950 :shigh, :slow FROM subnet WHERE snet_id = :id;
953 saddr = (unsigned) ssaddr;
954 mask = (unsigned) smask;
955 high = (unsigned) shigh;
956 low = (unsigned) slow;
960 * someone specified an IP address for the host record
962 if ((value & mask) != saddr || value < low || value > high)
965 * run the address argument through inet_addr(). This
966 * has the effect that any out of bounds host addrs will
967 * be converted to a valid host addr. We do this now
968 * so that the uniqueness check works. We should also
969 * link in an inet_addr() that returns an error for
972 addr.s_addr = inet_addr(argv[9 + row + idx]);
973 name = inet_ntoa(addr);
974 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
975 WHERE address = :name;
981 * make IP address is unique. If this a modify request
982 * (row == 1), then we expect one record to exist.
984 if (row == 0 || (row == 1 && cnt > 1))
986 if (row == 1 && cnt == 1)
988 EXEC SQL SELECT mach_id INTO :id FROM machine
989 WHERE address = :name;
990 if (id != *(int *)argv[0])
998 * a "unique" address was specified. Walk through the
999 * range specified in the network record, return
1000 * error if no room left.
1002 for (id = low; id <= high; id++)
1004 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1006 addr.s_addr = htonl(id);
1007 name = inet_ntoa(addr);
1008 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1009 WHERE address = :name;
1021 * we have an address in value. Convert it to a string and store it.
1023 addr.s_addr = htonl(value);
1024 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1027 strcpy(argv[9 + row + idx], "unassigned");
1029 /* status checking */
1030 value = atoi(argv[7 + row + idx]);
1031 if (row == 0 && !(value == 1 || value == 0))
1035 id = *(int *)argv[0];
1036 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1041 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1042 WHERE mach_id = :id;
1047 * If this is an update_host query, we're done.
1053 * For an add_host query, allocate and fill in a new machine id,
1054 * and then insert the creator id.
1056 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1059 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1067 int setup_ahal(struct query *q, char **argv, client *cl)
1069 EXEC SQL BEGIN DECLARE SECTION;
1072 EXEC SQL END DECLARE SECTION;
1076 if (!hostname_check(argv[0]))
1079 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1080 name = UPPER(:name);
1089 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1092 int setup_uhha(struct query *q, char **argv, client *cl)
1094 EXEC SQL BEGIN DECLARE SECTION;
1095 char *hwaddr = argv[1];
1097 EXEC SQL END DECLARE SECTION;
1100 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1102 for (p = hwaddr; *p; p++)
1109 if (p != hwaddr + 12)
1112 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1113 FROM machine WHERE hwaddr = :hwaddr;
1115 return MR_NOT_UNIQUE;
1121 /* setup_aprn(): Make sure name/duplexname don't conflict with
1122 * anything. If [ANY] was specified for the spooling host, pick the
1123 * least loaded print server that serves this kind of printer.
1125 int setup_aprn(struct query *q, char **argv, client *cl)
1129 EXEC SQL BEGIN DECLARE SECTION;
1130 int mid, usage, count;
1131 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1132 EXEC SQL END DECLARE SECTION;
1134 /* Check for aprn or uprn. */
1135 if (q->type == APPEND)
1140 name = argv[PRN_NAME + row];
1141 duplexname = argv[PRN_DUPLEXNAME + row];
1148 if (q->type == APPEND)
1150 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1151 WHERE name = :name OR duplexname = :name;
1155 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1156 WHERE ( name = :name OR duplexname = :name )
1157 AND name != :oldname;
1162 return MR_NOT_UNIQUE;
1167 if (q->type == APPEND)
1169 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1170 WHERE name = :duplexname OR duplexname = :duplexname;
1174 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1175 WHERE ( name = :duplexname OR duplexname = :duplexname )
1176 AND name != :oldname;
1182 return MR_NOT_UNIQUE;
1185 if (!strcmp(name, duplexname))
1186 return MR_NOT_UNIQUE;
1188 mid = *(int *)argv[PRN_RM + row];
1191 EXEC SQL DECLARE csr_rm CURSOR FOR
1192 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1194 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1196 AND ps.printer_types = s.string_id;
1199 EXEC SQL OPEN csr_rm;
1205 EXEC SQL FETCH csr_rm INTO :mid, :types;
1209 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1211 if (!strcasecmp(argv[PRN_TYPE + row], p))
1213 EXEC SQL SELECT COUNT(name) INTO :usage
1214 FROM printers WHERE rm = :mid;
1216 if (best < 0 || usage < best)
1219 *(int *)argv[PRN_RM + row] = mid;
1225 EXEC SQL CLOSE csr_rm;
1234 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1235 WHERE mach_id = :mid;
1243 int setup_dpsv(struct query *q, char **argv, client *cl)
1246 EXEC SQL BEGIN DECLARE SECTION;
1248 EXEC SQL END DECLARE SECTION;
1250 id = *(int *)argv[0];
1252 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1261 * validate the rfc1035/rfc1123-ness of a hostname
1264 int hostname_check(char *name)
1269 /* Sanity check name: must contain only letters, numerals, and
1270 * hyphen, and not start or end with a hyphen. Also make sure no
1271 * label (the thing the .s seperate) is longer than 63 characters,
1275 for (p = name, count = 0; *p; p++)
1278 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1279 (*p == '-' && p[1] == '.'))
1290 if (*(p - 1) == '-')
1295 int hostinfo_check(char *info, int num)
1302 /* Sanity check host hostinfo: must start with a letter (or number
1303 * if num is true), contain only letters, numerals, and hyphen, and
1304 * not end with a hyphen.
1307 if (!isalpha(*info) && (!num || !isdigit(*info)))
1309 for (p = info; *p; p++)
1311 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1312 (*p == '-' && p[1] == '.'))
1315 if (!isalnum(*(p - 1)))