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 * [DFS] - Magic token for DFS home directory
87 * UNC pathname - \\<something>
88 * local pathname - <drive letter>:<something>
91 if ((strcasecmp(argv[row + 12], "[AFS]")) &&
92 (strcasecmp(argv[row + 12], "[LOCAL]")) &&
93 (strcasecmp(argv[row + 12], "[DFS]")) &&
94 (!(argv[row + 12][0] == '\\' && argv[row + 12][1] == '\\')) &&
95 (!(isalpha(*argv[row + 12]) && (argv[row + 12][1] == ':'))))
98 if ((strcasecmp(argv[row + 13], "[AFS]")) &&
99 (strcasecmp(argv[row + 13], "[LOCAL]")) &&
100 (strcasecmp(argv[row + 13], "[DFS]")) &&
101 (!(argv[row + 13][0] == '\\' && argv[row + 13][1] == '\\')) &&
102 (!(isalpha(*argv[row + 13]) && (argv[row + 13][1] == ':'))))
106 if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1)
108 if ((err = set_next_object_id("unix_uid", USERS_TABLE, 1)))
110 EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'unix_uid';
111 if (sqlca.sqlerrd[2] != 1)
113 sprintf(argv[row], "%d", nuid);
116 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1)
117 sprintf(argv[0], "#%s", argv[row]);
119 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
122 /* If this is an MR_Q_UPDATE query, we're done. */
126 /* For an add query, we need to fill in the creator id. */
127 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
132 /* setup_dusr - verify that the user is no longer being referenced
133 * and may safely be deleted.
136 int setup_dusr(struct query *q, char *argv[], client *cl)
138 EXEC SQL BEGIN DECLARE SECTION;
140 char resv[USERS_RESERVATIONS_SIZE];
141 EXEC SQL END DECLARE SECTION;
143 id = *(int *)argv[0];
145 /* For now, only allow users to be deleted if their status is
146 * one of 0, 4, or 8 (the various registerable statuses)
147 * and we have no reservations about deleting them.
149 EXEC SQL SELECT status, reservations INTO :flag, :resv
150 FROM users WHERE users_id = :id;
151 if ((flag != 0 && flag != 4 && flag != 8) || *resv)
154 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
155 WHERE member_id = :id AND member_type = 'USER';
158 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
162 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
163 WHERE acl_id = :id AND acl_type = 'USER';
166 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
167 WHERE acl_id = :id AND acl_type = 'USER';
170 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
171 WHERE acl_id = :id AND acl_type = 'USER';
177 EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
178 EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
183 /* setup_dpob: Take care of keeping track of the post office usage.
185 int setup_dpob(struct query *q, char *argv[], client *cl)
187 EXEC SQL BEGIN DECLARE SECTION;
189 char type[USERS_POTYPE_SIZE];
190 EXEC SQL END DECLARE SECTION;
192 user = *(int *)argv[0];
193 EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
194 WHERE users_id = :user;
198 if (!strcmp(strtrim(type), "POP"))
199 set_pop_usage(id, -1);
204 /* setup_dmac - verify that the machine is no longer being referenced
205 * and may safely be deleted.
208 int setup_dmac(struct query *q, char *argv[], client *cl)
210 EXEC SQL BEGIN DECLARE SECTION;
212 EXEC SQL END DECLARE SECTION;
214 id = *(int *)argv[0];
216 EXEC SQL SELECT status INTO :flag FROM machine
220 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
221 WHERE potype = 'POP' AND pop_id = :id;
224 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
225 WHERE potype = 'EXCHANGE' and exchange_id = :id;
228 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
232 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
236 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
240 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
244 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
248 EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
252 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
256 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
260 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
261 WHERE member_type = 'MACHINE' and member_id = :id;
265 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
269 EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id;
275 /* setup_asnt - verify that the data entered for the subnet is sane.
276 * In particular, make sure that the "low" and "high" addresses are
277 * correctly ordered, i.e., high > low.
280 int setup_asnt(struct query *q, char *argv[], client *cl)
282 int high, low, row, status;
283 char *account_number;
285 /* Check for asnt or usnt. */
286 if (q->type == MR_Q_APPEND)
291 low = atoi(argv[row + 7]);
292 high = atoi(argv[row + 8]);
293 status = atoi(argv[row + 2]);
294 account_number = argv[row + 4];
296 /* Don't allow Private subnets to be created without a valid billing
299 if (status == SNET_STATUS_PRIVATE_10MBPS ||
300 status == SNET_STATUS_PRIVATE_100MBPS ||
301 status == SNET_STATUS_PRIVATE_1000MBPS)
303 EXEC SQL SELECT account_number FROM accountnumbers
304 WHERE account_number = :account_number;
305 if (sqlca.sqlcode == SQL_NO_MATCH)
306 return MR_ACCOUNT_NUMBER;
309 /* Special case 0.0.0.0 and 255.255.255.255 */
310 if (!(low == 0 || low == -1 || high == 0 || high == -1))
314 /* If this is update_subnet, we're done. */
318 /* For an add_subnet query, allocate and fill in a new snet_id */
319 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
325 /* setup_dsnt - verify that the subnet is no longer being referenced
326 * and may safely be deleted.
329 int setup_dsnt(struct query *q, char *argv[], client *cl)
331 EXEC SQL BEGIN DECLARE SECTION;
333 EXEC SQL END DECLARE SECTION;
335 id = *(int *)argv[0];
336 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
344 /* setup_dclu - verify that the cluster is no longer being referenced
345 * and may safely be deleted.
348 int setup_dclu(struct query *q, char *argv[], client *cl)
350 EXEC SQL BEGIN DECLARE SECTION;
352 EXEC SQL END DECLARE SECTION;
354 id = *(int *)argv[0];
355 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
359 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
369 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
370 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
371 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
372 * a -1 there. Remember that this is also used for ulis, with the indexes
373 * at 6 & 7. Also check that the list name does not contain uppercase
374 * characters, control characters, @, or :.
376 * Newlines in list descriptions do bad things to the aliases file
377 * moira generates, so make sure the description doesn't contain any, too.
380 static int badlistchars[] = {
381 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
382 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
383 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
385 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
386 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
387 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
388 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
389 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
390 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
391 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
392 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
393 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
394 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
395 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
396 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
399 static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
400 "-bounces", "-confirm", "-join",
401 "-leave", "-subscribe",
402 "-unsubscribe", NULL };
404 int setup_alis(struct query *q, char *argv[], client *cl)
406 EXEC SQL BEGIN DECLARE SECTION;
407 int ngid, cnt, mailman, mailman_id, lid;
409 EXEC SQL END DECLARE SECTION;
411 int idx, err, best = -1, usage, i;
413 if (!strcmp(q->shortname, "alis"))
415 else if (!strcmp(q->shortname, "ulis"))
420 desc = argv[9 + idx];
421 else if (q->version == 3)
422 desc = argv[10 + idx];
423 else if (q->version == 4)
424 desc = argv[12 + idx];
425 else if (q->version >= 10)
426 desc = argv[14 + idx];
430 lid = *(int *)argv[0];
432 if (acl_access_check(lid, cl))
436 for (p = (unsigned char *) name; *p; p++)
438 if (badlistchars[*p])
442 for (p = (unsigned char *) desc; *p; p++)
448 /* Check that it doesn't conflict with a pre-existing weirdly-cased
450 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
451 WHERE LOWER(name) = :name AND name != :name;
455 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
457 if (atoi(argv[5 + idx]))
459 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
461 EXEC SQL SELECT value INTO :ngid FROM numvalues
465 sprintf(argv[6 + idx], "%d", ngid);
468 strcpy(argv[6 + idx], "-1");
471 /* Don't let someone rename a list to one of the magic mailman names
472 * (foo-admin, etc) if foo already exists as a mailman list.
474 for (i = 0; mailman_suffixes[i]; i++)
476 if ((err = check_mailman_listname(name, mailman_suffixes[i]))
481 if (q->version >= 10)
483 /* Don't let them take this name for a mailman list if we can't
484 * reserve the -admin, -owner, and -request names.
486 if (atoi(argv[8 + idx]))
488 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
489 WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
490 name = :name || '-request');
495 /* Handle the [ANY] case for mailman server. */
496 mailman_id = *(int *)argv[9 + idx];
497 if (mailman_id == -1)
499 EXEC SQL DECLARE csr_mailman CURSOR FOR
500 SELECT mach_id FROM serverhosts WHERE service = 'MAILMAN'
504 EXEC SQL OPEN csr_mailman;
510 EXEC SQL FETCH csr_mailman INTO :mailman_id;
514 EXEC SQL SELECT COUNT(name) INTO :usage FROM list
515 WHERE mailman_id = :mailman_id;
517 if (best < 0 || usage < best)
520 *(int *)argv[9 + idx] = mailman_id;
524 EXEC SQL CLOSE csr_mailman;
534 /* Client too old to know about the mailman code.
535 * Use existing value of mailman boolean in the table.
536 * Don't do this for add_list from an old client, since the row
537 * they're creating won't exist yet, and there's no way for them to
538 * create a list with the mailman bit set, anyway.
542 EXEC SQL SELECT mailman INTO :mailman FROM list WHERE list_id = :lid;
545 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
546 WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
547 name = :name || '-request');
554 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
561 /* setup_dlis - verify that the list is no longer being referenced
562 * and may safely be deleted.
565 int setup_dlis(struct query *q, char *argv[], client *cl)
568 EXEC SQL BEGIN DECLARE SECTION;
570 EXEC SQL END DECLARE SECTION;
572 id = *(int *)argv[0];
574 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
575 WHERE member_id = :id AND member_type = 'LIST';
579 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
580 WHERE member_id = :id AND member_type = 'LIST';
584 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
589 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
593 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
597 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
598 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
602 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
603 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
607 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
608 WHERE acl_id = :id AND acl_type = 'LIST';
612 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
613 WHERE entity_id = :id AND type = 'GROUP';
617 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
618 WHERE acl_id = :id AND acl_type = 'LIST';
622 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
623 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
624 OR z.sub_type = 'LIST' AND z.sub_id = :id
625 OR z.iws_type = 'LIST' AND z.iws_id = :id
626 OR z.iui_type = 'LIST' AND z.iui_id = :id
627 OR z.owner_type = 'LIST' and z.owner_id = :id;
631 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
632 WHERE lpc_acl = :id OR ac = :id;
636 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
637 WHERE owner_type = 'LIST' AND owner_id = :id
642 EXEC SQL SELECT count(name) INTO :cnt FROM containers
643 WHERE acl_id = :id AND acl_type = 'LIST';
647 EXEC SQL SELECT count(name) INTO :cnt FROM containers
648 WHERE memacl_id = :id AND memacl_type = 'LIST';
656 /* setup_dsin - verify that the service is no longer being referenced
657 * and may safely be deleted.
660 int setup_dsin(struct query *q, char *argv[], client *cl)
662 EXEC SQL BEGIN DECLARE SECTION;
665 EXEC SQL END DECLARE SECTION;
668 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
669 WHERE service = UPPER(:svrname);
673 EXEC SQL SELECT inprogress INTO :ec FROM servers
674 WHERE name = UPPER(:svrname);
684 /* setup_dshi - verify that the service-host is no longer being referenced
685 * and may safely be deleted.
688 int setup_dshi(struct query *q, char *argv[], client *cl)
690 EXEC SQL BEGIN DECLARE SECTION;
693 EXEC SQL END DECLARE SECTION;
696 id = *(int *)argv[1];
698 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
699 WHERE service = UPPER(:svrname) AND mach_id = :id;
710 ** setup_add_filesys - verify existance of referenced file systems
716 ** argv[5] - rwaccess
721 ** - for type = NFS/IMAP:
722 ** * extract directory prefix from name
723 ** * verify mach_id/dir in nfsphys
724 ** * verify rwaccess in {r, w, R, W}
726 ** Side effect: sets variable _var_phys_id to the ID of the physical
727 ** filesystem (nfsphys_id for NFS, 0 for RVD)
730 ** MR_NFS - specified directory not exported
731 ** MR_FILESYS_ACCESS - invalid filesys access
735 EXEC SQL BEGIN DECLARE SECTION;
737 EXEC SQL END DECLARE SECTION;
739 int setup_afil(struct query *q, char *argv[], client *cl)
743 EXEC SQL BEGIN DECLARE SECTION;
745 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
746 EXEC SQL END DECLARE SECTION;
749 mach_id = *(int *)argv[2];
754 sprintf(ftype, "fs_access_%s", type);
755 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
756 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
760 return MR_FILESYS_ACCESS;
762 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
765 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
766 return check_nfs(mach_id, name, rwaccess);
772 /* Verify the arguments, depending on the FStype. Also, if this is an
773 * NFS filesystem, then update any quotas for that filesystem to reflect
777 int setup_ufil(struct query *q, char *argv[], client *cl)
781 EXEC SQL BEGIN DECLARE SECTION;
782 int fid, total, who, ok;
783 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
784 short int total_null;
785 EXEC SQL END DECLARE SECTION;
789 mach_id = *(int *)argv[3];
792 fid = *(int *)argv[0];
796 sprintf(ftype, "fs_access_%s", type);
797 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
798 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
802 return MR_FILESYS_ACCESS;
804 EXEC SQL SELECT type INTO :ftype FROM filesys
805 WHERE filsys_id = :fid;
809 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
811 status = check_nfs(mach_id, name, access);
812 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
813 WHERE filsys_id = :fid;
818 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
819 && strcmp(strtrim(ftype), "ERR"))
822 EXEC SQL DELETE FROM quota
823 WHERE type = 'ANY' AND filsys_id = :fid;
824 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
825 WHERE filsys_id = :fid AND phys_id != 0;
828 if (!total_null && (total != 0))
830 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
831 type, modtime, modby, modwith)
832 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
839 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
847 /* Find the NFS physical partition that the named directory is on.
848 * This is done by comparing the dir against the mount point of the
849 * partition. To make sure we get the correct match when there is
850 * more than one, we sort the query in reverse order by dir name.
853 int check_nfs(int mach_id, char *name, char *access)
855 EXEC SQL BEGIN DECLARE SECTION;
856 char dir[NFSPHYS_DIR_SIZE];
858 EXEC SQL END DECLARE SECTION;
864 EXEC SQL DECLARE csr101 CURSOR FOR
865 SELECT nfsphys_id, dir FROM nfsphys
870 EXEC SQL OPEN csr101;
875 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
892 EXEC SQL CLOSE csr101;
899 /* setup_dfil: free any quota records and fsgroup info associated with
900 * a filesystem when it is deleted. Also adjust the allocation numbers.
903 int setup_dfil(struct query *q, char **argv, client *cl)
905 EXEC SQL BEGIN DECLARE SECTION;
906 int id, total, phys_id;
908 EXEC SQL END DECLARE SECTION;
910 id = *(int *)argv[0];
911 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
912 WHERE filsys_id = :id;
917 /** What if there are multiple phys_id's per f/s? (bad data) **/
918 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
919 WHERE filsys_id = :id;
920 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
921 WHERE nfsphys_id = :phys_id;
924 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
925 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
926 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
933 /* setup_dnfp: check to see that the nfs physical partition does not have
934 * any filesystems assigned to it before allowing it to be deleted.
937 int setup_dnfp(struct query *q, char **argv, client *cl)
939 EXEC SQL BEGIN DECLARE SECTION;
942 EXEC SQL END DECLARE SECTION;
944 id = *(int *)argv[0];
946 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
947 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
948 AND np.mach_id = :id AND np.dir = :dir;
957 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
958 * argv[0] = filsys_id
959 * argv[1] = type if "update_quota" or "delete_quota"
960 * argv[2 or 1] = users_id or list_id
963 int setup_dqot(struct query *q, char **argv, client *cl)
965 EXEC SQL BEGIN DECLARE SECTION;
966 int quota, fs, id, physid;
968 EXEC SQL END DECLARE SECTION;
970 fs = *(int *)argv[0];
971 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
974 id = *(int *)argv[2];
979 id = *(int *)argv[1];
982 EXEC SQL SELECT quota INTO :quota FROM quota
983 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
984 EXEC SQL SELECT phys_id INTO :physid FROM filesys
985 WHERE filsys_id = :fs;
986 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
987 WHERE nfsphys_id = :physid;
996 * This routine fetches an appropriate value from the numvalues table.
997 * It is a little hack to get around the fact that SQL doesn't let you
998 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
1000 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
1001 * from within a setup_...() routine with the appropriate arguments.
1003 * Correct functioning of this routine may depend on the assumption
1004 * that this query is an MR_Q_APPEND.
1007 int prefetch_value(struct query *q, char **argv, client *cl)
1009 EXEC SQL BEGIN DECLARE SECTION;
1010 char *name = q->validate->object_id;
1012 EXEC SQL END DECLARE SECTION;
1013 int status, limit, argc;
1015 /* set next object id, limiting it if necessary */
1016 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
1017 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
1020 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
1023 /* fetch object id */
1024 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
1027 if (sqlca.sqlerrd[2] != 1)
1030 argc = q->argc + q->vcnt; /* end of Argv for MR_Q_APPENDs */
1031 sprintf(argv[argc], "%d", value);
1036 /* prefetch_filesys():
1037 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
1038 * Appends the filsys_id and the phys_id to the argv so they can be
1039 * referenced in an INSERT into a table other than filesys. Also
1040 * see comments at prefetch_value().
1042 * Assumes the existence of a row where filsys_id = argv[0], since a
1043 * filesys label has already been resolved to a filsys_id.
1045 int prefetch_filesys(struct query *q, char **argv, client *cl)
1047 EXEC SQL BEGIN DECLARE SECTION;
1049 EXEC SQL END DECLARE SECTION;
1052 fid = *(int *)argv[0];
1053 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
1057 argc = q->argc + q->vcnt;
1058 sprintf(argv[argc++], "%d", phid);
1059 sprintf(argv[argc], "%d", fid);
1068 int setup_ghst(struct query *q, char **argv, client *cl)
1070 if (strcmp(argv[0], "*") || strcmp(argv[1], "*") ||
1071 strcmp(argv[2], "*") || strcmp(argv[3], "*"))
1080 int setup_ahst(struct query *q, char **argv, client *cl)
1082 EXEC SQL BEGIN DECLARE SECTION;
1083 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
1084 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
1085 int value, id, ssaddr, smask, shigh, slow, cnt;
1086 unsigned int saddr, mask, high, low;
1087 EXEC SQL END DECLARE SECTION;
1089 struct in_addr addr;
1091 id = *(int *)argv[0];
1093 if (!strcmp(q->shortname, "uhst"))
1096 EXEC SQL SELECT name, vendor, model, os
1097 INTO :oldname, :vendor, :model, :os
1098 FROM machine WHERE mach_id = :id;
1105 else if (q->version >= 6 && q->version < 8)
1110 /* Sanity check name, vendor, model, and os. */
1111 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
1112 !hostname_check(argv[row]))
1114 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
1115 !hostinfo_check(argv[row + 1], 0))
1117 if ((row == 0 || strcasecmp(argv[3], model)) &&
1118 !hostinfo_check(argv[row + 2], 1))
1120 if ((row == 0 || strcasecmp(argv[4], os)) &&
1121 !hostinfo_check(argv[row + 3], 0))
1124 /* check for duplicate name */
1126 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
1127 WHERE name = UPPER(:name);
1134 if (!strcmp(argv[9 + row + idx], "unassigned"))
1136 else if (!strcmp(argv[9 + row + idx], "unique"))
1138 if (*(int *)argv[8 + row + idx] == 0)
1145 value = ntohl(inet_addr(argv[9 + row + idx]));
1154 * an address or unique was specified.
1156 id = *(int *)argv[8 + row + idx];
1157 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1158 :shigh, :slow FROM subnet WHERE snet_id = :id;
1161 saddr = (unsigned) ssaddr;
1162 mask = (unsigned) smask;
1163 high = (unsigned) shigh;
1164 low = (unsigned) slow;
1168 * someone specified an IP address for the host record
1170 if ((value & mask) != saddr || value < low || value > high)
1173 * run the address argument through inet_addr(). This
1174 * has the effect that any out of bounds host addrs will
1175 * be converted to a valid host addr. We do this now
1176 * so that the uniqueness check works. We should also
1177 * link in an inet_addr() that returns an error for
1180 addr.s_addr = inet_addr(argv[9 + row + idx]);
1181 name = inet_ntoa(addr);
1182 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1183 WHERE address = :name;
1189 * make IP address is unique. If this a modify request
1190 * (row == 1), then we expect one record to exist.
1192 if (row == 0 || (row == 1 && cnt > 1))
1194 if (row == 1 && cnt == 1)
1196 EXEC SQL SELECT mach_id INTO :id FROM machine
1197 WHERE address = :name;
1198 if (id != *(int *)argv[0])
1206 * a "unique" address was specified. Walk through the
1207 * range specified in the network record, return
1208 * error if no room left.
1210 for (id = low; id <= high; id++)
1212 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1214 addr.s_addr = htonl(id);
1215 name = inet_ntoa(addr);
1216 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1217 WHERE address = :name;
1229 * we have an address in value. Convert it to a string and store it.
1231 addr.s_addr = htonl(value);
1232 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1235 strcpy(argv[9 + row + idx], "unassigned");
1237 /* status checking */
1238 value = atoi(argv[7 + row + idx]);
1239 if (row == 0 && !(value == 1 || value == 0))
1243 id = *(int *)argv[0];
1244 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1249 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1250 WHERE mach_id = :id;
1255 * If this is an update_host query, we're done.
1261 * For an add_host query, allocate and fill in a new machine id,
1262 * and then insert the creator id.
1264 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1267 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1275 int setup_ahal(struct query *q, char **argv, client *cl)
1277 EXEC SQL BEGIN DECLARE SECTION;
1280 EXEC SQL END DECLARE SECTION;
1284 if (!hostname_check(argv[0]))
1287 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1288 name = UPPER(:name);
1297 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1300 int setup_uhha(struct query *q, char **argv, client *cl)
1302 EXEC SQL BEGIN DECLARE SECTION;
1303 char *hwaddr = argv[1];
1305 EXEC SQL END DECLARE SECTION;
1308 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1310 for (p = hwaddr; *p; p++)
1317 if (p != hwaddr + 12)
1320 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1321 FROM machine WHERE hwaddr = :hwaddr;
1323 return MR_NOT_UNIQUE;
1329 /* setup_aprn(): Make sure name/duplexname don't conflict with
1330 * anything. If [ANY] was specified for the spooling host, pick the
1331 * least loaded print server that serves this kind of printer.
1333 int setup_aprn(struct query *q, char **argv, client *cl)
1337 EXEC SQL BEGIN DECLARE SECTION;
1338 int mid, usage, count;
1339 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1340 EXEC SQL END DECLARE SECTION;
1342 /* Check for aprn or uprn. */
1343 if (q->type == MR_Q_APPEND)
1348 name = argv[PRN_NAME + row];
1349 duplexname = argv[PRN_DUPLEXNAME + row];
1356 if (q->type == MR_Q_APPEND)
1358 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1359 WHERE name = :name OR duplexname = :name;
1363 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1364 WHERE ( name = :name OR duplexname = :name )
1365 AND name != :oldname;
1370 return MR_NOT_UNIQUE;
1375 if (q->type == MR_Q_APPEND)
1377 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1378 WHERE name = :duplexname OR duplexname = :duplexname;
1382 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1383 WHERE ( name = :duplexname OR duplexname = :duplexname )
1384 AND name != :oldname;
1390 return MR_NOT_UNIQUE;
1393 if (!strcmp(name, duplexname))
1394 return MR_NOT_UNIQUE;
1396 mid = *(int *)argv[PRN_RM + row];
1399 EXEC SQL DECLARE csr_rm CURSOR FOR
1400 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1402 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1404 AND ps.printer_types = s.string_id;
1407 EXEC SQL OPEN csr_rm;
1413 EXEC SQL FETCH csr_rm INTO :mid, :types;
1417 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1419 if (!strcasecmp(argv[PRN_TYPE + row], p))
1421 EXEC SQL SELECT COUNT(name) INTO :usage
1422 FROM printers WHERE rm = :mid;
1424 if (best < 0 || usage < best)
1427 *(int *)argv[PRN_RM + row] = mid;
1433 EXEC SQL CLOSE csr_rm;
1442 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1443 WHERE mach_id = :mid;
1451 int setup_dpsv(struct query *q, char **argv, client *cl)
1454 EXEC SQL BEGIN DECLARE SECTION;
1456 EXEC SQL END DECLARE SECTION;
1458 id = *(int *)argv[0];
1460 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1468 int setup_dcon(struct query *q, char *argv[], client *cl)
1470 EXEC SQL BEGIN DECLARE SECTION;
1472 char containername[CONTAINERS_NAME_SIZE];
1473 EXEC SQL END DECLARE SECTION;
1475 id = *(int *)argv[0];
1476 /* check to see if there are machines in this container */
1477 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1482 /* check to see if there are subcontainers in this container */
1484 /* get the container name */
1486 EXEC SQL SELECT name INTO :containername
1490 /* trim off the trailing spaces */
1491 strcpy(containername, strtrim(containername));
1493 EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1494 WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
1504 int setup_scli(struct query *q, char *argv[], client *cl)
1506 EXEC SQL BEGIN DECLARE SECTION;
1507 int cnt_id, list_id;
1508 EXEC SQL END DECLARE SECTION;
1510 cnt_id = *(int *)argv[0];
1511 /* Check if someone has already set the list for this container */
1512 EXEC SQL SELECT list_id INTO :list_id FROM containers
1513 WHERE cnt_id = :cnt_id;
1524 * validate the rfc1035/rfc1123-ness of a hostname
1527 int hostname_check(char *name)
1532 /* Sanity check name: must contain only letters, numerals, and
1533 * hyphen, and not start or end with a hyphen. Also make sure no
1534 * label (the thing the .s seperate) is longer than 63 characters,
1538 for (p = name, count = 0; *p; p++)
1541 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1542 (*p == '-' && p[1] == '.'))
1553 if (*(p - 1) == '-')
1558 int hostinfo_check(char *info, int num)
1565 /* Sanity check host hostinfo: must start with a letter (or number
1566 * if num is true), contain only letters, numerals, and hyphen, and
1567 * not end with a hyphen.
1570 if (!isalpha(*info) && (!num || !isdigit(*info)))
1572 for (p = info; *p; p++)
1574 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1575 (*p == '-' && p[1] == '.'))
1578 if (!isalnum(*(p - 1)))
1582 int setup_aali(struct query *q, char *argv[], client *cl)
1584 EXEC SQL BEGIN DECLARE SECTION;
1586 char *name, *type, *trans;
1587 EXEC SQL END DECLARE SECTION;
1592 if (strcmp(strtrim(type), "FILESYS"))
1595 EXEC SQL SELECT count(label) INTO :cnt FROM filesys WHERE
1603 int setup_acon(struct query *q, char *argv[], client *cl)
1605 EXEC SQL BEGIN DECLARE SECTION;
1606 char containername[CONTAINERS_NAME_SIZE];
1607 EXEC SQL END DECLARE SECTION;
1611 memset(containername, 0, sizeof(containername));
1612 strcpy(containername, argv[0]);
1613 ptr = strrchr(containername, '/');
1614 /* sub container, check for parents */
1618 EXEC SQL SELECT * FROM containers
1619 WHERE lower(name) = lower(:containername);
1620 if (sqlca.sqlerrd[2] != 1)
1621 return MR_CONTAINER_NO_PARENT;
1624 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1630 int check_mailman_listname(char *name, const char *suffix)
1633 EXEC SQL BEGIN DECLARE SECTION;
1635 EXEC SQL END DECLARE SECTION;
1637 p = strstr(name, suffix);
1640 if (strlen(name) == (p - name + strlen(suffix)))
1642 /* list is of the form "name-suffix" */
1644 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
1645 WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1;