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
227 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
232 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
233 if (dbms_errno) return(mr_errcode);
238 /* setup_dsnt - verify that the subnet is no longer being referenced
239 * and may safely be deleted.
242 int setup_dsnt(q, argv)
246 EXEC SQL BEGIN DECLARE SECTION;
248 EXEC SQL END DECLARE SECTION;
250 id = *(int *)argv[0];
251 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
259 /* setup_dclu - verify that the cluster is no longer being referenced
260 * and may safely be deleted.
263 int setup_dclu(q, argv)
267 EXEC SQL BEGIN DECLARE SECTION;
269 EXEC SQL END DECLARE SECTION;
271 id = *(int *)argv[0];
272 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
276 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
286 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
287 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
288 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
289 * a -1 there. Remember that this is also used for ulis, with the indexes
290 * at 6 & 7. Also check that the list name does not contain uppercase
291 * characters, control characters, @, or :.
294 static int badlistchars[] = {
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, 1, 1, /* ^P - ^_ */
297 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
298 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
299 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
300 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, /* P - _ */
301 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
302 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
303 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
304 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
305 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
306 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
307 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
308 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
309 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
310 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
313 int setup_alis(q, argv, cl)
318 EXEC SQL BEGIN DECLARE SECTION;
320 EXEC SQL END DECLARE SECTION;
324 if (!strcmp(q->shortname, "alis"))
326 else if (!strcmp(q->shortname, "ulis"))
329 for (p = (unsigned char *) argv[idx]; *p; p++)
330 if (badlistchars[*p])
333 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1) {
334 if (atoi(argv[5 + idx])) {
335 if ((err=set_next_object_id("gid", LIST_TABLE, 1)))
337 EXEC SQL SELECT value INTO :ngid FROM numvalues
339 if (dbms_errno) return(mr_errcode);
340 sprintf(argv[6 + idx], "%d", ngid);
342 strcpy(argv[6 + idx], "-1");
346 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
353 /* setup_dlis - verify that the list is no longer being referenced
354 * and may safely be deleted.
357 int setup_dlis(q, argv)
362 EXEC SQL BEGIN DECLARE SECTION;
364 EXEC SQL END DECLARE SECTION;
366 id = *(int *)argv[0];
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
373 WHERE member_id = :id AND member_type='LIST';
374 if(cnt>0) return MR_IN_USE;
376 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
378 if(cnt>0) return MR_IN_USE;
380 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
381 if(cnt>0) return MR_IN_USE;
383 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
384 if(cnt>0) return MR_IN_USE;
386 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
387 WHERE acl_id = :id AND acl_type='LIST' AND list_id != :id;
388 if(cnt>0) return MR_IN_USE;
390 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
391 WHERE acl_id = :id AND acl_type='LIST';
392 if(cnt>0) return MR_IN_USE;
394 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
395 WHERE entity_id = :id AND type='GROUP';
396 if(cnt>0) return MR_IN_USE;
398 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
399 WHERE acl_id = :id AND acl_type='LIST';
400 if(cnt>0) return MR_IN_USE;
402 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
403 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
404 OR z.sub_type = 'LIST' AND z.sub_id = :id
405 OR z.iws_type = 'LIST' AND z.iws_id = :id
406 OR z.iui_type = 'LIST' AND z.iui_id = :id;
407 if(cnt>0) return MR_IN_USE;
413 /* setup_dsin - verify that the service is no longer being referenced
414 * and may safely be deleted.
417 int setup_dsin(q, argv)
421 EXEC SQL BEGIN DECLARE SECTION;
424 EXEC SQL END DECLARE SECTION;
427 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
428 WHERE service = UPPER(:svrname);
429 if(cnt>0) return MR_IN_USE;
431 EXEC SQL SELECT inprogress INTO :ec FROM servers
432 WHERE name=UPPER(:svrname);
442 /* setup_dshi - verify that the service-host is no longer being referenced
443 * and may safely be deleted.
446 int setup_dshi(q, argv)
450 EXEC SQL BEGIN DECLARE SECTION;
453 EXEC SQL END DECLARE SECTION;
456 id = *(int *)argv[1];
458 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
459 WHERE service=UPPER(:svrname) AND mach_id = :id;
471 ** setup_add_filesys - verify existance of referenced file systems
477 ** argv[5] - rwaccess
483 ** * extract directory prefix from name
484 ** * verify mach_id/dir in nfsphys
485 ** * verify rwaccess in {r, w, R, W}
487 ** Side effect: sets variable _var_phys_id to the ID of the physical
488 ** filesystem (nfsphys_id for NFS, 0 for RVD)
491 ** MR_NFS - specified directory not exported
492 ** MR_FILESYS_ACCESS - invalid filesys access
496 EXEC SQL BEGIN DECLARE SECTION;
498 EXEC SQL END DECLARE SECTION;
500 int setup_afil(q, argv, cl)
507 EXEC SQL BEGIN DECLARE SECTION;
509 char ftype[32], *rwaccess;
510 EXEC SQL END DECLARE SECTION;
513 mach_id = *(int *)argv[2];
518 sprintf(ftype, "fs_access_%s", type);
519 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
520 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
521 if (dbms_errno) return(mr_errcode);
522 if (ok == 0) return(MR_FILESYS_ACCESS);
524 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
527 if (!strcmp(type, "NFS"))
528 return (check_nfs(mach_id, name, rwaccess));
534 /* Verify the arguments, depending on the FStype. Also, if this is an
535 * NFS filesystem, then update any quotas for that filesystem to reflect
539 int setup_ufil(q, argv, cl)
546 EXEC SQL BEGIN DECLARE SECTION;
547 int fid, total, who, ok;
548 char *entity, ftype[32], *access;
549 short int total_null;
550 EXEC SQL END DECLARE SECTION;
554 mach_id = *(int *)argv[3];
557 fid = *(int *)argv[0];
561 sprintf(ftype, "fs_access_%s", type);
562 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
563 WHERE name = :ftype AND type='TYPE' AND trans = :access;
564 if (dbms_errno) return(mr_errcode);
565 if (ok == 0) return(MR_FILESYS_ACCESS);
567 EXEC SQL SELECT type INTO :ftype FROM filesys
568 WHERE filsys_id = :fid;
569 if (dbms_errno) return(mr_errcode);
571 if (!strcmp(type, "NFS")) {
572 status = check_nfs(mach_id, name, access);
573 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
574 WHERE filsys_id = :fid;
575 if (dbms_errno) return(mr_errcode);
577 } else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")) {
579 EXEC SQL DELETE FROM quota
580 WHERE type = 'ANY' AND filsys_id = :fid;
581 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
582 WHERE filsys_id = :fid AND phys_id != 0;
583 if (dbms_errno) return(mr_errcode);
584 if (!total_null && (total != 0)) {
586 * append quota (quota = total, filsys_id = fid,
587 * phys_id = 0, entity_id = 0, type = "ANY",
588 * modtime = "now", modby = who, modwith = entity)
590 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
591 type, modtime, modby, modwith)
592 VALUES (:total, :fid, 0, 0,
593 'ANY', SYSDATE, :who, :entity) ;
594 if (dbms_errno) return(mr_errcode);
597 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
598 if (dbms_errno) return(mr_errcode);
604 /* Find the NFS physical partition that the named directory is on.
605 * This is done by comparing the dir against the mount point of the
606 * partition. To make sure we get the correct match when there is
607 * more than one, we sort the query in reverse order by dir name.
610 int check_nfs(mach_id, name, access)
611 EXEC SQL BEGIN DECLARE SECTION;
613 EXEC SQL END DECLARE SECTION;
616 EXEC SQL BEGIN DECLARE SECTION;
618 EXEC SQL END DECLARE SECTION;
624 EXEC SQL DECLARE csr101 CURSOR FOR
625 SELECT nfsphys_id, dir FROM nfsphys
626 WHERE mach_id = :mach_id
630 EXEC SQL OPEN csr101;
634 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
635 if(sqlca.sqlcode != 0) break;
639 if (*cp1++ != *cp2) break;
647 EXEC SQL CLOSE csr101;
654 /* setup_dfil: free any quota records and fsgroup info associated with
655 * a filesystem when it is deleted. Also adjust the allocation numbers.
658 int setup_dfil(q, argv, cl)
663 EXEC SQL BEGIN DECLARE SECTION;
664 int id, total, phys_id;
666 EXEC SQL END DECLARE SECTION;
668 id = *(int *)argv[0];
669 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
670 WHERE filsys_id = :id;
674 /** What if there are multiple phys_id's per f/s? (bad data) **/
675 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
676 WHERE filsys_id = :id;
677 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
678 WHERE nfsphys_id = :phys_id;
681 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
683 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
684 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
685 if (dbms_errno) return(mr_errcode);
690 /* setup_dnfp: check to see that the nfs physical partition does not have
691 * any filesystems assigned to it before allowing it to be deleted.
694 int setup_dnfp(q, argv, cl)
699 EXEC SQL BEGIN DECLARE SECTION;
702 EXEC SQL END DECLARE SECTION;
704 id = *(int *)argv[0];
706 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
707 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
708 AND np.mach_id = :id AND np.dir = :dir;
717 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
718 * argv[0] = filsys_id
719 * argv[1] = type if "update_quota" or "delete_quota"
720 * argv[2 or 1] = users_id or list_id
723 int setup_dqot(q, argv, cl)
728 EXEC SQL BEGIN DECLARE SECTION;
729 int quota, fs, id, physid;
731 EXEC SQL END DECLARE SECTION;
733 fs = *(int *)argv[0];
734 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
736 id = *(int *)argv[2];
739 id = *(int *)argv[1];
742 EXEC SQL SELECT quota INTO :quota FROM quota
743 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
744 EXEC SQL SELECT phys_id INTO :physid FROM filesys
745 WHERE filsys_id = :fs;
746 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
747 WHERE nfsphys_id = :physid;
749 if (dbms_errno) return(mr_errcode);
754 /* setup add_kerberos_user_mapping: add the string to the string
755 * table if necessary.
758 int setup_akum(q, argv, cl)
763 EXEC SQL BEGIN DECLARE SECTION;
766 EXEC SQL END DECLARE SECTION;
769 if (name_to_id(name, STRINGS_TABLE, &id) != MR_SUCCESS) {
770 if (q->type != APPEND) return(MR_STRING);
772 cache_entry(name, STRINGS_TABLE, id);
774 if (dbms_errno) return(mr_errcode);
775 *(int *)argv[1] = id;
781 * This routine fetches an appropriate value from the numvalues table.
782 * It is a little hack to get around the fact that SQL doesn't let you
783 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
785 * It is called from the query table as (*v->pre_rtn)(q,Argv,cl) or
786 * from within a setup_...() routine with the appropriate arguments.
788 * Correct functioning of this routine may depend on the assumption
789 * that this query is an APPEND.
792 int prefetch_value(q, argv, cl)
797 EXEC SQL BEGIN DECLARE SECTION;
798 char *name = q->validate->object_id;
800 EXEC SQL END DECLARE SECTION;
801 int status, limit, argc;
803 /* set next object id, limiting it if necessary */
804 if(!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
805 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
808 if((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
811 /* fetch object id */
812 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name=:name;
813 if(dbms_errno) return(mr_errcode);
814 if(sqlca.sqlerrd[2] != 1) return(MR_INTERNAL);
816 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
817 sprintf(argv[argc],"%d",value); /** Could save this step by changing tlist from %s to %d **/
822 /* prefetch_filesys():
823 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
824 * Appends the filsys_id and the phys_id to the argv so they can be
825 * referenced in an INSERT into a table other than filesys. Also
826 * see comments at prefetch_value().
828 * Assumes the existence of a row where filsys_id = argv[0], since a
829 * filesys label has already been resolved to a filsys_id.
831 int prefetch_filesys(q, argv, cl)
836 EXEC SQL BEGIN DECLARE SECTION;
838 EXEC SQL END DECLARE SECTION;
841 fid = *(int *)argv[0];
842 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
843 if(dbms_errno) return(mr_errcode);
845 argc=q->argc+q->vcnt;
846 sprintf(argv[argc++],"%d",phid);
847 sprintf(argv[argc],"%d",fid);
856 int setup_ahst(q, argv, cl)
861 EXEC SQL BEGIN DECLARE SECTION;
863 int value, id, saddr, mask, high, low, cnt;
864 EXEC SQL END DECLARE SECTION;
867 extern int host_access_level, privileged;
869 if (!strcmp(q->shortname, "uhst"))
874 /* sanity check name: must start with a letter, contain only
875 * letters, numerals, and hyphen, and not end with a hyphen.
877 if (row == 0 || strcmp(argv[1], cl->args->mr_argv[1])) {
880 if (!isalpha(*p)) return(MR_BAD_CHAR);
882 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
883 (*p == '-' && p[1] == '.'))
886 if (*(p-1) == '-') return(MR_BAD_CHAR);
889 /* sanity check host vendor: must start with a letter, contain only
890 * letters, numerals, and hyphen, and end with an alphanumeric.
892 if (*argv[row+1] && (row == 0 || strcmp(argv[2], cl->args->mr_argv[2]))) {
893 char *p = argv[row+1];
895 if (!isalpha(*p)) return(MR_BAD_CHAR);
897 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
898 (*p == '-' && p[1] == '.'))
901 if (!isalnum(*(p-1))) return(MR_BAD_CHAR);
904 /* sanity check host type: must start with a letter, contain only
905 * letters, numerals, and hyphen, and end with an alphanumeric.
907 if (*argv[row+2] && (row == 0 || strcmp(argv[3], cl->args->mr_argv[3]))) {
908 char *p = argv[row+2];
910 if (!isalnum(*p)) return(MR_BAD_CHAR);
912 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
913 (*p == '-' && p[1] == '.'))
916 if (!isalnum(*(p-1))) return(MR_BAD_CHAR);
919 /* sanity check host vendor: must start with a letter, contain only
920 * letters, numerals, and hyphen, and end with an hyphen alphanumeric.
922 if (*argv[row+3] && (row == 0 || strcmp(argv[4], cl->args->mr_argv[4]))) {
923 char *p = argv[row+3];
925 if (!isalpha(*p)) return(MR_BAD_CHAR);
927 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
928 (*p == '-' && p[1] == '.'))
931 if (!isalnum(*(p-1))) return(MR_BAD_CHAR);
934 /* check for duplicate name */
936 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
938 if (dbms_errno) return(mr_errcode);
939 if (cnt != 0) return(MR_EXISTS);
942 if (!strcmp(argv[9+row], "unassigned"))
944 else if (!strcmp(argv[9+row], "unique")) {
945 if (*(int *)argv[8+row] == 0)
950 value = ntohl(inet_addr(argv[9+row]));
951 if (value == -1) return(MR_ADDRESS);
953 if (value == 0) return(MR_ADDRESS);
956 * an address or unique was specified.
958 id = *(int *)argv[8+row];
959 EXEC SQL SELECT saddr, mask, high, low INTO :saddr, :mask, :high, :low
960 FROM subnet WHERE snet_id = :id;
961 if (dbms_errno) return(mr_errcode);
964 * someone specified an IP address for the host record
966 if ((value & mask) != saddr) return(MR_ADDRESS);
968 * run the address argument through inet_addr(). This
969 * has the effect that any out of bounds host addrs will
970 * be converted to a valid host addr. We do this now
971 * so that the uniqueness check works. We should also
972 * link in an inet_addr() that returns an error for
975 addr.s_addr=inet_addr(argv[9+row]);
976 name = inet_ntoa(addr);
977 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
978 WHERE address = :name;
979 if (dbms_errno) return(mr_errcode);
982 * make IP address is unique. If this a modify request
983 * (row == 1), then we expect one record to exist.
985 if (row == 0 || row == 1 && cnt > 1) return(MR_ADDRESS);
986 if (row == 1 && cnt == 1) {
987 EXEC SQL SELECT mach_id INTO :id FROM machine
988 WHERE address = :name;
989 if (id != *(int *)argv[0]) return(MR_ADDRESS);
994 * a "unique" address was specified. Walk through the
995 * range specified in the network record, return
996 * error if no room left.
998 for (id = low; id <= high; id++) {
999 if (((id & 0xff) == 0) ||
1000 ((id & 0xff) == 255))
1002 addr.s_addr = htonl(id);
1003 name = (char *)inet_ntoa(addr);
1004 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1005 WHERE address = :name;
1006 if (dbms_errno) return(mr_errcode);
1007 if (cnt == 0) break;
1015 * we have an address in value. Convert it to a string and store it.
1017 addr.s_addr = htonl(value);
1018 strcpy(argv[9+row], inet_ntoa(addr));
1020 strcpy(argv[9+row], "unassigned");
1023 /* status checking */
1024 value = atoi(argv[7+row]);
1025 if (row == 0 && !(value == 1 || value == 0))
1028 id = *(int *)argv[0];
1029 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1030 if (dbms_errno) return(mr_errcode);
1032 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1033 WHERE mach_id = :id;
1037 if (row == 0 && !privileged) {
1038 /* subnet owner is adding a host */
1039 /* Non-query owner must set use to zero */
1040 if (atoi(argv[6]) != 0) return(MR_PERM);
1041 } else if (row == 1 && !privileged) {
1042 EXEC SQL BEGIN DECLARE SECTION;
1043 int i8, i12, i13, i7, i9, i14;
1044 char s6[33], s10[33], s11[9];
1045 EXEC SQL END DECLARE SECTION;
1046 /* Non-query owner is restricted in changes that can be made */
1047 id = *(int *)argv[0];
1048 EXEC SQL SELECT contact, status, address, owner_type, owner_id,
1049 acomment, use, snet_id, ocomment INTO :s6, :i8, :s10, :s11,
1050 :i12, :i13, :i7, :i9, :i14 FROM machine WHERE mach_id = :id;
1051 if (dbms_errno) return(mr_errcode);
1052 /* subnet owner cannot change use, comment, or network */
1053 if ((i7 != atoi(argv[7])) || (i14 != *(int *)argv[14]) ||
1054 (i9 != *(int *)argv[9]))
1056 /* host owner cannot change contact, status, address, owner_type,
1057 * owner_id, acomment, or subnet */
1058 if (host_access_level == 2 &&
1059 (strcmp(argv[6], strtrim(s6)) || (i8 != atoi(argv[8])) ||
1060 strcmp(argv[10], strtrim(s10)) ||strcmp(argv[11], strtrim(s11)) ||
1061 (i12 != *(int *)argv[12]) || (i13 != *(int *)argv[13]) ||
1062 (i9 != *(int *)argv[9])))
1067 * If this is an update_host query, we're done.
1073 * For an add_host query, allocate and fill in a new machine id,
1074 * and then insert the creator id.
1076 if ((mr_errcode = prefetch_value(q,argv,cl)) != MR_SUCCESS)
1079 sprintf(argv[q->argc + q->vcnt + 1], "%d",cl->client_id);
1087 int setup_ahal(q, argv, cl)
1092 EXEC SQL BEGIN DECLARE SECTION;
1095 EXEC SQL END DECLARE SECTION;
1099 if (!isalpha(*p)) return(MR_BAD_CHAR);
1101 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1102 (*p == '-' && p[1] == '.'))
1103 return(MR_BAD_CHAR);
1105 if (*(p-1) == '-') return(MR_BAD_CHAR);
1107 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1109 if (dbms_errno) return(mr_errcode);
1110 if (cnt > 0) return(MR_EXISTS);