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 :.
281 static int badlistchars[] = {
282 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
283 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
284 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, /* SPACE - / */
285 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
286 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
287 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
288 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
289 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
290 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
291 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
292 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
300 int setup_alis(struct query *q, char *argv[], client *cl)
302 EXEC SQL BEGIN DECLARE SECTION;
305 EXEC SQL END DECLARE SECTION;
309 if (!strcmp(q->shortname, "alis"))
311 else if (!strcmp(q->shortname, "ulis"))
317 EXEC SQL BEGIN DECLARE SECTION;
318 int lid = *(int *)argv[0];
319 EXEC SQL END DECLARE SECTION;
321 if (acl_access_check(lid, cl))
325 for (p = (unsigned char *) name; *p; p++)
327 if (badlistchars[*p])
331 /* Check that it doesn't conflict with a pre-existing weirdly-cased
333 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
334 WHERE LOWER(name) = :name AND name != :name;
338 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
340 if (atoi(argv[5 + idx]))
342 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
344 EXEC SQL SELECT value INTO :ngid FROM numvalues
348 sprintf(argv[6 + idx], "%d", ngid);
351 strcpy(argv[6 + idx], "-1");
354 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
361 /* setup_dlis - verify that the list is no longer being referenced
362 * and may safely be deleted.
365 int setup_dlis(struct query *q, char *argv[], client *cl)
368 EXEC SQL BEGIN DECLARE SECTION;
370 EXEC SQL END DECLARE SECTION;
372 id = *(int *)argv[0];
374 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
375 WHERE member_id = :id AND member_type = 'LIST';
379 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
380 WHERE member_id = :id AND member_type = 'LIST';
384 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
389 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
393 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
397 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
398 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
402 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
403 WHERE acl_id = :id AND acl_type = 'LIST';
407 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
408 WHERE entity_id = :id AND type = 'GROUP';
412 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
413 WHERE acl_id = :id AND acl_type = 'LIST';
417 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
418 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
419 OR z.sub_type = 'LIST' AND z.sub_id = :id
420 OR z.iws_type = 'LIST' AND z.iws_id = :id
421 OR z.iui_type = 'LIST' AND z.iui_id = :id;
425 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
426 WHERE lpc_acl = :id OR ac = :id;
430 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
431 WHERE owner_type = 'LIST' AND owner_id = :id
440 /* setup_dsin - verify that the service is no longer being referenced
441 * and may safely be deleted.
444 int setup_dsin(struct query *q, char *argv[], client *cl)
446 EXEC SQL BEGIN DECLARE SECTION;
449 EXEC SQL END DECLARE SECTION;
452 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
453 WHERE service = UPPER(:svrname);
457 EXEC SQL SELECT inprogress INTO :ec FROM servers
458 WHERE name = UPPER(:svrname);
468 /* setup_dshi - verify that the service-host is no longer being referenced
469 * and may safely be deleted.
472 int setup_dshi(struct query *q, char *argv[], client *cl)
474 EXEC SQL BEGIN DECLARE SECTION;
477 EXEC SQL END DECLARE SECTION;
480 id = *(int *)argv[1];
482 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
483 WHERE service = UPPER(:svrname) AND mach_id = :id;
494 ** setup_add_filesys - verify existance of referenced file systems
500 ** argv[5] - rwaccess
505 ** - for type = NFS/IMAP:
506 ** * extract directory prefix from name
507 ** * verify mach_id/dir in nfsphys
508 ** * verify rwaccess in {r, w, R, W}
510 ** Side effect: sets variable _var_phys_id to the ID of the physical
511 ** filesystem (nfsphys_id for NFS, 0 for RVD)
514 ** MR_NFS - specified directory not exported
515 ** MR_FILESYS_ACCESS - invalid filesys access
519 EXEC SQL BEGIN DECLARE SECTION;
521 EXEC SQL END DECLARE SECTION;
523 int setup_afil(struct query *q, char *argv[], client *cl)
527 EXEC SQL BEGIN DECLARE SECTION;
529 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
530 EXEC SQL END DECLARE SECTION;
533 mach_id = *(int *)argv[2];
538 sprintf(ftype, "fs_access_%s", type);
539 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
540 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
544 return MR_FILESYS_ACCESS;
546 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
549 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
550 return check_nfs(mach_id, name, rwaccess);
556 /* Verify the arguments, depending on the FStype. Also, if this is an
557 * NFS filesystem, then update any quotas for that filesystem to reflect
561 int setup_ufil(struct query *q, char *argv[], client *cl)
565 EXEC SQL BEGIN DECLARE SECTION;
566 int fid, total, who, ok;
567 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
568 short int total_null;
569 EXEC SQL END DECLARE SECTION;
573 mach_id = *(int *)argv[3];
576 fid = *(int *)argv[0];
580 sprintf(ftype, "fs_access_%s", type);
581 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
582 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
586 return MR_FILESYS_ACCESS;
588 EXEC SQL SELECT type INTO :ftype FROM filesys
589 WHERE filsys_id = :fid;
593 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
595 status = check_nfs(mach_id, name, access);
596 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
597 WHERE filsys_id = :fid;
602 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
603 && strcmp(strtrim(ftype), "ERR"))
606 EXEC SQL DELETE FROM quota
607 WHERE type = 'ANY' AND filsys_id = :fid;
608 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
609 WHERE filsys_id = :fid AND phys_id != 0;
612 if (!total_null && (total != 0))
614 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
615 type, modtime, modby, modwith)
616 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
623 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
631 /* Find the NFS physical partition that the named directory is on.
632 * This is done by comparing the dir against the mount point of the
633 * partition. To make sure we get the correct match when there is
634 * more than one, we sort the query in reverse order by dir name.
637 int check_nfs(int mach_id, char *name, char *access)
639 EXEC SQL BEGIN DECLARE SECTION;
640 char dir[NFSPHYS_DIR_SIZE];
642 EXEC SQL END DECLARE SECTION;
648 EXEC SQL DECLARE csr101 CURSOR FOR
649 SELECT nfsphys_id, dir FROM nfsphys
654 EXEC SQL OPEN csr101;
659 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
676 EXEC SQL CLOSE csr101;
683 /* setup_dfil: free any quota records and fsgroup info associated with
684 * a filesystem when it is deleted. Also adjust the allocation numbers.
687 int setup_dfil(struct query *q, char **argv, client *cl)
689 EXEC SQL BEGIN DECLARE SECTION;
690 int id, total, phys_id;
692 EXEC SQL END DECLARE SECTION;
694 id = *(int *)argv[0];
695 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
696 WHERE filsys_id = :id;
701 /** What if there are multiple phys_id's per f/s? (bad data) **/
702 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
703 WHERE filsys_id = :id;
704 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
705 WHERE nfsphys_id = :phys_id;
708 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
709 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
710 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
717 /* setup_dnfp: check to see that the nfs physical partition does not have
718 * any filesystems assigned to it before allowing it to be deleted.
721 int setup_dnfp(struct query *q, char **argv, client *cl)
723 EXEC SQL BEGIN DECLARE SECTION;
726 EXEC SQL END DECLARE SECTION;
728 id = *(int *)argv[0];
730 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
731 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
732 AND np.mach_id = :id AND np.dir = :dir;
741 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
742 * argv[0] = filsys_id
743 * argv[1] = type if "update_quota" or "delete_quota"
744 * argv[2 or 1] = users_id or list_id
747 int setup_dqot(struct query *q, char **argv, client *cl)
749 EXEC SQL BEGIN DECLARE SECTION;
750 int quota, fs, id, physid;
752 EXEC SQL END DECLARE SECTION;
754 fs = *(int *)argv[0];
755 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
758 id = *(int *)argv[2];
763 id = *(int *)argv[1];
766 EXEC SQL SELECT quota INTO :quota FROM quota
767 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
768 EXEC SQL SELECT phys_id INTO :physid FROM filesys
769 WHERE filsys_id = :fs;
770 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
771 WHERE nfsphys_id = :physid;
780 * This routine fetches an appropriate value from the numvalues table.
781 * It is a little hack to get around the fact that SQL doesn't let you
782 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
784 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
785 * from within a setup_...() routine with the appropriate arguments.
787 * Correct functioning of this routine may depend on the assumption
788 * that this query is an APPEND.
791 int prefetch_value(struct query *q, char **argv, client *cl)
793 EXEC SQL BEGIN DECLARE SECTION;
794 char *name = q->validate->object_id;
796 EXEC SQL END DECLARE SECTION;
797 int status, limit, argc;
799 /* set next object id, limiting it if necessary */
800 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
801 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
804 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
807 /* fetch object id */
808 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
811 if (sqlca.sqlerrd[2] != 1)
814 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
815 sprintf(argv[argc], "%d", value);
820 /* prefetch_filesys():
821 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
822 * Appends the filsys_id and the phys_id to the argv so they can be
823 * referenced in an INSERT into a table other than filesys. Also
824 * see comments at prefetch_value().
826 * Assumes the existence of a row where filsys_id = argv[0], since a
827 * filesys label has already been resolved to a filsys_id.
829 int prefetch_filesys(struct query *q, char **argv, client *cl)
831 EXEC SQL BEGIN DECLARE SECTION;
833 EXEC SQL END DECLARE SECTION;
836 fid = *(int *)argv[0];
837 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
841 argc = q->argc + q->vcnt;
842 sprintf(argv[argc++], "%d", phid);
843 sprintf(argv[argc], "%d", fid);
852 int setup_ahst(struct query *q, char **argv, client *cl)
854 EXEC SQL BEGIN DECLARE SECTION;
855 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
856 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
857 int value, id, ssaddr, smask, shigh, slow, cnt;
858 unsigned int saddr, mask, high, low;
859 EXEC SQL END DECLARE SECTION;
863 id = *(int *)argv[0];
865 if (!strcmp(q->shortname, "uhst"))
868 EXEC SQL SELECT name, vendor, model, os
869 INTO :oldname, :vendor, :model, :os
870 FROM machine WHERE mach_id = :id;
875 /* Sanity check name, vendor, model, and os. */
876 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
877 !hostname_check(argv[row]))
879 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
880 !hostinfo_check(argv[row + 1], 0))
882 if ((row == 0 || strcasecmp(argv[3], model)) &&
883 !hostinfo_check(argv[row + 2], 1))
885 if ((row == 0 || strcasecmp(argv[4], os)) &&
886 !hostinfo_check(argv[row + 3], 0))
889 /* check for duplicate name */
891 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
892 WHERE name = UPPER(:name);
899 if (!strcmp(argv[9 + row], "unassigned"))
901 else if (!strcmp(argv[9 + row], "unique"))
903 if (*(int *)argv[8 + row] == 0)
910 value = ntohl(inet_addr(argv[9 + row]));
919 * an address or unique was specified.
921 id = *(int *)argv[8 + row];
922 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
923 :shigh, :slow FROM subnet WHERE snet_id = :id;
926 saddr = (unsigned) ssaddr;
927 mask = (unsigned) smask;
928 high = (unsigned) shigh;
929 low = (unsigned) slow;
933 * someone specified an IP address for the host record
935 if ((value & mask) != saddr || value < low || value > high)
938 * run the address argument through inet_addr(). This
939 * has the effect that any out of bounds host addrs will
940 * be converted to a valid host addr. We do this now
941 * so that the uniqueness check works. We should also
942 * link in an inet_addr() that returns an error for
945 addr.s_addr = inet_addr(argv[9 + row]);
946 name = inet_ntoa(addr);
947 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
948 WHERE address = :name;
954 * make IP address is unique. If this a modify request
955 * (row == 1), then we expect one record to exist.
957 if (row == 0 || (row == 1 && cnt > 1))
959 if (row == 1 && cnt == 1)
961 EXEC SQL SELECT mach_id INTO :id FROM machine
962 WHERE address = :name;
963 if (id != *(int *)argv[0])
971 * a "unique" address was specified. Walk through the
972 * range specified in the network record, return
973 * error if no room left.
975 for (id = low; id <= high; id++)
977 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
979 addr.s_addr = htonl(id);
980 name = inet_ntoa(addr);
981 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
982 WHERE address = :name;
994 * we have an address in value. Convert it to a string and store it.
996 addr.s_addr = htonl(value);
997 strcpy(argv[9 + row], inet_ntoa(addr));
1000 strcpy(argv[9 + row], "unassigned");
1002 /* status checking */
1003 value = atoi(argv[7 + row]);
1004 if (row == 0 && !(value == 1 || value == 0))
1008 id = *(int *)argv[0];
1009 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1014 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1015 WHERE mach_id = :id;
1020 * If this is an update_host query, we're done.
1026 * For an add_host query, allocate and fill in a new machine id,
1027 * and then insert the creator id.
1029 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1032 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1040 int setup_ahal(struct query *q, char **argv, client *cl)
1042 EXEC SQL BEGIN DECLARE SECTION;
1045 EXEC SQL END DECLARE SECTION;
1049 if (!hostname_check(argv[0]))
1052 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1053 name = UPPER(:name);
1062 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1065 int setup_uhha(struct query *q, char **argv, client *cl)
1067 EXEC SQL BEGIN DECLARE SECTION;
1068 char *hwaddr = argv[1];
1070 EXEC SQL END DECLARE SECTION;
1073 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1075 for (p = hwaddr; *p; p++)
1082 if (p != hwaddr + 12)
1085 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1086 FROM machine WHERE hwaddr = :hwaddr;
1088 return MR_NOT_UNIQUE;
1094 /* setup_aprn(): Make sure name/duplexname don't conflict with
1095 * anything. If [ANY] was specified for the spooling host, pick the
1096 * least loaded print server that serves this kind of printer.
1098 int setup_aprn(struct query *q, char **argv, client *cl)
1102 EXEC SQL BEGIN DECLARE SECTION;
1103 int mid, usage, count;
1104 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1105 EXEC SQL END DECLARE SECTION;
1107 /* Check for aprn or uprn. */
1108 if (q->type == APPEND)
1113 name = argv[PRN_NAME + row];
1114 duplexname = argv[PRN_DUPLEXNAME + row];
1121 if (q->type == APPEND)
1123 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1124 WHERE name = :name OR duplexname = :name;
1128 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1129 WHERE ( name = :name OR duplexname = :name )
1130 AND name != :oldname;
1135 return MR_NOT_UNIQUE;
1140 if (q->type == APPEND)
1142 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1143 WHERE name = :duplexname OR duplexname = :duplexname;
1147 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1148 WHERE ( name = :duplexname OR duplexname = :duplexname )
1149 AND name != :oldname;
1155 return MR_NOT_UNIQUE;
1158 if (!strcmp(name, duplexname))
1159 return MR_NOT_UNIQUE;
1161 mid = *(int *)argv[PRN_RM + row];
1164 EXEC SQL DECLARE csr_rm CURSOR FOR
1165 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1167 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1169 AND ps.printer_types = s.string_id;
1172 EXEC SQL OPEN csr_rm;
1178 EXEC SQL FETCH csr_rm INTO :mid, :types;
1182 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1184 if (!strcasecmp(argv[PRN_TYPE + row], p))
1186 EXEC SQL SELECT COUNT(name) INTO :usage
1187 FROM printers WHERE rm = :mid;
1189 if (best < 0 || usage < best)
1192 *(int *)argv[PRN_RM + row] = mid;
1198 EXEC SQL CLOSE csr_rm;
1207 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1208 WHERE mach_id = :mid;
1216 int setup_dpsv(struct query *q, char **argv, client *cl)
1219 EXEC SQL BEGIN DECLARE SECTION;
1221 EXEC SQL END DECLARE SECTION;
1223 id = *(int *)argv[0];
1225 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1234 * validate the rfc1035/rfc1123-ness of a hostname
1237 int hostname_check(char *name)
1242 /* Sanity check name: must contain only letters, numerals, and
1243 * hyphen, and not start or end with a hyphen. Also make sure no
1244 * label (the thing the .s seperate) is longer than 63 characters,
1248 for (p = name, count = 0; *p; p++)
1251 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1252 (*p == '-' && p[1] == '.'))
1263 if (*(p - 1) == '-')
1268 int hostinfo_check(char *info, int num)
1275 /* Sanity check host hostinfo: must start with a letter (or number
1276 * if num is true), contain only letters, numerals, and hyphen, and
1277 * not end with a hyphen.
1280 if (!isalpha(*info) && (!num || !isdigit(*info)))
1282 for (p = info; *p; p++)
1284 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1285 (*p == '-' && p[1] == '.'))
1288 if (!isalnum(*(p - 1)))