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 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(mach_id) INTO :cnt FROM serverhosts
228 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
232 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
236 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
240 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
244 EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
248 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
252 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
256 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
257 WHERE member_type = 'MACHINE' and member_id = :id;
261 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
265 EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id;
271 /* setup_asnt - verify that the data entered for the subnet is sane.
272 * In particular, make sure that the "low" and "high" addresses are
273 * correctly ordered, i.e., high > low.
276 int setup_asnt(struct query *q, char *argv[], client *cl)
278 int high, low, row, status;
279 char *account_number;
281 /* Check for asnt or usnt. */
282 if (q->type == APPEND)
287 low = atoi(argv[row + 7]);
288 high = atoi(argv[row + 8]);
289 status = atoi(argv[row + 2]);
290 account_number = argv[row + 4];
292 /* Don't allow Private subnets to be created without a valid billing
295 if (status == SNET_STATUS_PRIVATE_10MBPS ||
296 status == SNET_STATUS_PRIVATE_100MBPS ||
297 status == SNET_STATUS_PRIVATE_1000MBPS)
299 EXEC SQL SELECT account_number FROM accountnumbers
300 WHERE account_number = :account_number;
301 if (sqlca.sqlcode == SQL_NO_MATCH)
302 return MR_ACCOUNT_NUMBER;
305 /* Special case 0.0.0.0 and 255.255.255.255 */
306 if (!(low == 0 || low == -1 || high == 0 || high == -1))
310 /* If this is update_subnet, we're done. */
314 /* For an add_subnet query, allocate and fill in a new snet_id */
315 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
321 /* setup_dsnt - verify that the subnet is no longer being referenced
322 * and may safely be deleted.
325 int setup_dsnt(struct query *q, char *argv[], client *cl)
327 EXEC SQL BEGIN DECLARE SECTION;
329 EXEC SQL END DECLARE SECTION;
331 id = *(int *)argv[0];
332 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
340 /* setup_dclu - verify that the cluster is no longer being referenced
341 * and may safely be deleted.
344 int setup_dclu(struct query *q, char *argv[], client *cl)
346 EXEC SQL BEGIN DECLARE SECTION;
348 EXEC SQL END DECLARE SECTION;
350 id = *(int *)argv[0];
351 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
355 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
365 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
366 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
367 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
368 * a -1 there. Remember that this is also used for ulis, with the indexes
369 * at 6 & 7. Also check that the list name does not contain uppercase
370 * characters, control characters, @, or :.
372 * Newlines in list descriptions do bad things to the aliases file
373 * moira generates, so make sure the description doesn't contain any, too.
376 static int badlistchars[] = {
377 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
378 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
379 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
380 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
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, 0, /* P - _ */
383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
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,
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,
395 static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
396 "-bounces", "-confirm", "-join",
397 "-leave", "-subscribe",
398 "-unsubscribe", NULL };
400 int setup_alis(struct query *q, char *argv[], client *cl)
402 EXEC SQL BEGIN DECLARE SECTION;
403 int ngid, cnt, mailman, mailman_id, lid;
405 EXEC SQL END DECLARE SECTION;
407 int idx, err, best = -1, usage, i;
409 if (!strcmp(q->shortname, "alis"))
411 else if (!strcmp(q->shortname, "ulis"))
416 desc = argv[9 + idx];
417 else if (q->version == 3)
418 desc = argv[10 + idx];
419 else if (q->version == 4)
420 desc = argv[12 + idx];
421 else if (q->version >= 10)
422 desc = argv[14 + idx];
426 lid = *(int *)argv[0];
428 if (acl_access_check(lid, cl))
432 for (p = (unsigned char *) name; *p; p++)
434 if (badlistchars[*p])
438 for (p = (unsigned char *) desc; *p; p++)
444 /* Check that it doesn't conflict with a pre-existing weirdly-cased
446 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
447 WHERE LOWER(name) = :name AND name != :name;
451 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
453 if (atoi(argv[5 + idx]))
455 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
457 EXEC SQL SELECT value INTO :ngid FROM numvalues
461 sprintf(argv[6 + idx], "%d", ngid);
464 strcpy(argv[6 + idx], "-1");
467 /* Don't let someone rename a list to one of the magic mailman names
468 * (foo-admin, etc) if foo already exists as a mailman list.
470 for (i = 0; mailman_suffixes[i]; i++)
472 if ((err = check_mailman_listname(name, mailman_suffixes[i]))
477 if (q->version >= 10)
479 /* Don't let them take this name for a mailman list if we can't
480 * reserve the -admin, -owner, and -request names.
482 if (atoi(argv[8 + idx]))
484 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
485 WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
486 name = :name || '-request');
491 /* Handle the [ANY] case for mailman server. */
492 mailman_id = *(int *)argv[9 + idx];
493 if (mailman_id == -1)
495 EXEC SQL DECLARE csr_mailman CURSOR FOR
496 SELECT mach_id FROM serverhosts WHERE service = 'MAILMAN'
500 EXEC SQL OPEN csr_mailman;
506 EXEC SQL FETCH csr_mailman INTO :mailman_id;
510 EXEC SQL SELECT COUNT(name) INTO :usage FROM list
511 WHERE mailman_id = :mailman_id;
513 if (best < 0 || usage < best)
516 *(int *)argv[9 + idx] = mailman_id;
520 EXEC SQL CLOSE csr_mailman;
530 /* Client too old to know about the mailman code.
531 * Use existing value of mailman boolean in the table.
532 * Don't do this for add_list from an old client, since the row
533 * they're creating won't exist yet, and there's no way for them to
534 * create a list with the mailman bit set, anyway.
538 EXEC SQL SELECT mailman INTO :mailman FROM list WHERE list_id = :lid;
541 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
542 WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
543 name = :name || '-request');
550 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
557 /* setup_dlis - verify that the list is no longer being referenced
558 * and may safely be deleted.
561 int setup_dlis(struct query *q, char *argv[], client *cl)
564 EXEC SQL BEGIN DECLARE SECTION;
566 EXEC SQL END DECLARE SECTION;
568 id = *(int *)argv[0];
570 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
571 WHERE member_id = :id AND member_type = 'LIST';
575 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
576 WHERE member_id = :id AND member_type = 'LIST';
580 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
585 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
589 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
593 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
594 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
598 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
599 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
603 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
604 WHERE acl_id = :id AND acl_type = 'LIST';
608 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
609 WHERE entity_id = :id AND type = 'GROUP';
613 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
614 WHERE acl_id = :id AND acl_type = 'LIST';
618 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
619 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
620 OR z.sub_type = 'LIST' AND z.sub_id = :id
621 OR z.iws_type = 'LIST' AND z.iws_id = :id
622 OR z.iui_type = 'LIST' AND z.iui_id = :id
623 OR z.owner_type = 'LIST' and z.owner_id = :id;
627 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
628 WHERE lpc_acl = :id OR ac = :id;
632 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
633 WHERE owner_type = 'LIST' AND owner_id = :id
638 EXEC SQL SELECT count(name) INTO :cnt FROM containers
639 WHERE acl_id = :id AND acl_type = 'LIST';
643 EXEC SQL SELECT count(name) INTO :cnt FROM containers
644 WHERE memacl_id = :id AND memacl_type = 'LIST';
652 /* setup_dsin - verify that the service is no longer being referenced
653 * and may safely be deleted.
656 int setup_dsin(struct query *q, char *argv[], client *cl)
658 EXEC SQL BEGIN DECLARE SECTION;
661 EXEC SQL END DECLARE SECTION;
664 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
665 WHERE service = UPPER(:svrname);
669 EXEC SQL SELECT inprogress INTO :ec FROM servers
670 WHERE name = UPPER(:svrname);
680 /* setup_dshi - verify that the service-host is no longer being referenced
681 * and may safely be deleted.
684 int setup_dshi(struct query *q, char *argv[], client *cl)
686 EXEC SQL BEGIN DECLARE SECTION;
689 EXEC SQL END DECLARE SECTION;
692 id = *(int *)argv[1];
694 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
695 WHERE service = UPPER(:svrname) AND mach_id = :id;
706 ** setup_add_filesys - verify existance of referenced file systems
712 ** argv[5] - rwaccess
717 ** - for type = NFS/IMAP:
718 ** * extract directory prefix from name
719 ** * verify mach_id/dir in nfsphys
720 ** * verify rwaccess in {r, w, R, W}
722 ** Side effect: sets variable _var_phys_id to the ID of the physical
723 ** filesystem (nfsphys_id for NFS, 0 for RVD)
726 ** MR_NFS - specified directory not exported
727 ** MR_FILESYS_ACCESS - invalid filesys access
731 EXEC SQL BEGIN DECLARE SECTION;
733 EXEC SQL END DECLARE SECTION;
735 int setup_afil(struct query *q, char *argv[], client *cl)
739 EXEC SQL BEGIN DECLARE SECTION;
741 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
742 EXEC SQL END DECLARE SECTION;
745 mach_id = *(int *)argv[2];
750 sprintf(ftype, "fs_access_%s", type);
751 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
752 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
756 return MR_FILESYS_ACCESS;
758 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
761 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
762 return check_nfs(mach_id, name, rwaccess);
768 /* Verify the arguments, depending on the FStype. Also, if this is an
769 * NFS filesystem, then update any quotas for that filesystem to reflect
773 int setup_ufil(struct query *q, char *argv[], client *cl)
777 EXEC SQL BEGIN DECLARE SECTION;
778 int fid, total, who, ok;
779 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
780 short int total_null;
781 EXEC SQL END DECLARE SECTION;
785 mach_id = *(int *)argv[3];
788 fid = *(int *)argv[0];
792 sprintf(ftype, "fs_access_%s", type);
793 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
794 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
798 return MR_FILESYS_ACCESS;
800 EXEC SQL SELECT type INTO :ftype FROM filesys
801 WHERE filsys_id = :fid;
805 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
807 status = check_nfs(mach_id, name, access);
808 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
809 WHERE filsys_id = :fid;
814 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
815 && strcmp(strtrim(ftype), "ERR"))
818 EXEC SQL DELETE FROM quota
819 WHERE type = 'ANY' AND filsys_id = :fid;
820 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
821 WHERE filsys_id = :fid AND phys_id != 0;
824 if (!total_null && (total != 0))
826 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
827 type, modtime, modby, modwith)
828 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
835 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
843 /* Find the NFS physical partition that the named directory is on.
844 * This is done by comparing the dir against the mount point of the
845 * partition. To make sure we get the correct match when there is
846 * more than one, we sort the query in reverse order by dir name.
849 int check_nfs(int mach_id, char *name, char *access)
851 EXEC SQL BEGIN DECLARE SECTION;
852 char dir[NFSPHYS_DIR_SIZE];
854 EXEC SQL END DECLARE SECTION;
860 EXEC SQL DECLARE csr101 CURSOR FOR
861 SELECT nfsphys_id, dir FROM nfsphys
866 EXEC SQL OPEN csr101;
871 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
888 EXEC SQL CLOSE csr101;
895 /* setup_dfil: free any quota records and fsgroup info associated with
896 * a filesystem when it is deleted. Also adjust the allocation numbers.
899 int setup_dfil(struct query *q, char **argv, client *cl)
901 EXEC SQL BEGIN DECLARE SECTION;
902 int id, total, phys_id;
904 EXEC SQL END DECLARE SECTION;
906 id = *(int *)argv[0];
907 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
908 WHERE filsys_id = :id;
913 /** What if there are multiple phys_id's per f/s? (bad data) **/
914 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
915 WHERE filsys_id = :id;
916 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
917 WHERE nfsphys_id = :phys_id;
920 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
921 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
922 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
929 /* setup_dnfp: check to see that the nfs physical partition does not have
930 * any filesystems assigned to it before allowing it to be deleted.
933 int setup_dnfp(struct query *q, char **argv, client *cl)
935 EXEC SQL BEGIN DECLARE SECTION;
938 EXEC SQL END DECLARE SECTION;
940 id = *(int *)argv[0];
942 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
943 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
944 AND np.mach_id = :id AND np.dir = :dir;
953 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
954 * argv[0] = filsys_id
955 * argv[1] = type if "update_quota" or "delete_quota"
956 * argv[2 or 1] = users_id or list_id
959 int setup_dqot(struct query *q, char **argv, client *cl)
961 EXEC SQL BEGIN DECLARE SECTION;
962 int quota, fs, id, physid;
964 EXEC SQL END DECLARE SECTION;
966 fs = *(int *)argv[0];
967 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
970 id = *(int *)argv[2];
975 id = *(int *)argv[1];
978 EXEC SQL SELECT quota INTO :quota FROM quota
979 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
980 EXEC SQL SELECT phys_id INTO :physid FROM filesys
981 WHERE filsys_id = :fs;
982 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
983 WHERE nfsphys_id = :physid;
992 * This routine fetches an appropriate value from the numvalues table.
993 * It is a little hack to get around the fact that SQL doesn't let you
994 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
996 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
997 * from within a setup_...() routine with the appropriate arguments.
999 * Correct functioning of this routine may depend on the assumption
1000 * that this query is an APPEND.
1003 int prefetch_value(struct query *q, char **argv, client *cl)
1005 EXEC SQL BEGIN DECLARE SECTION;
1006 char *name = q->validate->object_id;
1008 EXEC SQL END DECLARE SECTION;
1009 int status, limit, argc;
1011 /* set next object id, limiting it if necessary */
1012 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
1013 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
1016 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
1019 /* fetch object id */
1020 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
1023 if (sqlca.sqlerrd[2] != 1)
1026 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
1027 sprintf(argv[argc], "%d", value);
1032 /* prefetch_filesys():
1033 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
1034 * Appends the filsys_id and the phys_id to the argv so they can be
1035 * referenced in an INSERT into a table other than filesys. Also
1036 * see comments at prefetch_value().
1038 * Assumes the existence of a row where filsys_id = argv[0], since a
1039 * filesys label has already been resolved to a filsys_id.
1041 int prefetch_filesys(struct query *q, char **argv, client *cl)
1043 EXEC SQL BEGIN DECLARE SECTION;
1045 EXEC SQL END DECLARE SECTION;
1048 fid = *(int *)argv[0];
1049 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
1053 argc = q->argc + q->vcnt;
1054 sprintf(argv[argc++], "%d", phid);
1055 sprintf(argv[argc], "%d", fid);
1064 int setup_ghst(struct query *q, char **argv, client *cl)
1066 if (strcmp(argv[0], "*") || strcmp(argv[1], "*") ||
1067 strcmp(argv[2], "*") || strcmp(argv[3], "*"))
1076 int setup_ahst(struct query *q, char **argv, client *cl)
1078 EXEC SQL BEGIN DECLARE SECTION;
1079 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
1080 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
1081 int value, id, ssaddr, smask, shigh, slow, cnt;
1082 unsigned int saddr, mask, high, low;
1083 EXEC SQL END DECLARE SECTION;
1085 struct in_addr addr;
1087 id = *(int *)argv[0];
1089 if (!strcmp(q->shortname, "uhst"))
1092 EXEC SQL SELECT name, vendor, model, os
1093 INTO :oldname, :vendor, :model, :os
1094 FROM machine WHERE mach_id = :id;
1101 else if (q->version >= 6 && q->version < 8)
1106 /* Sanity check name, vendor, model, and os. */
1107 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
1108 !hostname_check(argv[row]))
1110 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
1111 !hostinfo_check(argv[row + 1], 0))
1113 if ((row == 0 || strcasecmp(argv[3], model)) &&
1114 !hostinfo_check(argv[row + 2], 1))
1116 if ((row == 0 || strcasecmp(argv[4], os)) &&
1117 !hostinfo_check(argv[row + 3], 0))
1120 /* check for duplicate name */
1122 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
1123 WHERE name = UPPER(:name);
1130 if (!strcmp(argv[9 + row + idx], "unassigned"))
1132 else if (!strcmp(argv[9 + row + idx], "unique"))
1134 if (*(int *)argv[8 + row + idx] == 0)
1141 value = ntohl(inet_addr(argv[9 + row + idx]));
1150 * an address or unique was specified.
1152 id = *(int *)argv[8 + row + idx];
1153 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1154 :shigh, :slow FROM subnet WHERE snet_id = :id;
1157 saddr = (unsigned) ssaddr;
1158 mask = (unsigned) smask;
1159 high = (unsigned) shigh;
1160 low = (unsigned) slow;
1164 * someone specified an IP address for the host record
1166 if ((value & mask) != saddr || value < low || value > high)
1169 * run the address argument through inet_addr(). This
1170 * has the effect that any out of bounds host addrs will
1171 * be converted to a valid host addr. We do this now
1172 * so that the uniqueness check works. We should also
1173 * link in an inet_addr() that returns an error for
1176 addr.s_addr = inet_addr(argv[9 + row + idx]);
1177 name = inet_ntoa(addr);
1178 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1179 WHERE address = :name;
1185 * make IP address is unique. If this a modify request
1186 * (row == 1), then we expect one record to exist.
1188 if (row == 0 || (row == 1 && cnt > 1))
1190 if (row == 1 && cnt == 1)
1192 EXEC SQL SELECT mach_id INTO :id FROM machine
1193 WHERE address = :name;
1194 if (id != *(int *)argv[0])
1202 * a "unique" address was specified. Walk through the
1203 * range specified in the network record, return
1204 * error if no room left.
1206 for (id = low; id <= high; id++)
1208 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1210 addr.s_addr = htonl(id);
1211 name = inet_ntoa(addr);
1212 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1213 WHERE address = :name;
1225 * we have an address in value. Convert it to a string and store it.
1227 addr.s_addr = htonl(value);
1228 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1231 strcpy(argv[9 + row + idx], "unassigned");
1233 /* status checking */
1234 value = atoi(argv[7 + row + idx]);
1235 if (row == 0 && !(value == 1 || value == 0))
1239 id = *(int *)argv[0];
1240 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1245 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1246 WHERE mach_id = :id;
1251 * If this is an update_host query, we're done.
1257 * For an add_host query, allocate and fill in a new machine id,
1258 * and then insert the creator id.
1260 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1263 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1271 int setup_ahal(struct query *q, char **argv, client *cl)
1273 EXEC SQL BEGIN DECLARE SECTION;
1276 EXEC SQL END DECLARE SECTION;
1280 if (!hostname_check(argv[0]))
1283 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1284 name = UPPER(:name);
1293 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1296 int setup_uhha(struct query *q, char **argv, client *cl)
1298 EXEC SQL BEGIN DECLARE SECTION;
1299 char *hwaddr = argv[1];
1301 EXEC SQL END DECLARE SECTION;
1304 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1306 for (p = hwaddr; *p; p++)
1313 if (p != hwaddr + 12)
1316 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1317 FROM machine WHERE hwaddr = :hwaddr;
1319 return MR_NOT_UNIQUE;
1325 /* setup_aprn(): Make sure name/duplexname don't conflict with
1326 * anything. If [ANY] was specified for the spooling host, pick the
1327 * least loaded print server that serves this kind of printer.
1329 int setup_aprn(struct query *q, char **argv, client *cl)
1333 EXEC SQL BEGIN DECLARE SECTION;
1334 int mid, usage, count;
1335 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1336 EXEC SQL END DECLARE SECTION;
1338 /* Check for aprn or uprn. */
1339 if (q->type == APPEND)
1344 name = argv[PRN_NAME + row];
1345 duplexname = argv[PRN_DUPLEXNAME + row];
1352 if (q->type == APPEND)
1354 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1355 WHERE name = :name OR duplexname = :name;
1359 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1360 WHERE ( name = :name OR duplexname = :name )
1361 AND name != :oldname;
1366 return MR_NOT_UNIQUE;
1371 if (q->type == APPEND)
1373 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1374 WHERE name = :duplexname OR duplexname = :duplexname;
1378 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1379 WHERE ( name = :duplexname OR duplexname = :duplexname )
1380 AND name != :oldname;
1386 return MR_NOT_UNIQUE;
1389 if (!strcmp(name, duplexname))
1390 return MR_NOT_UNIQUE;
1392 mid = *(int *)argv[PRN_RM + row];
1395 EXEC SQL DECLARE csr_rm CURSOR FOR
1396 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1398 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1400 AND ps.printer_types = s.string_id;
1403 EXEC SQL OPEN csr_rm;
1409 EXEC SQL FETCH csr_rm INTO :mid, :types;
1413 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1415 if (!strcasecmp(argv[PRN_TYPE + row], p))
1417 EXEC SQL SELECT COUNT(name) INTO :usage
1418 FROM printers WHERE rm = :mid;
1420 if (best < 0 || usage < best)
1423 *(int *)argv[PRN_RM + row] = mid;
1429 EXEC SQL CLOSE csr_rm;
1438 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1439 WHERE mach_id = :mid;
1447 int setup_dpsv(struct query *q, char **argv, client *cl)
1450 EXEC SQL BEGIN DECLARE SECTION;
1452 EXEC SQL END DECLARE SECTION;
1454 id = *(int *)argv[0];
1456 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1464 int setup_dcon(struct query *q, char *argv[], client *cl)
1466 EXEC SQL BEGIN DECLARE SECTION;
1468 char containername[CONTAINERS_NAME_SIZE];
1469 EXEC SQL END DECLARE SECTION;
1471 id = *(int *)argv[0];
1472 /* check to see if there are machines in this container */
1473 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1478 /* check to see if there are subcontainers in this container */
1480 /* get the container name */
1482 EXEC SQL SELECT name INTO :containername
1486 /* trim off the trailing spaces */
1487 strcpy(containername, strtrim(containername));
1489 EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1490 WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
1500 int setup_scli(struct query *q, char *argv[], client *cl)
1502 EXEC SQL BEGIN DECLARE SECTION;
1503 int cnt_id, list_id;
1504 EXEC SQL END DECLARE SECTION;
1506 cnt_id = *(int *)argv[0];
1507 /* Check if someone has already set the list for this container */
1508 EXEC SQL SELECT list_id INTO :list_id FROM containers
1509 WHERE cnt_id = :cnt_id;
1520 * validate the rfc1035/rfc1123-ness of a hostname
1523 int hostname_check(char *name)
1528 /* Sanity check name: must contain only letters, numerals, and
1529 * hyphen, and not start or end with a hyphen. Also make sure no
1530 * label (the thing the .s seperate) is longer than 63 characters,
1534 for (p = name, count = 0; *p; p++)
1537 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1538 (*p == '-' && p[1] == '.'))
1549 if (*(p - 1) == '-')
1554 int hostinfo_check(char *info, int num)
1561 /* Sanity check host hostinfo: must start with a letter (or number
1562 * if num is true), contain only letters, numerals, and hyphen, and
1563 * not end with a hyphen.
1566 if (!isalpha(*info) && (!num || !isdigit(*info)))
1568 for (p = info; *p; p++)
1570 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1571 (*p == '-' && p[1] == '.'))
1574 if (!isalnum(*(p - 1)))
1578 int setup_acon(struct query *q, char *argv[], client *cl)
1580 EXEC SQL BEGIN DECLARE SECTION;
1581 char containername[CONTAINERS_NAME_SIZE];
1582 EXEC SQL END DECLARE SECTION;
1586 memset(containername, 0, sizeof(containername));
1587 strcpy(containername, argv[0]);
1588 ptr = strrchr(containername, '/');
1589 /* sub container, check for parents */
1593 EXEC SQL SELECT * FROM containers
1594 WHERE lower(name) = lower(:containername);
1595 if (sqlca.sqlerrd[2] != 1)
1596 return MR_CONTAINER_NO_PARENT;
1599 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1605 int check_mailman_listname(char *name, const char *suffix)
1608 EXEC SQL BEGIN DECLARE SECTION;
1610 EXEC SQL END DECLARE SECTION;
1612 p = strstr(name, suffix);
1615 if (strlen(name) == (p - name + strlen(suffix)))
1617 /* list is of the form "name-suffix" */
1619 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
1620 WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1;