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"))
65 if (strlen(argv[row + 2]) + strlen(argv[row + 3]) +
66 strlen(argv[row + 4]) + 2 > USERS_FULLNAME_SIZE)
67 return MR_ARG_TOO_LONG;
69 if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1)
71 if ((err = set_next_object_id("unix_uid", USERS_TABLE, 1)))
73 EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'unix_uid';
74 if (sqlca.sqlerrd[2] != 1)
76 sprintf(argv[row], "%d", nuid);
79 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1)
80 sprintf(argv[0], "#%s", argv[row]);
82 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
89 /* setup_dusr - verify that the user is no longer being referenced
90 * and may safely be deleted.
93 int setup_dusr(struct query *q, char *argv[], client *cl)
95 EXEC SQL BEGIN DECLARE SECTION;
97 EXEC SQL END DECLARE SECTION;
101 /* For now, only allow users to be deleted if their status is 0 */
102 EXEC SQL SELECT status INTO :flag FROM users WHERE users_id = :id;
103 if (flag != 0 && flag != 4)
106 EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
107 EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
108 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
109 WHERE member_id = :id AND member_type = 'USER';
112 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
116 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
117 WHERE acl_id = :id AND acl_type = 'USER';
120 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
121 WHERE acl_id = :id AND acl_type = 'USER';
124 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
125 WHERE acl_id = :id AND acl_type = 'USER';
134 /* setup_spop: verify that there is already a valid POP machine_id in the
135 * pop_id field. Also take care of keeping track of the post office usage.
137 int setup_spop(struct query *q, char *argv[], client *cl)
139 EXEC SQL BEGIN DECLARE SECTION;
141 char type[USERS_POTYPE_SIZE];
142 EXEC SQL END DECLARE SECTION;
144 id = *(int *)argv[0];
145 EXEC SQL SELECT potype, pop_id INTO :type, :mid FROM users
146 WHERE users_id = :id;
147 if (sqlca.sqlerrd[2] == 0)
149 EXEC SQL SELECT mach_id INTO :mid FROM machine
150 WHERE mach_id = :mid;
151 if (sqlca.sqlerrd[2] == 0)
153 if (strcmp(strtrim(type), "POP"))
154 set_pop_usage(mid, 1);
159 /* setup_dpob: Take care of keeping track of the post office usage.
161 int setup_dpob(struct query *q, char *argv[], client *cl)
163 EXEC SQL BEGIN DECLARE SECTION;
165 char type[USERS_POTYPE_SIZE];
166 EXEC SQL END DECLARE SECTION;
168 user = *(int *)argv[0];
169 EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
170 WHERE users_id = :user;
174 if (!strcmp(strtrim(type), "POP"))
175 set_pop_usage(id, -1);
180 /* setup_dmac - verify that the machine is no longer being referenced
181 * and may safely be deleted.
184 int setup_dmac(struct query *q, char *argv[], client *cl)
186 EXEC SQL BEGIN DECLARE SECTION;
188 EXEC SQL END DECLARE SECTION;
190 id = *(int *)argv[0];
192 EXEC SQL SELECT status INTO :flag FROM machine
196 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
197 WHERE potype = 'POP' AND pop_id = :id;
200 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
204 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
208 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
212 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
216 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
220 EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
224 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
228 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
233 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
240 /* setup_dsnt - verify that the subnet is no longer being referenced
241 * and may safely be deleted.
244 int setup_dsnt(struct query *q, char *argv[], client *cl)
246 EXEC SQL BEGIN DECLARE SECTION;
248 EXEC SQL END DECLARE SECTION;
250 id = *(int *)argv[0];
251 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
259 /* setup_dclu - verify that the cluster is no longer being referenced
260 * and may safely be deleted.
263 int setup_dclu(struct query *q, char *argv[], client *cl)
265 EXEC SQL BEGIN DECLARE SECTION;
267 EXEC SQL END DECLARE SECTION;
269 id = *(int *)argv[0];
270 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
274 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
284 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
285 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
286 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
287 * a -1 there. Remember that this is also used for ulis, with the indexes
288 * at 6 & 7. Also check that the list name does not contain uppercase
289 * characters, control characters, @, or :.
292 static int badlistchars[] = {
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, 1, /* ^P - ^_ */
295 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */
296 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
297 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
298 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
299 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
300 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
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,
305 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
306 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
307 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
308 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
311 int setup_alis(struct query *q, char *argv[], client *cl)
313 EXEC SQL BEGIN DECLARE SECTION;
316 EXEC SQL END DECLARE SECTION;
320 if (!strcmp(q->shortname, "alis"))
322 else if (!strcmp(q->shortname, "ulis"))
328 EXEC SQL BEGIN DECLARE SECTION;
329 int lid = *(int *)argv[0];
330 EXEC SQL END DECLARE SECTION;
332 if (acl_access_check(lid, cl))
336 for (p = (unsigned char *) name; *p; p++)
338 if (badlistchars[*p])
342 /* Check that it doesn't conflict with a pre-existing weirdly-cased
344 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
345 WHERE LOWER(name) = :name AND name != :name;
349 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
351 if (atoi(argv[5 + idx]))
353 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
355 EXEC SQL SELECT value INTO :ngid FROM numvalues
359 sprintf(argv[6 + idx], "%d", ngid);
362 strcpy(argv[6 + idx], "-1");
365 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
372 /* setup_dlis - verify that the list is no longer being referenced
373 * and may safely be deleted.
376 int setup_dlis(struct query *q, char *argv[], client *cl)
379 EXEC SQL BEGIN DECLARE SECTION;
381 EXEC SQL END DECLARE SECTION;
383 id = *(int *)argv[0];
385 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
386 WHERE member_id = :id AND member_type = 'LIST';
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
400 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
404 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
408 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
409 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
413 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
414 WHERE acl_id = :id AND acl_type = 'LIST';
418 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
419 WHERE entity_id = :id AND type = 'GROUP';
423 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
424 WHERE acl_id = :id AND acl_type = 'LIST';
428 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
429 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
430 OR z.sub_type = 'LIST' AND z.sub_id = :id
431 OR z.iws_type = 'LIST' AND z.iws_id = :id
432 OR z.iui_type = 'LIST' AND z.iui_id = :id;
436 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
437 WHERE lpc_acl = :id OR ac = :id;
441 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
442 WHERE owner_type = 'LIST' AND owner_id = :id
451 /* setup_dsin - verify that the service is no longer being referenced
452 * and may safely be deleted.
455 int setup_dsin(struct query *q, char *argv[], client *cl)
457 EXEC SQL BEGIN DECLARE SECTION;
460 EXEC SQL END DECLARE SECTION;
463 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
464 WHERE service = UPPER(:svrname);
468 EXEC SQL SELECT inprogress INTO :ec FROM servers
469 WHERE name = UPPER(:svrname);
479 /* setup_dshi - verify that the service-host is no longer being referenced
480 * and may safely be deleted.
483 int setup_dshi(struct query *q, char *argv[], client *cl)
485 EXEC SQL BEGIN DECLARE SECTION;
488 EXEC SQL END DECLARE SECTION;
491 id = *(int *)argv[1];
493 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
494 WHERE service = UPPER(:svrname) AND mach_id = :id;
505 ** setup_add_filesys - verify existance of referenced file systems
511 ** argv[5] - rwaccess
517 ** * extract directory prefix from name
518 ** * verify mach_id/dir in nfsphys
519 ** * verify rwaccess in {r, w, R, W}
521 ** Side effect: sets variable _var_phys_id to the ID of the physical
522 ** filesystem (nfsphys_id for NFS, 0 for RVD)
525 ** MR_NFS - specified directory not exported
526 ** MR_FILESYS_ACCESS - invalid filesys access
530 EXEC SQL BEGIN DECLARE SECTION;
532 EXEC SQL END DECLARE SECTION;
534 int setup_afil(struct query *q, char *argv[], client *cl)
538 EXEC SQL BEGIN DECLARE SECTION;
540 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
541 EXEC SQL END DECLARE SECTION;
544 mach_id = *(int *)argv[2];
549 sprintf(ftype, "fs_access_%s", type);
550 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
551 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
555 return MR_FILESYS_ACCESS;
557 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
560 if (!strcmp(type, "NFS"))
561 return check_nfs(mach_id, name, rwaccess);
567 /* Verify the arguments, depending on the FStype. Also, if this is an
568 * NFS filesystem, then update any quotas for that filesystem to reflect
572 int setup_ufil(struct query *q, char *argv[], client *cl)
576 EXEC SQL BEGIN DECLARE SECTION;
577 int fid, total, who, ok;
578 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
579 short int total_null;
580 EXEC SQL END DECLARE SECTION;
584 mach_id = *(int *)argv[3];
587 fid = *(int *)argv[0];
591 sprintf(ftype, "fs_access_%s", type);
592 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
593 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
597 return MR_FILESYS_ACCESS;
599 EXEC SQL SELECT type INTO :ftype FROM filesys
600 WHERE filsys_id = :fid;
604 if (!strcmp(type, "NFS"))
606 status = check_nfs(mach_id, name, access);
607 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
608 WHERE filsys_id = :fid;
613 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
614 && strcmp(strtrim(ftype), "ERR"))
617 EXEC SQL DELETE FROM quota
618 WHERE type = 'ANY' AND filsys_id = :fid;
619 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
620 WHERE filsys_id = :fid AND phys_id != 0;
623 if (!total_null && (total != 0))
625 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
626 type, modtime, modby, modwith)
627 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
634 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
642 /* Find the NFS physical partition that the named directory is on.
643 * This is done by comparing the dir against the mount point of the
644 * partition. To make sure we get the correct match when there is
645 * more than one, we sort the query in reverse order by dir name.
648 int check_nfs(int mach_id, char *name, char *access)
650 EXEC SQL BEGIN DECLARE SECTION;
651 char dir[NFSPHYS_DIR_SIZE];
653 EXEC SQL END DECLARE SECTION;
659 EXEC SQL DECLARE csr101 CURSOR FOR
660 SELECT nfsphys_id, dir FROM nfsphys
665 EXEC SQL OPEN csr101;
670 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
687 EXEC SQL CLOSE csr101;
694 /* setup_dfil: free any quota records and fsgroup info associated with
695 * a filesystem when it is deleted. Also adjust the allocation numbers.
698 int setup_dfil(struct query *q, char **argv, client *cl)
700 EXEC SQL BEGIN DECLARE SECTION;
701 int id, total, phys_id;
703 EXEC SQL END DECLARE SECTION;
705 id = *(int *)argv[0];
706 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
707 WHERE filsys_id = :id;
712 /** What if there are multiple phys_id's per f/s? (bad data) **/
713 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
714 WHERE filsys_id = :id;
715 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
716 WHERE nfsphys_id = :phys_id;
719 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
720 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
721 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
728 /* setup_dnfp: check to see that the nfs physical partition does not have
729 * any filesystems assigned to it before allowing it to be deleted.
732 int setup_dnfp(struct query *q, char **argv, client *cl)
734 EXEC SQL BEGIN DECLARE SECTION;
737 EXEC SQL END DECLARE SECTION;
739 id = *(int *)argv[0];
741 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
742 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
743 AND np.mach_id = :id AND np.dir = :dir;
752 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
753 * argv[0] = filsys_id
754 * argv[1] = type if "update_quota" or "delete_quota"
755 * argv[2 or 1] = users_id or list_id
758 int setup_dqot(struct query *q, char **argv, client *cl)
760 EXEC SQL BEGIN DECLARE SECTION;
761 int quota, fs, id, physid;
763 EXEC SQL END DECLARE SECTION;
765 fs = *(int *)argv[0];
766 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
769 id = *(int *)argv[2];
774 id = *(int *)argv[1];
777 EXEC SQL SELECT quota INTO :quota FROM quota
778 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
779 EXEC SQL SELECT phys_id INTO :physid FROM filesys
780 WHERE filsys_id = :fs;
781 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
782 WHERE nfsphys_id = :physid;
791 * This routine fetches an appropriate value from the numvalues table.
792 * It is a little hack to get around the fact that SQL doesn't let you
793 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
795 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
796 * from within a setup_...() routine with the appropriate arguments.
798 * Correct functioning of this routine may depend on the assumption
799 * that this query is an APPEND.
802 int prefetch_value(struct query *q, char **argv, client *cl)
804 EXEC SQL BEGIN DECLARE SECTION;
805 char *name = q->validate->object_id;
807 EXEC SQL END DECLARE SECTION;
808 int status, limit, argc;
810 /* set next object id, limiting it if necessary */
811 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
812 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
815 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
818 /* fetch object id */
819 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
822 if (sqlca.sqlerrd[2] != 1)
825 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
826 sprintf(argv[argc], "%d", value);
831 /* prefetch_filesys():
832 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
833 * Appends the filsys_id and the phys_id to the argv so they can be
834 * referenced in an INSERT into a table other than filesys. Also
835 * see comments at prefetch_value().
837 * Assumes the existence of a row where filsys_id = argv[0], since a
838 * filesys label has already been resolved to a filsys_id.
840 int prefetch_filesys(struct query *q, char **argv, client *cl)
842 EXEC SQL BEGIN DECLARE SECTION;
844 EXEC SQL END DECLARE SECTION;
847 fid = *(int *)argv[0];
848 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
852 argc = q->argc + q->vcnt;
853 sprintf(argv[argc++], "%d", phid);
854 sprintf(argv[argc], "%d", fid);
863 int setup_ahst(struct query *q, char **argv, client *cl)
865 EXEC SQL BEGIN DECLARE SECTION;
866 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
867 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
868 int value, id, ssaddr, smask, shigh, slow, cnt;
869 unsigned int saddr, mask, high, low;
870 EXEC SQL END DECLARE SECTION;
874 id = *(int *)argv[0];
876 if (!strcmp(q->shortname, "uhst"))
879 EXEC SQL SELECT name, vendor, model, os
880 INTO :oldname, :vendor, :model, :os
881 FROM machine WHERE mach_id = :id;
886 /* Sanity check name, vendor, model, and os. */
887 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
888 !hostname_check(argv[row]))
890 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
891 !hostinfo_check(argv[row + 1], 0))
893 if ((row == 0 || strcasecmp(argv[3], model)) &&
894 !hostinfo_check(argv[row + 2], 1))
896 if ((row == 0 || strcasecmp(argv[4], os)) &&
897 !hostinfo_check(argv[row + 3], 0))
900 /* check for duplicate name */
902 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
903 WHERE name = UPPER(:name);
910 if (!strcmp(argv[9 + row], "unassigned"))
912 else if (!strcmp(argv[9 + row], "unique"))
914 if (*(int *)argv[8 + row] == 0)
921 value = ntohl(inet_addr(argv[9 + row]));
930 * an address or unique was specified.
932 id = *(int *)argv[8 + row];
933 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
934 :shigh, :slow FROM subnet WHERE snet_id = :id;
937 saddr = (unsigned) ssaddr;
938 mask = (unsigned) smask;
939 high = (unsigned) shigh;
940 low = (unsigned) slow;
944 * someone specified an IP address for the host record
946 if ((value & mask) != saddr || value < low || value > high)
949 * run the address argument through inet_addr(). This
950 * has the effect that any out of bounds host addrs will
951 * be converted to a valid host addr. We do this now
952 * so that the uniqueness check works. We should also
953 * link in an inet_addr() that returns an error for
956 addr.s_addr = inet_addr(argv[9 + row]);
957 name = inet_ntoa(addr);
958 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
959 WHERE address = :name;
965 * make IP address is unique. If this a modify request
966 * (row == 1), then we expect one record to exist.
968 if (row == 0 || (row == 1 && cnt > 1))
970 if (row == 1 && cnt == 1)
972 EXEC SQL SELECT mach_id INTO :id FROM machine
973 WHERE address = :name;
974 if (id != *(int *)argv[0])
982 * a "unique" address was specified. Walk through the
983 * range specified in the network record, return
984 * error if no room left.
986 for (id = low; id <= high; id++)
988 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
990 addr.s_addr = htonl(id);
991 name = inet_ntoa(addr);
992 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
993 WHERE address = :name;
1005 * we have an address in value. Convert it to a string and store it.
1007 addr.s_addr = htonl(value);
1008 strcpy(argv[9 + row], inet_ntoa(addr));
1011 strcpy(argv[9 + row], "unassigned");
1013 /* status checking */
1014 value = atoi(argv[7 + row]);
1015 if (row == 0 && !(value == 1 || value == 0))
1019 id = *(int *)argv[0];
1020 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1025 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1026 WHERE mach_id = :id;
1031 * If this is an update_host query, we're done.
1037 * For an add_host query, allocate and fill in a new machine id,
1038 * and then insert the creator id.
1040 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1043 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1051 int setup_ahal(struct query *q, char **argv, client *cl)
1053 EXEC SQL BEGIN DECLARE SECTION;
1056 EXEC SQL END DECLARE SECTION;
1060 if (!hostname_check(argv[0]))
1063 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1064 name = UPPER(:name);
1073 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1076 int setup_uhha(struct query *q, char **argv, client *cl)
1078 EXEC SQL BEGIN DECLARE SECTION;
1079 char *hwaddr = argv[1];
1081 EXEC SQL END DECLARE SECTION;
1084 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1086 for (p = hwaddr; *p; p++)
1093 if (p != hwaddr + 12)
1096 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1097 FROM machine WHERE hwaddr = :hwaddr;
1099 return MR_NOT_UNIQUE;
1105 /* setup_aprn(): Make sure name/duplexname don't conflict with
1106 * anything. If [ANY] was specified for the spooling host, pick the
1107 * least loaded print server that serves this kind of printer.
1109 int setup_aprn(struct query *q, char **argv, client *cl)
1113 EXEC SQL BEGIN DECLARE SECTION;
1114 int mid, usage, count;
1115 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1116 EXEC SQL END DECLARE SECTION;
1118 /* Check for aprn or uprn. */
1119 if (q->type == APPEND)
1124 name = argv[PRN_NAME + row];
1125 duplexname = argv[PRN_DUPLEXNAME + row];
1132 if (q->type == APPEND)
1134 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1135 WHERE name = :name OR duplexname = :name;
1139 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1140 WHERE ( name = :name OR duplexname = :name )
1141 AND name != :oldname;
1146 return MR_NOT_UNIQUE;
1151 if (q->type == APPEND)
1153 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1154 WHERE name = :duplexname OR duplexname = :duplexname;
1158 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1159 WHERE ( name = :duplexname OR duplexname = :duplexname )
1160 AND name != :oldname;
1166 return MR_NOT_UNIQUE;
1169 if (!strcmp(name, duplexname))
1170 return MR_NOT_UNIQUE;
1172 mid = *(int *)argv[PRN_RM + row];
1175 EXEC SQL DECLARE csr_rm CURSOR FOR
1176 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1177 WHERE ps.printer_types = s.string_id;
1180 EXEC SQL OPEN csr_rm;
1186 EXEC SQL FETCH csr_rm INTO :mid, :types;
1190 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1192 if (!strcasecmp(argv[PRN_TYPE + row], p))
1194 EXEC SQL SELECT COUNT(name) INTO :usage
1195 FROM printers WHERE mach_id = :mid;
1197 if (best > 0 && usage < best)
1200 *(int *)argv[PRN_RM + row] = mid;
1206 EXEC SQL CLOSE csr_rm;
1215 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1216 WHERE mach_id = :mid;
1224 int setup_dpsv(struct query *q, char **argv, client *cl)
1227 EXEC SQL BEGIN DECLARE SECTION;
1229 EXEC SQL END DECLARE SECTION;
1231 id = *(int *)argv[0];
1233 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1242 * validate the rfc1035/rfc1123-ness of a hostname
1245 int hostname_check(char *name)
1250 /* Sanity check name: must contain only letters, numerals, and
1251 * hyphen, and not start or end with a hyphen. Also make sure no
1252 * label (the thing the .s seperate) is longer than 63 characters,
1256 for (p = name, count = 0; *p; p++)
1259 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1260 (*p == '-' && p[1] == '.'))
1271 if (*(p - 1) == '-')
1276 int hostinfo_check(char *info, int num)
1283 /* Sanity check host hostinfo: must start with a letter (or number
1284 * if num is true), contain only letters, numerals, and hyphen, and
1285 * not end with a hyphen.
1288 if (!isalpha(*info) && (!num || !isdigit(*info)))
1290 for (p = info; *p; p++)
1292 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1293 (*p == '-' && p[1] == '.'))
1296 if (!isalnum(*(p - 1)))