5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
10 #include <mit-copyright.h>
11 #include "mr_server.h"
15 #include <arpa/inet.h>
16 #include <netinet/in.h>
22 EXEC SQL INCLUDE sqlca;
27 extern int dbms_errno, mr_errcode;
29 EXEC SQL BEGIN DECLARE SECTION;
30 extern char stmt_buf[];
31 EXEC SQL END DECLARE SECTION;
33 EXEC SQL WHENEVER SQLERROR DO dbmserr();
35 int hostname_check(char *name);
36 int hostinfo_check(char *name, int num);
37 int prefetch_value(struct query *q, char **argv, client *cl);
38 int check_nfs(int mach_idx, char *name, char *access);
42 /* Setup routine for add_user
44 * Inputs: argv[0] - login
49 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
50 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
53 int setup_ausr(struct query *q, char *argv[], client *cl)
56 EXEC SQL BEGIN DECLARE SECTION;
58 EXEC SQL END DECLARE SECTION;
60 if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
67 if (strlen(argv[row + 3]) + strlen(argv[row + 4]) +
68 strlen(argv[row + 5]) + 2 > USERS_FULLNAME_SIZE)
69 return MR_ARG_TOO_LONG;
73 if (strlen(argv[row + 2]) + strlen(argv[row + 3]) +
74 strlen(argv[row + 4]) + 2 > USERS_FULLNAME_SIZE)
75 return MR_ARG_TOO_LONG;
78 if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1)
80 if ((err = set_next_object_id("unix_uid", USERS_TABLE, 1)))
82 EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'unix_uid';
83 if (sqlca.sqlerrd[2] != 1)
85 sprintf(argv[row], "%d", nuid);
88 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1)
89 sprintf(argv[0], "#%s", argv[row]);
91 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
98 /* setup_dusr - verify that the user is no longer being referenced
99 * and may safely be deleted.
102 int setup_dusr(struct query *q, char *argv[], client *cl)
104 EXEC SQL BEGIN DECLARE SECTION;
106 char resv[USERS_RESERVATIONS_SIZE];
107 EXEC SQL END DECLARE SECTION;
109 id = *(int *)argv[0];
111 /* For now, only allow users to be deleted if their status is 0
112 * and we have no reservations about deleting them.
114 EXEC SQL SELECT status, reservations INTO :flag, :resv
115 FROM users WHERE users_id = :id;
116 if ((flag != 0 && flag != 4) || *resv)
119 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
120 WHERE member_id = :id AND member_type = 'USER';
123 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
127 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
128 WHERE acl_id = :id AND acl_type = 'USER';
131 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
132 WHERE acl_id = :id AND acl_type = 'USER';
135 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
136 WHERE acl_id = :id AND acl_type = 'USER';
142 EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
143 EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
148 /* setup_dpob: Take care of keeping track of the post office usage.
150 int setup_dpob(struct query *q, char *argv[], client *cl)
152 EXEC SQL BEGIN DECLARE SECTION;
154 char type[USERS_POTYPE_SIZE];
155 EXEC SQL END DECLARE SECTION;
157 user = *(int *)argv[0];
158 EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
159 WHERE users_id = :user;
163 if (!strcmp(strtrim(type), "POP"))
164 set_pop_usage(id, -1);
169 /* setup_dmac - verify that the machine is no longer being referenced
170 * and may safely be deleted.
173 int setup_dmac(struct query *q, char *argv[], client *cl)
175 EXEC SQL BEGIN DECLARE SECTION;
177 EXEC SQL END DECLARE SECTION;
179 id = *(int *)argv[0];
181 EXEC SQL SELECT status INTO :flag FROM machine
185 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
186 WHERE potype = 'POP' AND pop_id = :id;
189 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
193 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
197 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
201 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
205 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
209 EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
213 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
217 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
222 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
226 EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id;
232 /* setup_asnt - verify that the data entered for the subnet is sane.
233 * In particular, make sure that the "low" and "high" addresses are
234 * correctly ordered, i.e., high > low.
237 int setup_asnt(struct query *q, char *argv[], client *cl)
239 int high, low, row, status;
240 char *account_number;
242 /* Check for asnt or usnt. */
243 if (q->type == APPEND)
248 low = atoi(argv[row + 7]);
249 high = atoi(argv[row + 8]);
250 status = atoi(argv[row + 2]);
251 account_number = argv[row + 4];
253 /* Don't allow Private subnets to be created without a valid billing
256 if (status == SNET_STATUS_PRIVATE_10MBPS ||
257 status == SNET_STATUS_PRIVATE_100MBPS)
259 EXEC SQL SELECT account_number FROM accountnumbers
260 WHERE account_number = :account_number;
261 if (sqlca.sqlcode == SQL_NO_MATCH)
262 return MR_ACCOUNT_NUMBER;
265 /* Special case 0.0.0.0 and 255.255.255.255 */
266 if (!(low == 0 || low == -1 || high == 0 || high == -1))
270 /* If this is update_subnet, we're done. */
274 /* For an add_subnet query, allocate and fill in a new snet_id */
275 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
281 /* setup_dsnt - verify that the subnet is no longer being referenced
282 * and may safely be deleted.
285 int setup_dsnt(struct query *q, char *argv[], client *cl)
287 EXEC SQL BEGIN DECLARE SECTION;
289 EXEC SQL END DECLARE SECTION;
291 id = *(int *)argv[0];
292 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
300 /* setup_dclu - verify that the cluster is no longer being referenced
301 * and may safely be deleted.
304 int setup_dclu(struct query *q, char *argv[], client *cl)
306 EXEC SQL BEGIN DECLARE SECTION;
308 EXEC SQL END DECLARE SECTION;
310 id = *(int *)argv[0];
311 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
315 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
325 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
326 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
327 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
328 * a -1 there. Remember that this is also used for ulis, with the indexes
329 * at 6 & 7. Also check that the list name does not contain uppercase
330 * characters, control characters, @, or :.
332 * Newlines in list descriptions do bad things to the aliases file
333 * moira generates, so make sure the description doesn't contain any, too.
336 static int badlistchars[] = {
337 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
338 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
339 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
340 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
341 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
342 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
343 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
344 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
345 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
346 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
347 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
348 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
349 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
350 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
351 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
355 int setup_alis(struct query *q, char *argv[], client *cl)
357 EXEC SQL BEGIN DECLARE SECTION;
360 EXEC SQL END DECLARE SECTION;
364 if (!strcmp(q->shortname, "alis"))
366 else if (!strcmp(q->shortname, "ulis"))
371 desc = argv[9 + idx];
372 else if (q->version == 3)
373 desc = argv[10 + idx];
374 else if (q->version >= 4)
375 desc = argv[12 + idx];
379 EXEC SQL BEGIN DECLARE SECTION;
380 int lid = *(int *)argv[0];
381 EXEC SQL END DECLARE SECTION;
383 if (acl_access_check(lid, cl))
387 for (p = (unsigned char *) name; *p; p++)
389 if (badlistchars[*p])
393 for (p = (unsigned char *) desc; *p; p++)
399 /* Check that it doesn't conflict with a pre-existing weirdly-cased
401 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
402 WHERE LOWER(name) = :name AND name != :name;
406 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
408 if (atoi(argv[5 + idx]))
410 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
412 EXEC SQL SELECT value INTO :ngid FROM numvalues
416 sprintf(argv[6 + idx], "%d", ngid);
419 strcpy(argv[6 + idx], "-1");
422 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
429 /* setup_dlis - verify that the list is no longer being referenced
430 * and may safely be deleted.
433 int setup_dlis(struct query *q, char *argv[], client *cl)
436 EXEC SQL BEGIN DECLARE SECTION;
438 EXEC SQL END DECLARE SECTION;
440 id = *(int *)argv[0];
442 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
443 WHERE member_id = :id AND member_type = 'LIST';
447 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
448 WHERE member_id = :id AND member_type = 'LIST';
452 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
457 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
461 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
465 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
466 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
470 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
471 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
475 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
476 WHERE acl_id = :id AND acl_type = 'LIST';
480 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
481 WHERE entity_id = :id AND type = 'GROUP';
485 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
486 WHERE acl_id = :id AND acl_type = 'LIST';
490 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
491 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
492 OR z.sub_type = 'LIST' AND z.sub_id = :id
493 OR z.iws_type = 'LIST' AND z.iws_id = :id
494 OR z.iui_type = 'LIST' AND z.iui_id = :id
495 OR z.owner_type = 'LIST' and z.owner_id = :id;
499 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
500 WHERE lpc_acl = :id OR ac = :id;
504 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
505 WHERE owner_type = 'LIST' AND owner_id = :id
510 EXEC SQL SELECT count(name) INTO :cnt FROM containers
511 WHERE acl_id = :id AND acl_type = 'LIST';
515 EXEC SQL SELECT count(name) INTO :cnt FROM containers
516 WHERE memacl_id = :id AND memacl_type = 'LIST';
524 /* setup_dsin - verify that the service is no longer being referenced
525 * and may safely be deleted.
528 int setup_dsin(struct query *q, char *argv[], client *cl)
530 EXEC SQL BEGIN DECLARE SECTION;
533 EXEC SQL END DECLARE SECTION;
536 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
537 WHERE service = UPPER(:svrname);
541 EXEC SQL SELECT inprogress INTO :ec FROM servers
542 WHERE name = UPPER(:svrname);
552 /* setup_dshi - verify that the service-host is no longer being referenced
553 * and may safely be deleted.
556 int setup_dshi(struct query *q, char *argv[], client *cl)
558 EXEC SQL BEGIN DECLARE SECTION;
561 EXEC SQL END DECLARE SECTION;
564 id = *(int *)argv[1];
566 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
567 WHERE service = UPPER(:svrname) AND mach_id = :id;
578 ** setup_add_filesys - verify existance of referenced file systems
584 ** argv[5] - rwaccess
589 ** - for type = NFS/IMAP:
590 ** * extract directory prefix from name
591 ** * verify mach_id/dir in nfsphys
592 ** * verify rwaccess in {r, w, R, W}
594 ** Side effect: sets variable _var_phys_id to the ID of the physical
595 ** filesystem (nfsphys_id for NFS, 0 for RVD)
598 ** MR_NFS - specified directory not exported
599 ** MR_FILESYS_ACCESS - invalid filesys access
603 EXEC SQL BEGIN DECLARE SECTION;
605 EXEC SQL END DECLARE SECTION;
607 int setup_afil(struct query *q, char *argv[], client *cl)
611 EXEC SQL BEGIN DECLARE SECTION;
613 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
614 EXEC SQL END DECLARE SECTION;
617 mach_id = *(int *)argv[2];
622 sprintf(ftype, "fs_access_%s", type);
623 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
624 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
628 return MR_FILESYS_ACCESS;
630 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
633 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
634 return check_nfs(mach_id, name, rwaccess);
640 /* Verify the arguments, depending on the FStype. Also, if this is an
641 * NFS filesystem, then update any quotas for that filesystem to reflect
645 int setup_ufil(struct query *q, char *argv[], client *cl)
649 EXEC SQL BEGIN DECLARE SECTION;
650 int fid, total, who, ok;
651 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
652 short int total_null;
653 EXEC SQL END DECLARE SECTION;
657 mach_id = *(int *)argv[3];
660 fid = *(int *)argv[0];
664 sprintf(ftype, "fs_access_%s", type);
665 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
666 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
670 return MR_FILESYS_ACCESS;
672 EXEC SQL SELECT type INTO :ftype FROM filesys
673 WHERE filsys_id = :fid;
677 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
679 status = check_nfs(mach_id, name, access);
680 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
681 WHERE filsys_id = :fid;
686 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
687 && strcmp(strtrim(ftype), "ERR"))
690 EXEC SQL DELETE FROM quota
691 WHERE type = 'ANY' AND filsys_id = :fid;
692 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
693 WHERE filsys_id = :fid AND phys_id != 0;
696 if (!total_null && (total != 0))
698 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
699 type, modtime, modby, modwith)
700 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
707 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
715 /* Find the NFS physical partition that the named directory is on.
716 * This is done by comparing the dir against the mount point of the
717 * partition. To make sure we get the correct match when there is
718 * more than one, we sort the query in reverse order by dir name.
721 int check_nfs(int mach_id, char *name, char *access)
723 EXEC SQL BEGIN DECLARE SECTION;
724 char dir[NFSPHYS_DIR_SIZE];
726 EXEC SQL END DECLARE SECTION;
732 EXEC SQL DECLARE csr101 CURSOR FOR
733 SELECT nfsphys_id, dir FROM nfsphys
738 EXEC SQL OPEN csr101;
743 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
760 EXEC SQL CLOSE csr101;
767 /* setup_dfil: free any quota records and fsgroup info associated with
768 * a filesystem when it is deleted. Also adjust the allocation numbers.
771 int setup_dfil(struct query *q, char **argv, client *cl)
773 EXEC SQL BEGIN DECLARE SECTION;
774 int id, total, phys_id;
776 EXEC SQL END DECLARE SECTION;
778 id = *(int *)argv[0];
779 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
780 WHERE filsys_id = :id;
785 /** What if there are multiple phys_id's per f/s? (bad data) **/
786 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
787 WHERE filsys_id = :id;
788 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
789 WHERE nfsphys_id = :phys_id;
792 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
793 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
794 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
801 /* setup_dnfp: check to see that the nfs physical partition does not have
802 * any filesystems assigned to it before allowing it to be deleted.
805 int setup_dnfp(struct query *q, char **argv, client *cl)
807 EXEC SQL BEGIN DECLARE SECTION;
810 EXEC SQL END DECLARE SECTION;
812 id = *(int *)argv[0];
814 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
815 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
816 AND np.mach_id = :id AND np.dir = :dir;
825 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
826 * argv[0] = filsys_id
827 * argv[1] = type if "update_quota" or "delete_quota"
828 * argv[2 or 1] = users_id or list_id
831 int setup_dqot(struct query *q, char **argv, client *cl)
833 EXEC SQL BEGIN DECLARE SECTION;
834 int quota, fs, id, physid;
836 EXEC SQL END DECLARE SECTION;
838 fs = *(int *)argv[0];
839 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
842 id = *(int *)argv[2];
847 id = *(int *)argv[1];
850 EXEC SQL SELECT quota INTO :quota FROM quota
851 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
852 EXEC SQL SELECT phys_id INTO :physid FROM filesys
853 WHERE filsys_id = :fs;
854 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
855 WHERE nfsphys_id = :physid;
864 * This routine fetches an appropriate value from the numvalues table.
865 * It is a little hack to get around the fact that SQL doesn't let you
866 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
868 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
869 * from within a setup_...() routine with the appropriate arguments.
871 * Correct functioning of this routine may depend on the assumption
872 * that this query is an APPEND.
875 int prefetch_value(struct query *q, char **argv, client *cl)
877 EXEC SQL BEGIN DECLARE SECTION;
878 char *name = q->validate->object_id;
880 EXEC SQL END DECLARE SECTION;
881 int status, limit, argc;
883 /* set next object id, limiting it if necessary */
884 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
885 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
888 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
891 /* fetch object id */
892 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
895 if (sqlca.sqlerrd[2] != 1)
898 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
899 sprintf(argv[argc], "%d", value);
904 /* prefetch_filesys():
905 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
906 * Appends the filsys_id and the phys_id to the argv so they can be
907 * referenced in an INSERT into a table other than filesys. Also
908 * see comments at prefetch_value().
910 * Assumes the existence of a row where filsys_id = argv[0], since a
911 * filesys label has already been resolved to a filsys_id.
913 int prefetch_filesys(struct query *q, char **argv, client *cl)
915 EXEC SQL BEGIN DECLARE SECTION;
917 EXEC SQL END DECLARE SECTION;
920 fid = *(int *)argv[0];
921 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
925 argc = q->argc + q->vcnt;
926 sprintf(argv[argc++], "%d", phid);
927 sprintf(argv[argc], "%d", fid);
936 int setup_ahst(struct query *q, char **argv, client *cl)
938 EXEC SQL BEGIN DECLARE SECTION;
939 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
940 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
941 int value, id, ssaddr, smask, shigh, slow, cnt;
942 unsigned int saddr, mask, high, low;
943 EXEC SQL END DECLARE SECTION;
947 id = *(int *)argv[0];
949 if (!strcmp(q->shortname, "uhst"))
952 EXEC SQL SELECT name, vendor, model, os
953 INTO :oldname, :vendor, :model, :os
954 FROM machine WHERE mach_id = :id;
961 else if (q->version >= 6 && q->version < 8)
966 /* Sanity check name, vendor, model, and os. */
967 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
968 !hostname_check(argv[row]))
970 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
971 !hostinfo_check(argv[row + 1], 0))
973 if ((row == 0 || strcasecmp(argv[3], model)) &&
974 !hostinfo_check(argv[row + 2], 1))
976 if ((row == 0 || strcasecmp(argv[4], os)) &&
977 !hostinfo_check(argv[row + 3], 0))
980 /* check for duplicate name */
982 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
983 WHERE name = UPPER(:name);
990 if (!strcmp(argv[9 + row + idx], "unassigned"))
992 else if (!strcmp(argv[9 + row + idx], "unique"))
994 if (*(int *)argv[8 + row + idx] == 0)
1001 value = ntohl(inet_addr(argv[9 + row + idx]));
1010 * an address or unique was specified.
1012 id = *(int *)argv[8 + row + idx];
1013 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1014 :shigh, :slow FROM subnet WHERE snet_id = :id;
1017 saddr = (unsigned) ssaddr;
1018 mask = (unsigned) smask;
1019 high = (unsigned) shigh;
1020 low = (unsigned) slow;
1024 * someone specified an IP address for the host record
1026 if ((value & mask) != saddr || value < low || value > high)
1029 * run the address argument through inet_addr(). This
1030 * has the effect that any out of bounds host addrs will
1031 * be converted to a valid host addr. We do this now
1032 * so that the uniqueness check works. We should also
1033 * link in an inet_addr() that returns an error for
1036 addr.s_addr = inet_addr(argv[9 + row + idx]);
1037 name = inet_ntoa(addr);
1038 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1039 WHERE address = :name;
1045 * make IP address is unique. If this a modify request
1046 * (row == 1), then we expect one record to exist.
1048 if (row == 0 || (row == 1 && cnt > 1))
1050 if (row == 1 && cnt == 1)
1052 EXEC SQL SELECT mach_id INTO :id FROM machine
1053 WHERE address = :name;
1054 if (id != *(int *)argv[0])
1062 * a "unique" address was specified. Walk through the
1063 * range specified in the network record, return
1064 * error if no room left.
1066 for (id = low; id <= high; id++)
1068 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1070 addr.s_addr = htonl(id);
1071 name = inet_ntoa(addr);
1072 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1073 WHERE address = :name;
1085 * we have an address in value. Convert it to a string and store it.
1087 addr.s_addr = htonl(value);
1088 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1091 strcpy(argv[9 + row + idx], "unassigned");
1093 /* status checking */
1094 value = atoi(argv[7 + row + idx]);
1095 if (row == 0 && !(value == 1 || value == 0))
1099 id = *(int *)argv[0];
1100 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1105 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1106 WHERE mach_id = :id;
1111 * If this is an update_host query, we're done.
1117 * For an add_host query, allocate and fill in a new machine id,
1118 * and then insert the creator id.
1120 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1123 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1131 int setup_ahal(struct query *q, char **argv, client *cl)
1133 EXEC SQL BEGIN DECLARE SECTION;
1136 EXEC SQL END DECLARE SECTION;
1140 if (!hostname_check(argv[0]))
1143 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1144 name = UPPER(:name);
1153 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1156 int setup_uhha(struct query *q, char **argv, client *cl)
1158 EXEC SQL BEGIN DECLARE SECTION;
1159 char *hwaddr = argv[1];
1161 EXEC SQL END DECLARE SECTION;
1164 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1166 for (p = hwaddr; *p; p++)
1173 if (p != hwaddr + 12)
1176 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1177 FROM machine WHERE hwaddr = :hwaddr;
1179 return MR_NOT_UNIQUE;
1185 /* setup_aprn(): Make sure name/duplexname don't conflict with
1186 * anything. If [ANY] was specified for the spooling host, pick the
1187 * least loaded print server that serves this kind of printer.
1189 int setup_aprn(struct query *q, char **argv, client *cl)
1193 EXEC SQL BEGIN DECLARE SECTION;
1194 int mid, usage, count;
1195 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1196 EXEC SQL END DECLARE SECTION;
1198 /* Check for aprn or uprn. */
1199 if (q->type == APPEND)
1204 name = argv[PRN_NAME + row];
1205 duplexname = argv[PRN_DUPLEXNAME + row];
1212 if (q->type == APPEND)
1214 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1215 WHERE name = :name OR duplexname = :name;
1219 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1220 WHERE ( name = :name OR duplexname = :name )
1221 AND name != :oldname;
1226 return MR_NOT_UNIQUE;
1231 if (q->type == APPEND)
1233 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1234 WHERE name = :duplexname OR duplexname = :duplexname;
1238 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1239 WHERE ( name = :duplexname OR duplexname = :duplexname )
1240 AND name != :oldname;
1246 return MR_NOT_UNIQUE;
1249 if (!strcmp(name, duplexname))
1250 return MR_NOT_UNIQUE;
1252 mid = *(int *)argv[PRN_RM + row];
1255 EXEC SQL DECLARE csr_rm CURSOR FOR
1256 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1258 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1260 AND ps.printer_types = s.string_id;
1263 EXEC SQL OPEN csr_rm;
1269 EXEC SQL FETCH csr_rm INTO :mid, :types;
1273 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1275 if (!strcasecmp(argv[PRN_TYPE + row], p))
1277 EXEC SQL SELECT COUNT(name) INTO :usage
1278 FROM printers WHERE rm = :mid;
1280 if (best < 0 || usage < best)
1283 *(int *)argv[PRN_RM + row] = mid;
1289 EXEC SQL CLOSE csr_rm;
1298 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1299 WHERE mach_id = :mid;
1307 int setup_dpsv(struct query *q, char **argv, client *cl)
1310 EXEC SQL BEGIN DECLARE SECTION;
1312 EXEC SQL END DECLARE SECTION;
1314 id = *(int *)argv[0];
1316 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1324 int setup_dcon(struct query *q, char *argv[], client *cl)
1326 EXEC SQL BEGIN DECLARE SECTION;
1328 char containername[CONTAINERS_NAME_SIZE];
1329 EXEC SQL END DECLARE SECTION;
1331 id = *(int *)argv[0];
1332 /* check to see if there are machines in this container */
1333 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1338 /* check to see if there are subcontainers in this container */
1340 /* get the container name */
1342 EXEC SQL SELECT name INTO :containername
1346 /* trim off the trailing spaces */
1347 strcpy(containername, strtrim(containername));
1349 EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1350 WHERE name LIKE :containername || '/' || '%';
1361 * validate the rfc1035/rfc1123-ness of a hostname
1364 int hostname_check(char *name)
1369 /* Sanity check name: must contain only letters, numerals, and
1370 * hyphen, and not start or end with a hyphen. Also make sure no
1371 * label (the thing the .s seperate) is longer than 63 characters,
1375 for (p = name, count = 0; *p; p++)
1378 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1379 (*p == '-' && p[1] == '.'))
1390 if (*(p - 1) == '-')
1395 int hostinfo_check(char *info, int num)
1402 /* Sanity check host hostinfo: must start with a letter (or number
1403 * if num is true), contain only letters, numerals, and hyphen, and
1404 * not end with a hyphen.
1407 if (!isalpha(*info) && (!num || !isdigit(*info)))
1409 for (p = info; *p; p++)
1411 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1412 (*p == '-' && p[1] == '.'))
1415 if (!isalnum(*(p - 1)))