6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
13 static char *rcsid_qsupport_dc = "$Header$";
16 #include <mit-copyright.h>
17 #include "mr_server.h"
20 #include <arpa/inet.h>
21 EXEC SQL INCLUDE sqlca;
24 extern char *whoami, *strsave();
25 extern int dbms_errno, mr_errcode;
27 EXEC SQL BEGIN DECLARE SECTION;
28 extern char stmt_buf[];
29 EXEC SQL END DECLARE SECTION;
31 EXEC SQL WHENEVER SQLERROR DO dbmserr();
34 int prefetch_value(struct query *q, char **argv, client *cl);
35 int check_nfs(int mach_idx, char *name, char *access);
39 /* Setup routine for add_user
41 * Inputs: argv[0] - login
46 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
47 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
50 int setup_ausr(q, argv, cl)
56 EXEC SQL BEGIN DECLARE SECTION;
58 EXEC SQL END DECLARE SECTION;
60 if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
64 if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1) {
65 if ((err=set_next_object_id("unix_uid", USERS_TABLE, 1)))
67 EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'unix_uid';
68 if (sqlca.sqlerrd[2] != 1)
70 sprintf(argv[row], "%d", nuid);
73 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1) {
74 sprintf(argv[0], "#%s", argv[row]);
77 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
84 /* setup_dusr - verify that the user is no longer being referenced
85 * and may safely be deleted.
88 int setup_dusr(q, argv)
92 EXEC SQL BEGIN DECLARE SECTION;
94 EXEC SQL END DECLARE SECTION;
98 /* For now, only allow users to be deleted if their status is 0 */
99 EXEC SQL SELECT status INTO :flag FROM users
100 WHERE users_id = :id;
101 if (flag != 0 && flag != 4)
104 EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type='USER';
105 EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
106 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
107 WHERE member_id = :id AND member_type = 'USER';
110 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
114 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
115 WHERE acl_id = :id AND acl_type = 'USER';
118 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
119 WHERE acl_id = :id AND acl_type = 'USER';
122 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
123 WHERE acl_id = :id AND acl_type = 'USER';
132 /* setup_spop: verify that there is already a valid POP machine_id in the
133 * pop_id field. Also take care of keeping track of the post office usage.
135 int setup_spop(q, argv)
139 EXEC SQL BEGIN DECLARE SECTION;
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(q, argv)
165 EXEC SQL BEGIN DECLARE SECTION;
168 EXEC SQL END DECLARE SECTION;
170 user = *(int *)argv[0];
171 EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
172 WHERE users_id = :user;
173 if (dbms_errno) return(mr_errcode);
175 if (!strcmp(strtrim(type), "POP"))
176 set_pop_usage(id, -1);
181 /* setup_dmac - verify that the machine is no longer being referenced
182 * and may safely be deleted.
185 int setup_dmac(q, argv)
189 EXEC SQL BEGIN DECLARE SECTION;
191 EXEC SQL END DECLARE SECTION;
193 id = *(int *)argv[0];
195 EXEC SQL SELECT status INTO :flag FROM machine
199 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
200 WHERE potype='POP' AND pop_id = :id;
203 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
207 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
211 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
215 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printcap
219 EXEC SQL SELECT COUNT(quotaserver) INTO :cnt FROM printcap
220 WHERE quotaserver = :id;
223 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM palladium
228 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
229 if (dbms_errno) return(mr_errcode);
234 /* setup_dsnt - verify that the subnet is no longer being referenced
235 * and may safely be deleted.
238 int setup_dsnt(q, argv)
242 EXEC SQL BEGIN DECLARE SECTION;
244 EXEC SQL END DECLARE SECTION;
246 id = *(int *)argv[0];
247 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
255 /* setup_dclu - verify that the cluster is no longer being referenced
256 * and may safely be deleted.
259 int setup_dclu(q, argv)
263 EXEC SQL BEGIN DECLARE SECTION;
265 EXEC SQL END DECLARE SECTION;
267 id = *(int *)argv[0];
268 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
272 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
282 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
283 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
284 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
285 * a -1 there. Remember that this is also used for ulis, with the indexes
286 * at 6 & 7. Also check that the list name does not contain uppercase
287 * characters, control characters, @, or :.
290 static int badlistchars[] = {
291 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
292 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
293 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
294 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
295 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
296 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, /* P - _ */
297 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
298 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
299 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
300 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
309 int setup_alis(q, argv, cl)
314 EXEC SQL BEGIN DECLARE SECTION;
316 EXEC SQL END DECLARE SECTION;
320 if (!strcmp(q->shortname, "alis"))
322 else if (!strcmp(q->shortname, "ulis"))
325 for (p = (unsigned char *) argv[idx]; *p; p++)
326 if (badlistchars[*p])
329 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1) {
330 if (atoi(argv[5 + idx])) {
331 if ((err=set_next_object_id("gid", LIST_TABLE, 1)))
333 EXEC SQL SELECT value INTO :ngid FROM numvalues
335 if (dbms_errno) return(mr_errcode);
336 sprintf(argv[6 + idx], "%d", ngid);
338 strcpy(argv[6 + idx], "-1");
342 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
349 /* setup_dlis - verify that the list is no longer being referenced
350 * and may safely be deleted.
353 int setup_dlis(q, argv)
358 EXEC SQL BEGIN DECLARE SECTION;
360 EXEC SQL END DECLARE SECTION;
362 id = *(int *)argv[0];
364 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
365 WHERE member_id = :id AND member_type='LIST';
366 if(cnt>0) return MR_IN_USE;
368 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
369 WHERE member_id = :id AND member_type='LIST';
370 if(cnt>0) return MR_IN_USE;
372 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
374 if(cnt>0) return MR_IN_USE;
376 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
377 if(cnt>0) return MR_IN_USE;
379 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
380 if(cnt>0) return MR_IN_USE;
382 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
383 WHERE acl_id = :id AND acl_type='LIST' AND list_id != :id;
384 if(cnt>0) return MR_IN_USE;
386 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
387 WHERE acl_id = :id AND acl_type='LIST';
388 if(cnt>0) return MR_IN_USE;
390 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
391 WHERE entity_id = :id AND type='GROUP';
392 if(cnt>0) return MR_IN_USE;
394 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
395 WHERE acl_id = :id AND acl_type='LIST';
396 if(cnt>0) return MR_IN_USE;
398 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
399 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
400 OR z.sub_type = 'LIST' AND z.sub_id = :id
401 OR z.iws_type = 'LIST' AND z.iws_id = :id
402 OR z.iui_type = 'LIST' AND z.iui_id = :id;
403 if(cnt>0) return MR_IN_USE;
409 /* setup_dsin - verify that the service is no longer being referenced
410 * and may safely be deleted.
413 int setup_dsin(q, argv)
417 EXEC SQL BEGIN DECLARE SECTION;
420 EXEC SQL END DECLARE SECTION;
423 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
424 WHERE service = UPPER(:svrname);
425 if(cnt>0) return MR_IN_USE;
427 EXEC SQL SELECT inprogress INTO :ec FROM servers
428 WHERE name=UPPER(:svrname);
438 /* setup_dshi - verify that the service-host is no longer being referenced
439 * and may safely be deleted.
442 int setup_dshi(q, argv)
446 EXEC SQL BEGIN DECLARE SECTION;
449 EXEC SQL END DECLARE SECTION;
452 id = *(int *)argv[1];
454 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
455 WHERE service=UPPER(:svrname) AND mach_id = :id;
467 ** setup_add_filesys - verify existance of referenced file systems
473 ** argv[5] - rwaccess
479 ** * extract directory prefix from name
480 ** * verify mach_id/dir in nfsphys
481 ** * verify rwaccess in {r, w, R, W}
483 ** Side effect: sets variable _var_phys_id to the ID of the physical
484 ** filesystem (nfsphys_id for NFS, 0 for RVD)
487 ** MR_NFS - specified directory not exported
488 ** MR_FILESYS_ACCESS - invalid filesys access
492 EXEC SQL BEGIN DECLARE SECTION;
494 EXEC SQL END DECLARE SECTION;
496 int setup_afil(q, argv, cl)
503 EXEC SQL BEGIN DECLARE SECTION;
505 char ftype[32], *rwaccess;
506 EXEC SQL END DECLARE SECTION;
509 mach_id = *(int *)argv[2];
514 sprintf(ftype, "fs_access_%s", type);
515 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
516 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
517 if (dbms_errno) return(mr_errcode);
518 if (ok == 0) return(MR_FILESYS_ACCESS);
520 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
523 if (!strcmp(type, "NFS"))
524 return (check_nfs(mach_id, name, rwaccess));
530 /* Verify the arguments, depending on the FStype. Also, if this is an
531 * NFS filesystem, then update any quotas for that filesystem to reflect
535 int setup_ufil(q, argv, cl)
542 EXEC SQL BEGIN DECLARE SECTION;
543 int fid, total, who, ok;
544 char *entity, ftype[32], *access;
545 short int total_null;
546 EXEC SQL END DECLARE SECTION;
550 mach_id = *(int *)argv[3];
553 fid = *(int *)argv[0];
557 sprintf(ftype, "fs_access_%s", type);
558 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
559 WHERE name = :ftype AND type='TYPE' AND trans = :access;
560 if (dbms_errno) return(mr_errcode);
561 if (ok == 0) return(MR_FILESYS_ACCESS);
563 EXEC SQL SELECT type INTO :ftype FROM filesys
564 WHERE filsys_id = :fid;
565 if (dbms_errno) return(mr_errcode);
567 if (!strcmp(type, "NFS")) {
568 status = check_nfs(mach_id, name, access);
569 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
570 WHERE filsys_id = :fid;
571 if (dbms_errno) return(mr_errcode);
573 } else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")) {
575 EXEC SQL DELETE FROM quota
576 WHERE type = 'ANY' AND filsys_id = :fid;
577 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
578 WHERE filsys_id = :fid AND phys_id != 0;
579 if (dbms_errno) return(mr_errcode);
580 if (!total_null && (total != 0)) {
582 * append quota (quota = total, filsys_id = fid,
583 * phys_id = 0, entity_id = 0, type = "ANY",
584 * modtime = "now", modby = who, modwith = entity)
586 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
587 type, modtime, modby, modwith)
588 VALUES (:total, :fid, 0, 0,
589 'ANY', SYSDATE, :who, :entity) ;
590 if (dbms_errno) return(mr_errcode);
593 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
594 if (dbms_errno) return(mr_errcode);
600 /* Find the NFS physical partition that the named directory is on.
601 * This is done by comparing the dir against the mount point of the
602 * partition. To make sure we get the correct match when there is
603 * more than one, we sort the query in reverse order by dir name.
606 int check_nfs(mach_id, name, access)
607 EXEC SQL BEGIN DECLARE SECTION;
609 EXEC SQL END DECLARE SECTION;
612 EXEC SQL BEGIN DECLARE SECTION;
614 EXEC SQL END DECLARE SECTION;
620 EXEC SQL DECLARE csr101 CURSOR FOR
621 SELECT nfsphys_id, dir FROM nfsphys
622 WHERE mach_id = :mach_id
626 EXEC SQL OPEN csr101;
630 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
631 if(sqlca.sqlcode != 0) break;
635 if (*cp1++ != *cp2) break;
643 EXEC SQL CLOSE csr101;
650 /* setup_dfil: free any quota records and fsgroup info associated with
651 * a filesystem when it is deleted. Also adjust the allocation numbers.
654 int setup_dfil(q, argv, cl)
659 EXEC SQL BEGIN DECLARE SECTION;
660 int id, total, phys_id;
662 EXEC SQL END DECLARE SECTION;
664 id = *(int *)argv[0];
665 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
666 WHERE filsys_id = :id;
670 /** What if there are multiple phys_id's per f/s? (bad data) **/
671 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
672 WHERE filsys_id = :id;
673 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
674 WHERE nfsphys_id = :phys_id;
677 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
679 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
680 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
681 if (dbms_errno) return(mr_errcode);
686 /* setup_dnfp: check to see that the nfs physical partition does not have
687 * any filesystems assigned to it before allowing it to be deleted.
690 int setup_dnfp(q, argv, cl)
695 EXEC SQL BEGIN DECLARE SECTION;
698 EXEC SQL END DECLARE SECTION;
700 id = *(int *)argv[0];
702 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
703 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
704 AND np.mach_id = :id AND np.dir = :dir;
713 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
714 * argv[0] = filsys_id
715 * argv[1] = type if "update_quota" or "delete_quota"
716 * argv[2 or 1] = users_id or list_id
719 int setup_dqot(q, argv, cl)
724 EXEC SQL BEGIN DECLARE SECTION;
725 int quota, fs, id, physid;
727 EXEC SQL END DECLARE SECTION;
729 fs = *(int *)argv[0];
730 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
732 id = *(int *)argv[2];
735 id = *(int *)argv[1];
738 EXEC SQL SELECT quota INTO :quota FROM quota
739 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
740 EXEC SQL SELECT phys_id INTO :physid FROM filesys
741 WHERE filsys_id = :fs;
742 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
743 WHERE nfsphys_id = :physid;
745 if (dbms_errno) return(mr_errcode);
750 /* setup add_kerberos_user_mapping: add the string to the string
751 * table if necessary.
754 int setup_akum(q, argv, cl)
759 EXEC SQL BEGIN DECLARE SECTION;
762 EXEC SQL END DECLARE SECTION;
765 if (name_to_id(name, STRINGS_TABLE, &id) != MR_SUCCESS) {
766 if (q->type != APPEND) return(MR_STRING);
768 cache_entry(name, STRINGS_TABLE, id);
770 if (dbms_errno) return(mr_errcode);
771 *(int *)argv[1] = id;
777 * This routine fetches an appropriate value from the numvalues table.
778 * It is a little hack to get around the fact that SQL doesn't let you
779 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
781 * It is called from the query table as (*v->pre_rtn)(q,Argv,cl) or
782 * from within a setup_...() routine with the appropriate arguments.
784 * Correct functioning of this routine may depend on the assumption
785 * that this query is an APPEND.
788 int prefetch_value(q, argv, 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;
809 if(dbms_errno) return(mr_errcode);
810 if(sqlca.sqlerrd[2] != 1) return(MR_INTERNAL);
812 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
813 sprintf(argv[argc],"%d",value); /** Could save this step by changing tlist from %s to %d **/
818 /* prefetch_filesys():
819 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
820 * Appends the filsys_id and the phys_id to the argv so they can be
821 * referenced in an INSERT into a table other than filesys. Also
822 * see comments at prefetch_value().
824 * Assumes the existence of a row where filsys_id = argv[0], since a
825 * filesys label has already been resolved to a filsys_id.
827 int prefetch_filesys(q, argv, cl)
832 EXEC SQL BEGIN DECLARE SECTION;
834 EXEC SQL END DECLARE SECTION;
837 fid = *(int *)argv[0];
838 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
839 if(dbms_errno) return(mr_errcode);
841 argc=q->argc+q->vcnt;
842 sprintf(argv[argc++],"%d",phid);
843 sprintf(argv[argc],"%d",fid);
852 int setup_ahst(q, argv, cl)
857 EXEC SQL BEGIN DECLARE SECTION;
859 int value, id, saddr, mask, high, low, cnt;
860 EXEC SQL END DECLARE SECTION;
863 extern int host_access_level, privileged;
865 if (!strcmp(q->shortname, "uhst"))
870 /* sanity check name: must start with a letter, contain only
871 * letters, numerals, and hyphen, and not end with a hyphen.
873 if (row == 0 || strcmp(argv[1], cl->args->mr_argv[1])) {
876 if (!isalpha(*p)) return(MR_BAD_CHAR);
878 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
879 (*p == '-' && p[1] == '.'))
882 if (*(p-1) == '-') return(MR_BAD_CHAR);
885 /* sanity check host vendor: must start with a letter, contain only
886 * letters, numerals, and hyphen, and end with an alphanumeric.
888 if (*argv[row+1] && (row == 0 || strcmp(argv[2], cl->args->mr_argv[2]))) {
889 char *p = argv[row+1];
891 if (!isalpha(*p)) return(MR_BAD_CHAR);
893 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
894 (*p == '-' && p[1] == '.'))
897 if (!isalnum(*(p-1))) return(MR_BAD_CHAR);
900 /* sanity check host type: must start with a letter, contain only
901 * letters, numerals, and hyphen, and end with an alphanumeric.
903 if (*argv[row+2] && (row == 0 || strcmp(argv[3], cl->args->mr_argv[3]))) {
904 char *p = argv[row+2];
906 if (!isalnum(*p)) return(MR_BAD_CHAR);
908 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
909 (*p == '-' && p[1] == '.'))
912 if (!isalnum(*(p-1))) return(MR_BAD_CHAR);
915 /* sanity check host vendor: must start with a letter, contain only
916 * letters, numerals, and hyphen, and end with an hyphen alphanumeric.
918 if (*argv[row+3] && (row == 0 || strcmp(argv[4], cl->args->mr_argv[4]))) {
919 char *p = argv[row+3];
921 if (!isalpha(*p)) return(MR_BAD_CHAR);
923 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
924 (*p == '-' && p[1] == '.'))
927 if (!isalnum(*(p-1))) return(MR_BAD_CHAR);
930 /* check for duplicate name */
932 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
934 if (dbms_errno) return(mr_errcode);
935 if (cnt != 0) return(MR_EXISTS);
938 if (!strcmp(argv[9+row], "unassigned"))
940 else if (!strcmp(argv[9+row], "unique")) {
941 if (*(int *)argv[8+row] == 0)
946 value = ntohl(inet_addr(argv[9+row]));
947 if (value == -1) return(MR_ADDRESS);
949 if (value == 0) return(MR_ADDRESS);
952 * an address or unique was specified.
954 id = *(int *)argv[8+row];
955 EXEC SQL SELECT saddr, mask, high, low INTO :saddr, :mask, :high, :low
956 FROM subnet WHERE snet_id = :id;
957 if (dbms_errno) return(mr_errcode);
960 * someone specified an IP address for the host record
962 if ((value & mask) != saddr) return(MR_ADDRESS);
964 * run the address argument through inet_addr(). This
965 * has the effect that any out of bounds host addrs will
966 * be converted to a valid host addr. We do this now
967 * so that the uniqueness check works. We should also
968 * link in an inet_addr() that returns an error for
971 addr.s_addr=inet_addr(argv[9+row]);
972 name = inet_ntoa(addr);
973 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
974 WHERE address = :name;
975 if (dbms_errno) return(mr_errcode);
978 * make IP address is unique. If this a modify request
979 * (row == 1), then we expect one record to exist.
981 if (row == 0 || row == 1 && cnt > 1) return(MR_ADDRESS);
982 if (row == 1 && cnt == 1) {
983 EXEC SQL SELECT mach_id INTO :id FROM machine
984 WHERE address = :name;
985 if (id != *(int *)argv[0]) return(MR_ADDRESS);
990 * a "unique" address was specified. Walk through the
991 * range specified in the network record, return
992 * error if no room left.
994 for (id = low; id <= high; id++) {
995 if (((id & 0xff) == 0) ||
996 ((id & 0xff) == 255))
998 addr.s_addr = htonl(id);
999 name = (char *)inet_ntoa(addr);
1000 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1001 WHERE address = :name;
1002 if (dbms_errno) return(mr_errcode);
1003 if (cnt == 0) break;
1011 * we have an address in value. Convert it to a string and store it.
1013 addr.s_addr = htonl(value);
1014 strcpy(argv[9+row], inet_ntoa(addr));
1016 strcpy(argv[9+row], "unassigned");
1019 /* status checking */
1020 value = atoi(argv[7+row]);
1021 if (row == 0 && !(value == 1 || value == 0))
1024 id = *(int *)argv[0];
1025 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1026 if (dbms_errno) return(mr_errcode);
1028 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1029 WHERE mach_id = :id;
1033 if (row == 0 && !privileged) {
1034 /* subnet owner is adding a host */
1035 /* Non-query owner must set use to zero */
1036 if (atoi(argv[6]) != 0) return(MR_PERM);
1037 } else if (row == 1 && !privileged) {
1038 EXEC SQL BEGIN DECLARE SECTION;
1039 int i8, i12, i13, i7, i9, i14;
1040 char s6[33], s10[33], s11[9];
1041 EXEC SQL END DECLARE SECTION;
1042 /* Non-query owner is restricted in changes that can be made */
1043 id = *(int *)argv[0];
1044 EXEC SQL SELECT contact, status, address, owner_type, owner_id,
1045 acomment, use, snet_id, ocomment INTO :s6, :i8, :s10, :s11,
1046 :i12, :i13, :i7, :i9, :i14 FROM machine WHERE mach_id = :id;
1047 if (dbms_errno) return(mr_errcode);
1048 /* subnet owner cannot change use, comment, or network */
1049 if ((i7 != atoi(argv[7])) || (i14 != *(int *)argv[14]) ||
1050 (i9 != *(int *)argv[9]))
1052 /* host owner cannot change contact, status, address, owner_type,
1053 * owner_id, acomment, or subnet */
1054 if (host_access_level == 2 &&
1055 (strcmp(argv[6], strtrim(s6)) || (i8 != atoi(argv[8])) ||
1056 strcmp(argv[10], strtrim(s10)) ||strcmp(argv[11], strtrim(s11)) ||
1057 (i12 != *(int *)argv[12]) || (i13 != *(int *)argv[13]) ||
1058 (i9 != *(int *)argv[9])))
1063 * If this is an update_host query, we're done.
1069 * For an add_host query, allocate and fill in a new machine id,
1070 * and then insert the creator id.
1072 if ((mr_errcode = prefetch_value(q,argv,cl)) != MR_SUCCESS)
1075 sprintf(argv[q->argc + q->vcnt + 1], "%d",cl->client_id);
1083 int setup_ahal(q, argv, cl)
1088 EXEC SQL BEGIN DECLARE SECTION;
1091 EXEC SQL END DECLARE SECTION;
1095 if (!isalpha(*p)) return(MR_BAD_CHAR);
1097 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1098 (*p == '-' && p[1] == '.'))
1099 return(MR_BAD_CHAR);
1101 if (*(p-1) == '-') return(MR_BAD_CHAR);
1103 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1105 if (dbms_errno) return(mr_errcode);
1106 if (cnt > 0) return(MR_EXISTS);