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);
39 int check_mailman_listname(char *name, const char *suffix);
43 /* Setup routine for add_user
45 * Inputs: argv[0] - login
50 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
51 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
54 int setup_ausr(struct query *q, char *argv[], client *cl)
57 EXEC SQL BEGIN DECLARE SECTION;
59 EXEC SQL END DECLARE SECTION;
61 if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
68 if (strlen(argv[row + 3]) + strlen(argv[row + 4]) +
69 strlen(argv[row + 5]) + 2 > USERS_FULLNAME_SIZE)
70 return MR_ARG_TOO_LONG;
74 if (strlen(argv[row + 2]) + strlen(argv[row + 3]) +
75 strlen(argv[row + 4]) + 2 > USERS_FULLNAME_SIZE)
76 return MR_ARG_TOO_LONG;
81 /* For both winhomedir and winprofiledir, we allow values of the
84 * [AFS] - Magic token for AFS home directory.
85 * [LOCAL] - Magic token for AD default local values, i.e. C:\<mumble>
86 * UNC pathname - \\<something>
87 * local pathname - <drive letter>:<something>
90 if ((strcasecmp(argv[row + 12], "[AFS]")) &&
91 (strcasecmp(argv[row + 12], "[LOCAL]")) &&
92 (!(argv[row + 12][0] == '\\' && argv[row + 12][1] == '\\')) &&
93 (!(isalpha(*argv[row + 12]) && (argv[row + 12][1] == ':'))))
96 if ((strcasecmp(argv[row + 13], "[AFS]")) &&
97 (strcasecmp(argv[row + 13], "[LOCAL]")) &&
98 (!(argv[row + 13][0] == '\\' && argv[row + 13][1] == '\\')) &&
99 (!(isalpha(*argv[row + 13]) && (argv[row + 13][1] == ':'))))
103 if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1)
105 if ((err = set_next_object_id("unix_uid", USERS_TABLE, 1)))
107 EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'unix_uid';
108 if (sqlca.sqlerrd[2] != 1)
110 sprintf(argv[row], "%d", nuid);
113 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1)
114 sprintf(argv[0], "#%s", argv[row]);
116 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
119 /* If this is an UPDATE query, we're done. */
123 /* For an add query, we need to fill in the creator id. */
124 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
129 /* setup_dusr - verify that the user is no longer being referenced
130 * and may safely be deleted.
133 int setup_dusr(struct query *q, char *argv[], client *cl)
135 EXEC SQL BEGIN DECLARE SECTION;
137 char resv[USERS_RESERVATIONS_SIZE];
138 EXEC SQL END DECLARE SECTION;
140 id = *(int *)argv[0];
142 /* For now, only allow users to be deleted if their status is
143 * one of 0, 4, or 8 (the various registerable statuses)
144 * and we have no reservations about deleting them.
146 EXEC SQL SELECT status, reservations INTO :flag, :resv
147 FROM users WHERE users_id = :id;
148 if ((flag != 0 && flag != 4 && flag != 8) || *resv)
151 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
152 WHERE member_id = :id AND member_type = 'USER';
155 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
159 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
160 WHERE acl_id = :id AND acl_type = 'USER';
163 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
164 WHERE acl_id = :id AND acl_type = 'USER';
167 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
168 WHERE acl_id = :id AND acl_type = 'USER';
174 EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
175 EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
180 /* setup_dpob: Take care of keeping track of the post office usage.
182 int setup_dpob(struct query *q, char *argv[], client *cl)
184 EXEC SQL BEGIN DECLARE SECTION;
186 char type[USERS_POTYPE_SIZE];
187 EXEC SQL END DECLARE SECTION;
189 user = *(int *)argv[0];
190 EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
191 WHERE users_id = :user;
195 if (!strcmp(strtrim(type), "POP"))
196 set_pop_usage(id, -1);
201 /* setup_dmac - verify that the machine is no longer being referenced
202 * and may safely be deleted.
205 int setup_dmac(struct query *q, char *argv[], client *cl)
207 EXEC SQL BEGIN DECLARE SECTION;
209 EXEC SQL END DECLARE SECTION;
211 id = *(int *)argv[0];
213 EXEC SQL SELECT status INTO :flag FROM machine
217 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
218 WHERE potype = 'POP' AND pop_id = :id;
221 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
225 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
229 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
233 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
237 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
241 EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
245 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
249 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
253 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
254 WHERE member_type = 'MACHINE' and member_id = :id;
258 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
262 EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id;
268 /* setup_asnt - verify that the data entered for the subnet is sane.
269 * In particular, make sure that the "low" and "high" addresses are
270 * correctly ordered, i.e., high > low.
273 int setup_asnt(struct query *q, char *argv[], client *cl)
275 int high, low, row, status;
276 char *account_number;
278 /* Check for asnt or usnt. */
279 if (q->type == APPEND)
284 low = atoi(argv[row + 7]);
285 high = atoi(argv[row + 8]);
286 status = atoi(argv[row + 2]);
287 account_number = argv[row + 4];
289 /* Don't allow Private subnets to be created without a valid billing
292 if (status == SNET_STATUS_PRIVATE_10MBPS ||
293 status == SNET_STATUS_PRIVATE_100MBPS ||
294 status == SNET_STATUS_PRIVATE_1000MBPS)
296 EXEC SQL SELECT account_number FROM accountnumbers
297 WHERE account_number = :account_number;
298 if (sqlca.sqlcode == SQL_NO_MATCH)
299 return MR_ACCOUNT_NUMBER;
302 /* Special case 0.0.0.0 and 255.255.255.255 */
303 if (!(low == 0 || low == -1 || high == 0 || high == -1))
307 /* If this is update_subnet, we're done. */
311 /* For an add_subnet query, allocate and fill in a new snet_id */
312 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
318 /* setup_dsnt - verify that the subnet is no longer being referenced
319 * and may safely be deleted.
322 int setup_dsnt(struct query *q, char *argv[], client *cl)
324 EXEC SQL BEGIN DECLARE SECTION;
326 EXEC SQL END DECLARE SECTION;
328 id = *(int *)argv[0];
329 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
337 /* setup_dclu - verify that the cluster is no longer being referenced
338 * and may safely be deleted.
341 int setup_dclu(struct query *q, char *argv[], client *cl)
343 EXEC SQL BEGIN DECLARE SECTION;
345 EXEC SQL END DECLARE SECTION;
347 id = *(int *)argv[0];
348 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
352 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
362 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
363 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
364 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
365 * a -1 there. Remember that this is also used for ulis, with the indexes
366 * at 6 & 7. Also check that the list name does not contain uppercase
367 * characters, control characters, @, or :.
369 * Newlines in list descriptions do bad things to the aliases file
370 * moira generates, so make sure the description doesn't contain any, too.
373 static int badlistchars[] = {
374 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
375 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
376 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
378 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
379 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
380 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
382 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
383 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
384 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
385 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
386 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
387 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
388 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
389 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
392 static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
393 "-bounces", "-confirm", "-join",
394 "-leave", "-subscribe",
395 "-unsubscribe", NULL };
397 int setup_alis(struct query *q, char *argv[], client *cl)
399 EXEC SQL BEGIN DECLARE SECTION;
400 int ngid, cnt, mailman, mailman_id, lid;
402 EXEC SQL END DECLARE SECTION;
404 int idx, err, best = -1, usage, i;
406 if (!strcmp(q->shortname, "alis"))
408 else if (!strcmp(q->shortname, "ulis"))
413 desc = argv[9 + idx];
414 else if (q->version == 3)
415 desc = argv[10 + idx];
416 else if (q->version == 4)
417 desc = argv[12 + idx];
418 else if (q->version >= 10)
419 desc = argv[14 + idx];
423 lid = *(int *)argv[0];
425 if (acl_access_check(lid, cl))
429 for (p = (unsigned char *) name; *p; p++)
431 if (badlistchars[*p])
435 for (p = (unsigned char *) desc; *p; p++)
441 /* Check that it doesn't conflict with a pre-existing weirdly-cased
443 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
444 WHERE LOWER(name) = :name AND name != :name;
448 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
450 if (atoi(argv[5 + idx]))
452 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
454 EXEC SQL SELECT value INTO :ngid FROM numvalues
458 sprintf(argv[6 + idx], "%d", ngid);
461 strcpy(argv[6 + idx], "-1");
464 /* Don't let someone rename a list to one of the magic mailman names
465 * (foo-admin, etc) if foo already exists as a mailman list.
467 for (i = 0; mailman_suffixes[i]; i++)
469 if ((err = check_mailman_listname(name, mailman_suffixes[i]))
474 if (q->version >= 10)
476 /* Don't let them take this name for a mailman list if we can't
477 * reserve the -admin, -owner, and -request names.
479 if (atoi(argv[8 + idx]))
481 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
482 WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
483 name = :name || '-request');
488 /* Handle the [ANY] case for mailman server. */
489 mailman_id = *(int *)argv[9 + idx];
490 if (mailman_id == -1)
492 EXEC SQL DECLARE csr_mailman CURSOR FOR
493 SELECT mach_id FROM serverhosts WHERE service = 'MAILMAN'
497 EXEC SQL OPEN csr_mailman;
503 EXEC SQL FETCH csr_mailman INTO :mailman_id;
507 EXEC SQL SELECT COUNT(name) INTO :usage FROM list
508 WHERE mailman_id = :mailman_id;
510 if (best < 0 || usage < best)
513 *(int *)argv[9 + idx] = mailman_id;
517 EXEC SQL CLOSE csr_mailman;
527 /* Client too old to know about the mailman code.
528 * Use existing value of mailman boolean in the table.
529 * Don't do this for add_list from an old client, since the row
530 * they're creating won't exist yet, and there's no way for them to
531 * create a list with the mailman bit set, anyway.
535 EXEC SQL SELECT mailman INTO :mailman FROM list WHERE list_id = :lid;
538 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
539 WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
540 name = :name || '-request');
547 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
554 /* setup_dlis - verify that the list is no longer being referenced
555 * and may safely be deleted.
558 int setup_dlis(struct query *q, char *argv[], client *cl)
561 EXEC SQL BEGIN DECLARE SECTION;
563 EXEC SQL END DECLARE SECTION;
565 id = *(int *)argv[0];
567 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
568 WHERE member_id = :id AND member_type = 'LIST';
572 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
573 WHERE member_id = :id AND member_type = 'LIST';
577 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
582 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
586 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
590 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
591 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
595 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
596 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
600 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
601 WHERE acl_id = :id AND acl_type = 'LIST';
605 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
606 WHERE entity_id = :id AND type = 'GROUP';
610 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
611 WHERE acl_id = :id AND acl_type = 'LIST';
615 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
616 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
617 OR z.sub_type = 'LIST' AND z.sub_id = :id
618 OR z.iws_type = 'LIST' AND z.iws_id = :id
619 OR z.iui_type = 'LIST' AND z.iui_id = :id
620 OR z.owner_type = 'LIST' and z.owner_id = :id;
624 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
625 WHERE lpc_acl = :id OR ac = :id;
629 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
630 WHERE owner_type = 'LIST' AND owner_id = :id
635 EXEC SQL SELECT count(name) INTO :cnt FROM containers
636 WHERE acl_id = :id AND acl_type = 'LIST';
640 EXEC SQL SELECT count(name) INTO :cnt FROM containers
641 WHERE memacl_id = :id AND memacl_type = 'LIST';
649 /* setup_dsin - verify that the service is no longer being referenced
650 * and may safely be deleted.
653 int setup_dsin(struct query *q, char *argv[], client *cl)
655 EXEC SQL BEGIN DECLARE SECTION;
658 EXEC SQL END DECLARE SECTION;
661 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
662 WHERE service = UPPER(:svrname);
666 EXEC SQL SELECT inprogress INTO :ec FROM servers
667 WHERE name = UPPER(:svrname);
677 /* setup_dshi - verify that the service-host is no longer being referenced
678 * and may safely be deleted.
681 int setup_dshi(struct query *q, char *argv[], client *cl)
683 EXEC SQL BEGIN DECLARE SECTION;
686 EXEC SQL END DECLARE SECTION;
689 id = *(int *)argv[1];
691 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
692 WHERE service = UPPER(:svrname) AND mach_id = :id;
703 ** setup_add_filesys - verify existance of referenced file systems
709 ** argv[5] - rwaccess
714 ** - for type = NFS/IMAP:
715 ** * extract directory prefix from name
716 ** * verify mach_id/dir in nfsphys
717 ** * verify rwaccess in {r, w, R, W}
719 ** Side effect: sets variable _var_phys_id to the ID of the physical
720 ** filesystem (nfsphys_id for NFS, 0 for RVD)
723 ** MR_NFS - specified directory not exported
724 ** MR_FILESYS_ACCESS - invalid filesys access
728 EXEC SQL BEGIN DECLARE SECTION;
730 EXEC SQL END DECLARE SECTION;
732 int setup_afil(struct query *q, char *argv[], client *cl)
736 EXEC SQL BEGIN DECLARE SECTION;
738 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
739 EXEC SQL END DECLARE SECTION;
742 mach_id = *(int *)argv[2];
747 sprintf(ftype, "fs_access_%s", type);
748 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
749 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
753 return MR_FILESYS_ACCESS;
755 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
758 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
759 return check_nfs(mach_id, name, rwaccess);
765 /* Verify the arguments, depending on the FStype. Also, if this is an
766 * NFS filesystem, then update any quotas for that filesystem to reflect
770 int setup_ufil(struct query *q, char *argv[], client *cl)
774 EXEC SQL BEGIN DECLARE SECTION;
775 int fid, total, who, ok;
776 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
777 short int total_null;
778 EXEC SQL END DECLARE SECTION;
782 mach_id = *(int *)argv[3];
785 fid = *(int *)argv[0];
789 sprintf(ftype, "fs_access_%s", type);
790 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
791 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
795 return MR_FILESYS_ACCESS;
797 EXEC SQL SELECT type INTO :ftype FROM filesys
798 WHERE filsys_id = :fid;
802 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
804 status = check_nfs(mach_id, name, access);
805 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
806 WHERE filsys_id = :fid;
811 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
812 && strcmp(strtrim(ftype), "ERR"))
815 EXEC SQL DELETE FROM quota
816 WHERE type = 'ANY' AND filsys_id = :fid;
817 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
818 WHERE filsys_id = :fid AND phys_id != 0;
821 if (!total_null && (total != 0))
823 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
824 type, modtime, modby, modwith)
825 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
832 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
840 /* Find the NFS physical partition that the named directory is on.
841 * This is done by comparing the dir against the mount point of the
842 * partition. To make sure we get the correct match when there is
843 * more than one, we sort the query in reverse order by dir name.
846 int check_nfs(int mach_id, char *name, char *access)
848 EXEC SQL BEGIN DECLARE SECTION;
849 char dir[NFSPHYS_DIR_SIZE];
851 EXEC SQL END DECLARE SECTION;
857 EXEC SQL DECLARE csr101 CURSOR FOR
858 SELECT nfsphys_id, dir FROM nfsphys
863 EXEC SQL OPEN csr101;
868 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
885 EXEC SQL CLOSE csr101;
892 /* setup_dfil: free any quota records and fsgroup info associated with
893 * a filesystem when it is deleted. Also adjust the allocation numbers.
896 int setup_dfil(struct query *q, char **argv, client *cl)
898 EXEC SQL BEGIN DECLARE SECTION;
899 int id, total, phys_id;
901 EXEC SQL END DECLARE SECTION;
903 id = *(int *)argv[0];
904 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
905 WHERE filsys_id = :id;
910 /** What if there are multiple phys_id's per f/s? (bad data) **/
911 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
912 WHERE filsys_id = :id;
913 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
914 WHERE nfsphys_id = :phys_id;
917 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
918 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
919 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
926 /* setup_dnfp: check to see that the nfs physical partition does not have
927 * any filesystems assigned to it before allowing it to be deleted.
930 int setup_dnfp(struct query *q, char **argv, client *cl)
932 EXEC SQL BEGIN DECLARE SECTION;
935 EXEC SQL END DECLARE SECTION;
937 id = *(int *)argv[0];
939 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
940 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
941 AND np.mach_id = :id AND np.dir = :dir;
950 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
951 * argv[0] = filsys_id
952 * argv[1] = type if "update_quota" or "delete_quota"
953 * argv[2 or 1] = users_id or list_id
956 int setup_dqot(struct query *q, char **argv, client *cl)
958 EXEC SQL BEGIN DECLARE SECTION;
959 int quota, fs, id, physid;
961 EXEC SQL END DECLARE SECTION;
963 fs = *(int *)argv[0];
964 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
967 id = *(int *)argv[2];
972 id = *(int *)argv[1];
975 EXEC SQL SELECT quota INTO :quota FROM quota
976 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
977 EXEC SQL SELECT phys_id INTO :physid FROM filesys
978 WHERE filsys_id = :fs;
979 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
980 WHERE nfsphys_id = :physid;
989 * This routine fetches an appropriate value from the numvalues table.
990 * It is a little hack to get around the fact that SQL doesn't let you
991 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
993 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
994 * from within a setup_...() routine with the appropriate arguments.
996 * Correct functioning of this routine may depend on the assumption
997 * that this query is an APPEND.
1000 int prefetch_value(struct query *q, char **argv, client *cl)
1002 EXEC SQL BEGIN DECLARE SECTION;
1003 char *name = q->validate->object_id;
1005 EXEC SQL END DECLARE SECTION;
1006 int status, limit, argc;
1008 /* set next object id, limiting it if necessary */
1009 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
1010 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
1013 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
1016 /* fetch object id */
1017 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
1020 if (sqlca.sqlerrd[2] != 1)
1023 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
1024 sprintf(argv[argc], "%d", value);
1029 /* prefetch_filesys():
1030 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
1031 * Appends the filsys_id and the phys_id to the argv so they can be
1032 * referenced in an INSERT into a table other than filesys. Also
1033 * see comments at prefetch_value().
1035 * Assumes the existence of a row where filsys_id = argv[0], since a
1036 * filesys label has already been resolved to a filsys_id.
1038 int prefetch_filesys(struct query *q, char **argv, client *cl)
1040 EXEC SQL BEGIN DECLARE SECTION;
1042 EXEC SQL END DECLARE SECTION;
1045 fid = *(int *)argv[0];
1046 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
1050 argc = q->argc + q->vcnt;
1051 sprintf(argv[argc++], "%d", phid);
1052 sprintf(argv[argc], "%d", fid);
1061 int setup_ghst(struct query *q, char **argv, client *cl)
1063 if (strcmp(argv[0], "*") || strcmp(argv[1], "*") ||
1064 strcmp(argv[2], "*") || strcmp(argv[3], "*"))
1073 int setup_ahst(struct query *q, char **argv, client *cl)
1075 EXEC SQL BEGIN DECLARE SECTION;
1076 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
1077 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
1078 int value, id, ssaddr, smask, shigh, slow, cnt;
1079 unsigned int saddr, mask, high, low;
1080 EXEC SQL END DECLARE SECTION;
1082 struct in_addr addr;
1084 id = *(int *)argv[0];
1086 if (!strcmp(q->shortname, "uhst"))
1089 EXEC SQL SELECT name, vendor, model, os
1090 INTO :oldname, :vendor, :model, :os
1091 FROM machine WHERE mach_id = :id;
1098 else if (q->version >= 6 && q->version < 8)
1103 /* Sanity check name, vendor, model, and os. */
1104 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
1105 !hostname_check(argv[row]))
1107 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
1108 !hostinfo_check(argv[row + 1], 0))
1110 if ((row == 0 || strcasecmp(argv[3], model)) &&
1111 !hostinfo_check(argv[row + 2], 1))
1113 if ((row == 0 || strcasecmp(argv[4], os)) &&
1114 !hostinfo_check(argv[row + 3], 0))
1117 /* check for duplicate name */
1119 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
1120 WHERE name = UPPER(:name);
1127 if (!strcmp(argv[9 + row + idx], "unassigned"))
1129 else if (!strcmp(argv[9 + row + idx], "unique"))
1131 if (*(int *)argv[8 + row + idx] == 0)
1138 value = ntohl(inet_addr(argv[9 + row + idx]));
1147 * an address or unique was specified.
1149 id = *(int *)argv[8 + row + idx];
1150 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1151 :shigh, :slow FROM subnet WHERE snet_id = :id;
1154 saddr = (unsigned) ssaddr;
1155 mask = (unsigned) smask;
1156 high = (unsigned) shigh;
1157 low = (unsigned) slow;
1161 * someone specified an IP address for the host record
1163 if ((value & mask) != saddr || value < low || value > high)
1166 * run the address argument through inet_addr(). This
1167 * has the effect that any out of bounds host addrs will
1168 * be converted to a valid host addr. We do this now
1169 * so that the uniqueness check works. We should also
1170 * link in an inet_addr() that returns an error for
1173 addr.s_addr = inet_addr(argv[9 + row + idx]);
1174 name = inet_ntoa(addr);
1175 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1176 WHERE address = :name;
1182 * make IP address is unique. If this a modify request
1183 * (row == 1), then we expect one record to exist.
1185 if (row == 0 || (row == 1 && cnt > 1))
1187 if (row == 1 && cnt == 1)
1189 EXEC SQL SELECT mach_id INTO :id FROM machine
1190 WHERE address = :name;
1191 if (id != *(int *)argv[0])
1199 * a "unique" address was specified. Walk through the
1200 * range specified in the network record, return
1201 * error if no room left.
1203 for (id = low; id <= high; id++)
1205 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1207 addr.s_addr = htonl(id);
1208 name = inet_ntoa(addr);
1209 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1210 WHERE address = :name;
1222 * we have an address in value. Convert it to a string and store it.
1224 addr.s_addr = htonl(value);
1225 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1228 strcpy(argv[9 + row + idx], "unassigned");
1230 /* status checking */
1231 value = atoi(argv[7 + row + idx]);
1232 if (row == 0 && !(value == 1 || value == 0))
1236 id = *(int *)argv[0];
1237 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1242 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1243 WHERE mach_id = :id;
1248 * If this is an update_host query, we're done.
1254 * For an add_host query, allocate and fill in a new machine id,
1255 * and then insert the creator id.
1257 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1260 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1268 int setup_ahal(struct query *q, char **argv, client *cl)
1270 EXEC SQL BEGIN DECLARE SECTION;
1273 EXEC SQL END DECLARE SECTION;
1277 if (!hostname_check(argv[0]))
1280 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1281 name = UPPER(:name);
1290 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1293 int setup_uhha(struct query *q, char **argv, client *cl)
1295 EXEC SQL BEGIN DECLARE SECTION;
1296 char *hwaddr = argv[1];
1298 EXEC SQL END DECLARE SECTION;
1301 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1303 for (p = hwaddr; *p; p++)
1310 if (p != hwaddr + 12)
1313 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1314 FROM machine WHERE hwaddr = :hwaddr;
1316 return MR_NOT_UNIQUE;
1322 /* setup_aprn(): Make sure name/duplexname don't conflict with
1323 * anything. If [ANY] was specified for the spooling host, pick the
1324 * least loaded print server that serves this kind of printer.
1326 int setup_aprn(struct query *q, char **argv, client *cl)
1330 EXEC SQL BEGIN DECLARE SECTION;
1331 int mid, usage, count;
1332 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1333 EXEC SQL END DECLARE SECTION;
1335 /* Check for aprn or uprn. */
1336 if (q->type == APPEND)
1341 name = argv[PRN_NAME + row];
1342 duplexname = argv[PRN_DUPLEXNAME + row];
1349 if (q->type == APPEND)
1351 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1352 WHERE name = :name OR duplexname = :name;
1356 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1357 WHERE ( name = :name OR duplexname = :name )
1358 AND name != :oldname;
1363 return MR_NOT_UNIQUE;
1368 if (q->type == APPEND)
1370 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1371 WHERE name = :duplexname OR duplexname = :duplexname;
1375 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1376 WHERE ( name = :duplexname OR duplexname = :duplexname )
1377 AND name != :oldname;
1383 return MR_NOT_UNIQUE;
1386 if (!strcmp(name, duplexname))
1387 return MR_NOT_UNIQUE;
1389 mid = *(int *)argv[PRN_RM + row];
1392 EXEC SQL DECLARE csr_rm CURSOR FOR
1393 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1395 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1397 AND ps.printer_types = s.string_id;
1400 EXEC SQL OPEN csr_rm;
1406 EXEC SQL FETCH csr_rm INTO :mid, :types;
1410 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1412 if (!strcasecmp(argv[PRN_TYPE + row], p))
1414 EXEC SQL SELECT COUNT(name) INTO :usage
1415 FROM printers WHERE rm = :mid;
1417 if (best < 0 || usage < best)
1420 *(int *)argv[PRN_RM + row] = mid;
1426 EXEC SQL CLOSE csr_rm;
1435 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1436 WHERE mach_id = :mid;
1444 int setup_dpsv(struct query *q, char **argv, client *cl)
1447 EXEC SQL BEGIN DECLARE SECTION;
1449 EXEC SQL END DECLARE SECTION;
1451 id = *(int *)argv[0];
1453 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1461 int setup_dcon(struct query *q, char *argv[], client *cl)
1463 EXEC SQL BEGIN DECLARE SECTION;
1465 char containername[CONTAINERS_NAME_SIZE];
1466 EXEC SQL END DECLARE SECTION;
1468 id = *(int *)argv[0];
1469 /* check to see if there are machines in this container */
1470 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1475 /* check to see if there are subcontainers in this container */
1477 /* get the container name */
1479 EXEC SQL SELECT name INTO :containername
1483 /* trim off the trailing spaces */
1484 strcpy(containername, strtrim(containername));
1486 EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1487 WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
1497 int setup_scli(struct query *q, char *argv[], client *cl)
1499 EXEC SQL BEGIN DECLARE SECTION;
1500 int cnt_id, list_id;
1501 EXEC SQL END DECLARE SECTION;
1503 cnt_id = *(int *)argv[0];
1504 /* Check if someone has already set the list for this container */
1505 EXEC SQL SELECT list_id INTO :list_id FROM containers
1506 WHERE cnt_id = :cnt_id;
1517 * validate the rfc1035/rfc1123-ness of a hostname
1520 int hostname_check(char *name)
1525 /* Sanity check name: must contain only letters, numerals, and
1526 * hyphen, and not start or end with a hyphen. Also make sure no
1527 * label (the thing the .s seperate) is longer than 63 characters,
1531 for (p = name, count = 0; *p; p++)
1534 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1535 (*p == '-' && p[1] == '.'))
1546 if (*(p - 1) == '-')
1551 int hostinfo_check(char *info, int num)
1558 /* Sanity check host hostinfo: must start with a letter (or number
1559 * if num is true), contain only letters, numerals, and hyphen, and
1560 * not end with a hyphen.
1563 if (!isalpha(*info) && (!num || !isdigit(*info)))
1565 for (p = info; *p; p++)
1567 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1568 (*p == '-' && p[1] == '.'))
1571 if (!isalnum(*(p - 1)))
1575 int setup_acon(struct query *q, char *argv[], client *cl)
1577 EXEC SQL BEGIN DECLARE SECTION;
1578 char containername[CONTAINERS_NAME_SIZE];
1579 EXEC SQL END DECLARE SECTION;
1583 memset(containername, 0, sizeof(containername));
1584 strcpy(containername, argv[0]);
1585 ptr = strrchr(containername, '/');
1586 /* sub container, check for parents */
1590 EXEC SQL SELECT * FROM containers
1591 WHERE lower(name) = lower(:containername);
1592 if (sqlca.sqlerrd[2] != 1)
1593 return MR_CONTAINER_NO_PARENT;
1596 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1602 int check_mailman_listname(char *name, const char *suffix)
1605 EXEC SQL BEGIN DECLARE SECTION;
1607 EXEC SQL END DECLARE SECTION;
1609 p = strstr(name, suffix);
1612 if (strlen(name) == (p - name + strlen(suffix)))
1614 /* list is of the form "name-suffix" */
1616 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
1617 WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1;