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 char resv[USERS_RESERVATIONS_SIZE];
98 EXEC SQL END DECLARE SECTION;
100 id = *(int *)argv[0];
102 /* For now, only allow users to be deleted if their status is 0
103 * and we have no reservations about deleting them.
105 EXEC SQL SELECT status, reservations INTO :flag, :resv
106 FROM users WHERE users_id = :id;
107 if ((flag != 0 && flag != 4) || *resv)
110 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
111 WHERE member_id = :id AND member_type = 'USER';
114 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
118 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
119 WHERE acl_id = :id AND acl_type = 'USER';
122 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
123 WHERE acl_id = :id AND acl_type = 'USER';
126 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
127 WHERE acl_id = :id AND acl_type = 'USER';
133 EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
134 EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
139 /* setup_dpob: Take care of keeping track of the post office usage.
141 int setup_dpob(struct query *q, char *argv[], client *cl)
143 EXEC SQL BEGIN DECLARE SECTION;
145 char type[USERS_POTYPE_SIZE];
146 EXEC SQL END DECLARE SECTION;
148 user = *(int *)argv[0];
149 EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
150 WHERE users_id = :user;
154 if (!strcmp(strtrim(type), "POP"))
155 set_pop_usage(id, -1);
160 /* setup_dmac - verify that the machine is no longer being referenced
161 * and may safely be deleted.
164 int setup_dmac(struct query *q, char *argv[], client *cl)
166 EXEC SQL BEGIN DECLARE SECTION;
168 EXEC SQL END DECLARE SECTION;
170 id = *(int *)argv[0];
172 EXEC SQL SELECT status INTO :flag FROM machine
176 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
177 WHERE potype = 'POP' AND pop_id = :id;
180 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
184 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
188 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
192 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
196 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
200 EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
204 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
208 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
213 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
220 /* setup_dsnt - verify that the subnet is no longer being referenced
221 * and may safely be deleted.
224 int setup_dsnt(struct query *q, char *argv[], client *cl)
226 EXEC SQL BEGIN DECLARE SECTION;
228 EXEC SQL END DECLARE SECTION;
230 id = *(int *)argv[0];
231 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
239 /* setup_dclu - verify that the cluster is no longer being referenced
240 * and may safely be deleted.
243 int setup_dclu(struct query *q, char *argv[], client *cl)
245 EXEC SQL BEGIN DECLARE SECTION;
247 EXEC SQL END DECLARE SECTION;
249 id = *(int *)argv[0];
250 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
254 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
264 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
265 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
266 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
267 * a -1 there. Remember that this is also used for ulis, with the indexes
268 * at 6 & 7. Also check that the list name does not contain uppercase
269 * characters, control characters, @, or :.
272 static int badlistchars[] = {
273 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
274 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
275 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */
276 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
277 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
278 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
279 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
280 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
281 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
282 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
283 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
284 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
285 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
286 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
287 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
288 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
291 int setup_alis(struct query *q, char *argv[], client *cl)
293 EXEC SQL BEGIN DECLARE SECTION;
296 EXEC SQL END DECLARE SECTION;
300 if (!strcmp(q->shortname, "alis"))
302 else if (!strcmp(q->shortname, "ulis"))
308 EXEC SQL BEGIN DECLARE SECTION;
309 int lid = *(int *)argv[0];
310 EXEC SQL END DECLARE SECTION;
312 if (acl_access_check(lid, cl))
316 for (p = (unsigned char *) name; *p; p++)
318 if (badlistchars[*p])
322 /* Check that it doesn't conflict with a pre-existing weirdly-cased
324 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
325 WHERE LOWER(name) = :name AND name != :name;
329 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
331 if (atoi(argv[5 + idx]))
333 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
335 EXEC SQL SELECT value INTO :ngid FROM numvalues
339 sprintf(argv[6 + idx], "%d", ngid);
342 strcpy(argv[6 + idx], "-1");
345 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
352 /* setup_dlis - verify that the list is no longer being referenced
353 * and may safely be deleted.
356 int setup_dlis(struct query *q, char *argv[], client *cl)
359 EXEC SQL BEGIN DECLARE SECTION;
361 EXEC SQL END DECLARE SECTION;
363 id = *(int *)argv[0];
365 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
366 WHERE member_id = :id AND member_type = 'LIST';
370 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
371 WHERE member_id = :id AND member_type = 'LIST';
375 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
380 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
384 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
388 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
389 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
393 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
394 WHERE acl_id = :id AND acl_type = 'LIST';
398 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
399 WHERE entity_id = :id AND type = 'GROUP';
403 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
404 WHERE acl_id = :id AND acl_type = 'LIST';
408 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
409 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
410 OR z.sub_type = 'LIST' AND z.sub_id = :id
411 OR z.iws_type = 'LIST' AND z.iws_id = :id
412 OR z.iui_type = 'LIST' AND z.iui_id = :id;
416 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
417 WHERE lpc_acl = :id OR ac = :id;
421 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
422 WHERE owner_type = 'LIST' AND owner_id = :id
431 /* setup_dsin - verify that the service is no longer being referenced
432 * and may safely be deleted.
435 int setup_dsin(struct query *q, char *argv[], client *cl)
437 EXEC SQL BEGIN DECLARE SECTION;
440 EXEC SQL END DECLARE SECTION;
443 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
444 WHERE service = UPPER(:svrname);
448 EXEC SQL SELECT inprogress INTO :ec FROM servers
449 WHERE name = UPPER(:svrname);
459 /* setup_dshi - verify that the service-host is no longer being referenced
460 * and may safely be deleted.
463 int setup_dshi(struct query *q, char *argv[], client *cl)
465 EXEC SQL BEGIN DECLARE SECTION;
468 EXEC SQL END DECLARE SECTION;
471 id = *(int *)argv[1];
473 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
474 WHERE service = UPPER(:svrname) AND mach_id = :id;
485 ** setup_add_filesys - verify existance of referenced file systems
491 ** argv[5] - rwaccess
496 ** - for type = NFS/IMAP:
497 ** * extract directory prefix from name
498 ** * verify mach_id/dir in nfsphys
499 ** * verify rwaccess in {r, w, R, W}
501 ** Side effect: sets variable _var_phys_id to the ID of the physical
502 ** filesystem (nfsphys_id for NFS, 0 for RVD)
505 ** MR_NFS - specified directory not exported
506 ** MR_FILESYS_ACCESS - invalid filesys access
510 EXEC SQL BEGIN DECLARE SECTION;
512 EXEC SQL END DECLARE SECTION;
514 int setup_afil(struct query *q, char *argv[], client *cl)
518 EXEC SQL BEGIN DECLARE SECTION;
520 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
521 EXEC SQL END DECLARE SECTION;
524 mach_id = *(int *)argv[2];
529 sprintf(ftype, "fs_access_%s", type);
530 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
531 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
535 return MR_FILESYS_ACCESS;
537 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
540 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
541 return check_nfs(mach_id, name, rwaccess);
547 /* Verify the arguments, depending on the FStype. Also, if this is an
548 * NFS filesystem, then update any quotas for that filesystem to reflect
552 int setup_ufil(struct query *q, char *argv[], client *cl)
556 EXEC SQL BEGIN DECLARE SECTION;
557 int fid, total, who, ok;
558 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
559 short int total_null;
560 EXEC SQL END DECLARE SECTION;
564 mach_id = *(int *)argv[3];
567 fid = *(int *)argv[0];
571 sprintf(ftype, "fs_access_%s", type);
572 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
573 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
577 return MR_FILESYS_ACCESS;
579 EXEC SQL SELECT type INTO :ftype FROM filesys
580 WHERE filsys_id = :fid;
584 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
586 status = check_nfs(mach_id, name, access);
587 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
588 WHERE filsys_id = :fid;
593 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
594 && strcmp(strtrim(ftype), "ERR"))
597 EXEC SQL DELETE FROM quota
598 WHERE type = 'ANY' AND filsys_id = :fid;
599 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
600 WHERE filsys_id = :fid AND phys_id != 0;
603 if (!total_null && (total != 0))
605 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
606 type, modtime, modby, modwith)
607 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
614 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
622 /* Find the NFS physical partition that the named directory is on.
623 * This is done by comparing the dir against the mount point of the
624 * partition. To make sure we get the correct match when there is
625 * more than one, we sort the query in reverse order by dir name.
628 int check_nfs(int mach_id, char *name, char *access)
630 EXEC SQL BEGIN DECLARE SECTION;
631 char dir[NFSPHYS_DIR_SIZE];
633 EXEC SQL END DECLARE SECTION;
639 EXEC SQL DECLARE csr101 CURSOR FOR
640 SELECT nfsphys_id, dir FROM nfsphys
645 EXEC SQL OPEN csr101;
650 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
667 EXEC SQL CLOSE csr101;
674 /* setup_dfil: free any quota records and fsgroup info associated with
675 * a filesystem when it is deleted. Also adjust the allocation numbers.
678 int setup_dfil(struct query *q, char **argv, client *cl)
680 EXEC SQL BEGIN DECLARE SECTION;
681 int id, total, phys_id;
683 EXEC SQL END DECLARE SECTION;
685 id = *(int *)argv[0];
686 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
687 WHERE filsys_id = :id;
692 /** What if there are multiple phys_id's per f/s? (bad data) **/
693 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
694 WHERE filsys_id = :id;
695 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
696 WHERE nfsphys_id = :phys_id;
699 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
700 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
701 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
708 /* setup_dnfp: check to see that the nfs physical partition does not have
709 * any filesystems assigned to it before allowing it to be deleted.
712 int setup_dnfp(struct query *q, char **argv, client *cl)
714 EXEC SQL BEGIN DECLARE SECTION;
717 EXEC SQL END DECLARE SECTION;
719 id = *(int *)argv[0];
721 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
722 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
723 AND np.mach_id = :id AND np.dir = :dir;
732 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
733 * argv[0] = filsys_id
734 * argv[1] = type if "update_quota" or "delete_quota"
735 * argv[2 or 1] = users_id or list_id
738 int setup_dqot(struct query *q, char **argv, client *cl)
740 EXEC SQL BEGIN DECLARE SECTION;
741 int quota, fs, id, physid;
743 EXEC SQL END DECLARE SECTION;
745 fs = *(int *)argv[0];
746 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
749 id = *(int *)argv[2];
754 id = *(int *)argv[1];
757 EXEC SQL SELECT quota INTO :quota FROM quota
758 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
759 EXEC SQL SELECT phys_id INTO :physid FROM filesys
760 WHERE filsys_id = :fs;
761 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
762 WHERE nfsphys_id = :physid;
771 * This routine fetches an appropriate value from the numvalues table.
772 * It is a little hack to get around the fact that SQL doesn't let you
773 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
775 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
776 * from within a setup_...() routine with the appropriate arguments.
778 * Correct functioning of this routine may depend on the assumption
779 * that this query is an APPEND.
782 int prefetch_value(struct query *q, char **argv, client *cl)
784 EXEC SQL BEGIN DECLARE SECTION;
785 char *name = q->validate->object_id;
787 EXEC SQL END DECLARE SECTION;
788 int status, limit, argc;
790 /* set next object id, limiting it if necessary */
791 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
792 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
795 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
798 /* fetch object id */
799 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
802 if (sqlca.sqlerrd[2] != 1)
805 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
806 sprintf(argv[argc], "%d", value);
811 /* prefetch_filesys():
812 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
813 * Appends the filsys_id and the phys_id to the argv so they can be
814 * referenced in an INSERT into a table other than filesys. Also
815 * see comments at prefetch_value().
817 * Assumes the existence of a row where filsys_id = argv[0], since a
818 * filesys label has already been resolved to a filsys_id.
820 int prefetch_filesys(struct query *q, char **argv, client *cl)
822 EXEC SQL BEGIN DECLARE SECTION;
824 EXEC SQL END DECLARE SECTION;
827 fid = *(int *)argv[0];
828 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
832 argc = q->argc + q->vcnt;
833 sprintf(argv[argc++], "%d", phid);
834 sprintf(argv[argc], "%d", fid);
843 int setup_ahst(struct query *q, char **argv, client *cl)
845 EXEC SQL BEGIN DECLARE SECTION;
846 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
847 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
848 int value, id, ssaddr, smask, shigh, slow, cnt;
849 unsigned int saddr, mask, high, low;
850 EXEC SQL END DECLARE SECTION;
854 id = *(int *)argv[0];
856 if (!strcmp(q->shortname, "uhst"))
859 EXEC SQL SELECT name, vendor, model, os
860 INTO :oldname, :vendor, :model, :os
861 FROM machine WHERE mach_id = :id;
866 /* Sanity check name, vendor, model, and os. */
867 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
868 !hostname_check(argv[row]))
870 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
871 !hostinfo_check(argv[row + 1], 0))
873 if ((row == 0 || strcasecmp(argv[3], model)) &&
874 !hostinfo_check(argv[row + 2], 1))
876 if ((row == 0 || strcasecmp(argv[4], os)) &&
877 !hostinfo_check(argv[row + 3], 0))
880 /* check for duplicate name */
882 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
883 WHERE name = UPPER(:name);
890 if (!strcmp(argv[9 + row], "unassigned"))
892 else if (!strcmp(argv[9 + row], "unique"))
894 if (*(int *)argv[8 + row] == 0)
901 value = ntohl(inet_addr(argv[9 + row]));
910 * an address or unique was specified.
912 id = *(int *)argv[8 + row];
913 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
914 :shigh, :slow FROM subnet WHERE snet_id = :id;
917 saddr = (unsigned) ssaddr;
918 mask = (unsigned) smask;
919 high = (unsigned) shigh;
920 low = (unsigned) slow;
924 * someone specified an IP address for the host record
926 if ((value & mask) != saddr || value < low || value > high)
929 * run the address argument through inet_addr(). This
930 * has the effect that any out of bounds host addrs will
931 * be converted to a valid host addr. We do this now
932 * so that the uniqueness check works. We should also
933 * link in an inet_addr() that returns an error for
936 addr.s_addr = inet_addr(argv[9 + row]);
937 name = inet_ntoa(addr);
938 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
939 WHERE address = :name;
945 * make IP address is unique. If this a modify request
946 * (row == 1), then we expect one record to exist.
948 if (row == 0 || (row == 1 && cnt > 1))
950 if (row == 1 && cnt == 1)
952 EXEC SQL SELECT mach_id INTO :id FROM machine
953 WHERE address = :name;
954 if (id != *(int *)argv[0])
962 * a "unique" address was specified. Walk through the
963 * range specified in the network record, return
964 * error if no room left.
966 for (id = low; id <= high; id++)
968 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
970 addr.s_addr = htonl(id);
971 name = inet_ntoa(addr);
972 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
973 WHERE address = :name;
985 * we have an address in value. Convert it to a string and store it.
987 addr.s_addr = htonl(value);
988 strcpy(argv[9 + row], inet_ntoa(addr));
991 strcpy(argv[9 + row], "unassigned");
993 /* status checking */
994 value = atoi(argv[7 + row]);
995 if (row == 0 && !(value == 1 || value == 0))
999 id = *(int *)argv[0];
1000 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1005 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1006 WHERE mach_id = :id;
1011 * If this is an update_host query, we're done.
1017 * For an add_host query, allocate and fill in a new machine id,
1018 * and then insert the creator id.
1020 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1023 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1031 int setup_ahal(struct query *q, char **argv, client *cl)
1033 EXEC SQL BEGIN DECLARE SECTION;
1036 EXEC SQL END DECLARE SECTION;
1040 if (!hostname_check(argv[0]))
1043 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1044 name = UPPER(:name);
1053 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1056 int setup_uhha(struct query *q, char **argv, client *cl)
1058 EXEC SQL BEGIN DECLARE SECTION;
1059 char *hwaddr = argv[1];
1061 EXEC SQL END DECLARE SECTION;
1064 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1066 for (p = hwaddr; *p; p++)
1073 if (p != hwaddr + 12)
1076 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1077 FROM machine WHERE hwaddr = :hwaddr;
1079 return MR_NOT_UNIQUE;
1085 /* setup_aprn(): Make sure name/duplexname don't conflict with
1086 * anything. If [ANY] was specified for the spooling host, pick the
1087 * least loaded print server that serves this kind of printer.
1089 int setup_aprn(struct query *q, char **argv, client *cl)
1093 EXEC SQL BEGIN DECLARE SECTION;
1094 int mid, usage, count;
1095 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1096 EXEC SQL END DECLARE SECTION;
1098 /* Check for aprn or uprn. */
1099 if (q->type == APPEND)
1104 name = argv[PRN_NAME + row];
1105 duplexname = argv[PRN_DUPLEXNAME + row];
1112 if (q->type == APPEND)
1114 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1115 WHERE name = :name OR duplexname = :name;
1119 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1120 WHERE ( name = :name OR duplexname = :name )
1121 AND name != :oldname;
1126 return MR_NOT_UNIQUE;
1131 if (q->type == APPEND)
1133 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1134 WHERE name = :duplexname OR duplexname = :duplexname;
1138 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1139 WHERE ( name = :duplexname OR duplexname = :duplexname )
1140 AND name != :oldname;
1146 return MR_NOT_UNIQUE;
1149 if (!strcmp(name, duplexname))
1150 return MR_NOT_UNIQUE;
1152 mid = *(int *)argv[PRN_RM + row];
1155 EXEC SQL DECLARE csr_rm CURSOR FOR
1156 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1158 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1160 AND ps.printer_types = s.string_id;
1163 EXEC SQL OPEN csr_rm;
1169 EXEC SQL FETCH csr_rm INTO :mid, :types;
1173 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1175 if (!strcasecmp(argv[PRN_TYPE + row], p))
1177 EXEC SQL SELECT COUNT(name) INTO :usage
1178 FROM printers WHERE rm = :mid;
1180 if (best < 0 || usage < best)
1183 *(int *)argv[PRN_RM + row] = mid;
1189 EXEC SQL CLOSE csr_rm;
1198 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1199 WHERE mach_id = :mid;
1207 int setup_dpsv(struct query *q, char **argv, client *cl)
1210 EXEC SQL BEGIN DECLARE SECTION;
1212 EXEC SQL END DECLARE SECTION;
1214 id = *(int *)argv[0];
1216 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1225 * validate the rfc1035/rfc1123-ness of a hostname
1228 int hostname_check(char *name)
1233 /* Sanity check name: must contain only letters, numerals, and
1234 * hyphen, and not start or end with a hyphen. Also make sure no
1235 * label (the thing the .s seperate) is longer than 63 characters,
1239 for (p = name, count = 0; *p; p++)
1242 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1243 (*p == '-' && p[1] == '.'))
1254 if (*(p - 1) == '-')
1259 int hostinfo_check(char *info, int num)
1266 /* Sanity check host hostinfo: must start with a letter (or number
1267 * if num is true), contain only letters, numerals, and hyphen, and
1268 * not end with a hyphen.
1271 if (!isalpha(*info) && (!num || !isdigit(*info)))
1273 for (p = info; *p; p++)
1275 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1276 (*p == '-' && p[1] == '.'))
1279 if (!isalnum(*(p - 1)))