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;
79 if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1)
81 if ((err = set_next_object_id("unix_uid", USERS_TABLE, 1)))
83 EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'unix_uid';
84 if (sqlca.sqlerrd[2] != 1)
86 sprintf(argv[row], "%d", nuid);
89 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1)
90 sprintf(argv[0], "#%s", argv[row]);
92 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
95 /* If this is an UPDATE query, we're done. */
99 /* For an add query, we need to fill in the creator id. */
100 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
105 /* setup_dusr - verify that the user is no longer being referenced
106 * and may safely be deleted.
109 int setup_dusr(struct query *q, char *argv[], client *cl)
111 EXEC SQL BEGIN DECLARE SECTION;
113 char resv[USERS_RESERVATIONS_SIZE];
114 EXEC SQL END DECLARE SECTION;
116 id = *(int *)argv[0];
118 /* For now, only allow users to be deleted if their status is
119 * one of 0, 4, or 8 (the various registerable statuses)
120 * and we have no reservations about deleting them.
122 EXEC SQL SELECT status, reservations INTO :flag, :resv
123 FROM users WHERE users_id = :id;
124 if ((flag != 0 && flag != 4 && flag != 8) || *resv)
127 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
128 WHERE member_id = :id AND member_type = 'USER';
131 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys
135 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
136 WHERE acl_id = :id AND acl_type = 'USER';
139 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
140 WHERE acl_id = :id AND acl_type = 'USER';
143 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
144 WHERE acl_id = :id AND acl_type = 'USER';
150 EXEC SQL DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
151 EXEC SQL DELETE FROM krbmap WHERE users_id = :id;
156 /* setup_dpob: Take care of keeping track of the post office usage.
158 int setup_dpob(struct query *q, char *argv[], client *cl)
160 EXEC SQL BEGIN DECLARE SECTION;
162 char type[USERS_POTYPE_SIZE];
163 EXEC SQL END DECLARE SECTION;
165 user = *(int *)argv[0];
166 EXEC SQL SELECT potype, pop_id INTO :type, :id FROM users
167 WHERE users_id = :user;
171 if (!strcmp(strtrim(type), "POP"))
172 set_pop_usage(id, -1);
177 /* setup_dmac - verify that the machine is no longer being referenced
178 * and may safely be deleted.
181 int setup_dmac(struct query *q, char *argv[], client *cl)
183 EXEC SQL BEGIN DECLARE SECTION;
185 EXEC SQL END DECLARE SECTION;
187 id = *(int *)argv[0];
189 EXEC SQL SELECT status INTO :flag FROM machine
193 EXEC SQL SELECT COUNT(login) INTO :cnt FROM users
194 WHERE potype = 'POP' AND pop_id = :id;
197 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
201 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
205 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
209 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printers
213 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
217 EXEC SQL SELECT COUNT(rq) INTO :cnt FROM printers
221 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
225 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM hostalias
229 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
230 WHERE member_type = 'MACHINE' and member_id = :id;
234 EXEC SQL DELETE FROM mcmap WHERE mach_id = :id;
238 EXEC SQL DELETE FROM mcntmap WHERE mach_id = :id;
244 /* setup_asnt - verify that the data entered for the subnet is sane.
245 * In particular, make sure that the "low" and "high" addresses are
246 * correctly ordered, i.e., high > low.
249 int setup_asnt(struct query *q, char *argv[], client *cl)
251 int high, low, row, status;
252 char *account_number;
254 /* Check for asnt or usnt. */
255 if (q->type == APPEND)
260 low = atoi(argv[row + 7]);
261 high = atoi(argv[row + 8]);
262 status = atoi(argv[row + 2]);
263 account_number = argv[row + 4];
265 /* Don't allow Private subnets to be created without a valid billing
268 if (status == SNET_STATUS_PRIVATE_10MBPS ||
269 status == SNET_STATUS_PRIVATE_100MBPS ||
270 status == SNET_STATUS_PRIVATE_1000MBPS)
272 EXEC SQL SELECT account_number FROM accountnumbers
273 WHERE account_number = :account_number;
274 if (sqlca.sqlcode == SQL_NO_MATCH)
275 return MR_ACCOUNT_NUMBER;
278 /* Special case 0.0.0.0 and 255.255.255.255 */
279 if (!(low == 0 || low == -1 || high == 0 || high == -1))
283 /* If this is update_subnet, we're done. */
287 /* For an add_subnet query, allocate and fill in a new snet_id */
288 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
294 /* setup_dsnt - verify that the subnet is no longer being referenced
295 * and may safely be deleted.
298 int setup_dsnt(struct query *q, char *argv[], client *cl)
300 EXEC SQL BEGIN DECLARE SECTION;
302 EXEC SQL END DECLARE SECTION;
304 id = *(int *)argv[0];
305 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM machine
313 /* setup_dclu - verify that the cluster is no longer being referenced
314 * and may safely be deleted.
317 int setup_dclu(struct query *q, char *argv[], client *cl)
319 EXEC SQL BEGIN DECLARE SECTION;
321 EXEC SQL END DECLARE SECTION;
323 id = *(int *)argv[0];
324 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcmap
328 EXEC SQL SELECT COUNT(clu_id) INTO :cnt FROM svc
338 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
339 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
340 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
341 * a -1 there. Remember that this is also used for ulis, with the indexes
342 * at 6 & 7. Also check that the list name does not contain uppercase
343 * characters, control characters, @, or :.
345 * Newlines in list descriptions do bad things to the aliases file
346 * moira generates, so make sure the description doesn't contain any, too.
349 static int badlistchars[] = {
350 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
351 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
352 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, /* SPACE - / */
353 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, /* 0 - ? */
354 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
355 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, /* P - _ */
356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, /* p - ^? */
358 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
359 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
360 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
361 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
362 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
363 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
364 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
365 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
368 static const char *mailman_suffixes[] = { "-admin", "-owner", "-request",
369 "-bounces", "-confirm", "-join",
370 "-leave", "-subscribe",
371 "-unsubscribe", NULL };
373 int setup_alis(struct query *q, char *argv[], client *cl)
375 EXEC SQL BEGIN DECLARE SECTION;
376 int ngid, cnt, mailman, mailman_id;
378 EXEC SQL END DECLARE SECTION;
380 int idx, err, best = -1, usage, i;
382 if (!strcmp(q->shortname, "alis"))
384 else if (!strcmp(q->shortname, "ulis"))
389 desc = argv[9 + idx];
390 else if (q->version == 3)
391 desc = argv[10 + idx];
392 else if (q->version == 4)
393 desc = argv[12 + idx];
394 else if (q->version >= 10)
395 desc = argv[14 + idx];
399 EXEC SQL BEGIN DECLARE SECTION;
400 int lid = *(int *)argv[0];
401 EXEC SQL END DECLARE SECTION;
403 if (acl_access_check(lid, cl))
407 for (p = (unsigned char *) name; *p; p++)
409 if (badlistchars[*p])
413 for (p = (unsigned char *) desc; *p; p++)
419 /* Check that it doesn't conflict with a pre-existing weirdly-cased
421 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
422 WHERE LOWER(name) = :name AND name != :name;
426 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
428 if (atoi(argv[5 + idx]))
430 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
432 EXEC SQL SELECT value INTO :ngid FROM numvalues
436 sprintf(argv[6 + idx], "%d", ngid);
439 strcpy(argv[6 + idx], "-1");
442 /* Don't let someone rename a list to one of the magic mailman names
443 * (foo-admin, etc) if foo already exists as a mailman list.
445 for (i = 0; mailman_suffixes[i]; i++)
447 if ((err = check_mailman_listname(name, mailman_suffixes[i]))
452 if (q->version >= 10)
454 /* Don't let them take this name for a mailman list if we can't
455 * reserve the -admin, -owner, and -request names.
457 if (atoi(argv[8 + idx]))
459 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
460 WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
461 name = :name || '-request');
466 /* Handle the [ANY] case for mailman server. */
467 mailman_id = *(int *)argv[9 + idx];
468 if (mailman_id == -1)
470 EXEC SQL DECLARE csr_mailman CURSOR FOR
471 SELECT mach_id FROM serverhosts WHERE service = 'MAILMAN'
475 EXEC SQL OPEN csr_mailman;
481 EXEC SQL FETCH csr_mailman INTO :mailman_id;
485 EXEC SQL SELECT COUNT(name) INTO :usage FROM list
486 WHERE mailman_id = :mailman_id;
488 if (best < 0 || usage < best)
491 *(int *)argv[9 + idx] = mailman_id;
495 EXEC SQL CLOSE csr_mailman;
505 /* Client too old to know about the mailman code.
506 * Use existing value of mailman boolean in the table.
508 EXEC SQL SELECT mailman INTO :mailman FROM list WHERE name = :name;
511 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
512 WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
513 name = :name || '-request');
519 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
526 /* setup_dlis - verify that the list is no longer being referenced
527 * and may safely be deleted.
530 int setup_dlis(struct query *q, char *argv[], client *cl)
533 EXEC SQL BEGIN DECLARE SECTION;
535 EXEC SQL END DECLARE SECTION;
537 id = *(int *)argv[0];
539 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
540 WHERE member_id = :id AND member_type = 'LIST';
544 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
545 WHERE member_id = :id AND member_type = 'LIST';
549 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
554 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
558 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
562 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
563 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
567 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
568 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
572 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
573 WHERE acl_id = :id AND acl_type = 'LIST';
577 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
578 WHERE entity_id = :id AND type = 'GROUP';
582 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
583 WHERE acl_id = :id AND acl_type = 'LIST';
587 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
588 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
589 OR z.sub_type = 'LIST' AND z.sub_id = :id
590 OR z.iws_type = 'LIST' AND z.iws_id = :id
591 OR z.iui_type = 'LIST' AND z.iui_id = :id
592 OR z.owner_type = 'LIST' and z.owner_id = :id;
596 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
597 WHERE lpc_acl = :id OR ac = :id;
601 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
602 WHERE owner_type = 'LIST' AND owner_id = :id
607 EXEC SQL SELECT count(name) INTO :cnt FROM containers
608 WHERE acl_id = :id AND acl_type = 'LIST';
612 EXEC SQL SELECT count(name) INTO :cnt FROM containers
613 WHERE memacl_id = :id AND memacl_type = 'LIST';
621 /* setup_dsin - verify that the service is no longer being referenced
622 * and may safely be deleted.
625 int setup_dsin(struct query *q, char *argv[], client *cl)
627 EXEC SQL BEGIN DECLARE SECTION;
630 EXEC SQL END DECLARE SECTION;
633 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
634 WHERE service = UPPER(:svrname);
638 EXEC SQL SELECT inprogress INTO :ec FROM servers
639 WHERE name = UPPER(:svrname);
649 /* setup_dshi - verify that the service-host is no longer being referenced
650 * and may safely be deleted.
653 int setup_dshi(struct query *q, char *argv[], client *cl)
655 EXEC SQL BEGIN DECLARE SECTION;
658 EXEC SQL END DECLARE SECTION;
661 id = *(int *)argv[1];
663 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
664 WHERE service = UPPER(:svrname) AND mach_id = :id;
675 ** setup_add_filesys - verify existance of referenced file systems
681 ** argv[5] - rwaccess
686 ** - for type = NFS/IMAP:
687 ** * extract directory prefix from name
688 ** * verify mach_id/dir in nfsphys
689 ** * verify rwaccess in {r, w, R, W}
691 ** Side effect: sets variable _var_phys_id to the ID of the physical
692 ** filesystem (nfsphys_id for NFS, 0 for RVD)
695 ** MR_NFS - specified directory not exported
696 ** MR_FILESYS_ACCESS - invalid filesys access
700 EXEC SQL BEGIN DECLARE SECTION;
702 EXEC SQL END DECLARE SECTION;
704 int setup_afil(struct query *q, char *argv[], client *cl)
708 EXEC SQL BEGIN DECLARE SECTION;
710 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
711 EXEC SQL END DECLARE SECTION;
714 mach_id = *(int *)argv[2];
719 sprintf(ftype, "fs_access_%s", type);
720 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
721 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
725 return MR_FILESYS_ACCESS;
727 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
730 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
731 return check_nfs(mach_id, name, rwaccess);
737 /* Verify the arguments, depending on the FStype. Also, if this is an
738 * NFS filesystem, then update any quotas for that filesystem to reflect
742 int setup_ufil(struct query *q, char *argv[], client *cl)
746 EXEC SQL BEGIN DECLARE SECTION;
747 int fid, total, who, ok;
748 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
749 short int total_null;
750 EXEC SQL END DECLARE SECTION;
754 mach_id = *(int *)argv[3];
757 fid = *(int *)argv[0];
761 sprintf(ftype, "fs_access_%s", type);
762 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
763 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
767 return MR_FILESYS_ACCESS;
769 EXEC SQL SELECT type INTO :ftype FROM filesys
770 WHERE filsys_id = :fid;
774 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
776 status = check_nfs(mach_id, name, access);
777 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
778 WHERE filsys_id = :fid;
783 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
784 && strcmp(strtrim(ftype), "ERR"))
787 EXEC SQL DELETE FROM quota
788 WHERE type = 'ANY' AND filsys_id = :fid;
789 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
790 WHERE filsys_id = :fid AND phys_id != 0;
793 if (!total_null && (total != 0))
795 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
796 type, modtime, modby, modwith)
797 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
804 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
812 /* Find the NFS physical partition that the named directory is on.
813 * This is done by comparing the dir against the mount point of the
814 * partition. To make sure we get the correct match when there is
815 * more than one, we sort the query in reverse order by dir name.
818 int check_nfs(int mach_id, char *name, char *access)
820 EXEC SQL BEGIN DECLARE SECTION;
821 char dir[NFSPHYS_DIR_SIZE];
823 EXEC SQL END DECLARE SECTION;
829 EXEC SQL DECLARE csr101 CURSOR FOR
830 SELECT nfsphys_id, dir FROM nfsphys
835 EXEC SQL OPEN csr101;
840 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
857 EXEC SQL CLOSE csr101;
864 /* setup_dfil: free any quota records and fsgroup info associated with
865 * a filesystem when it is deleted. Also adjust the allocation numbers.
868 int setup_dfil(struct query *q, char **argv, client *cl)
870 EXEC SQL BEGIN DECLARE SECTION;
871 int id, total, phys_id;
873 EXEC SQL END DECLARE SECTION;
875 id = *(int *)argv[0];
876 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
877 WHERE filsys_id = :id;
882 /** What if there are multiple phys_id's per f/s? (bad data) **/
883 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
884 WHERE filsys_id = :id;
885 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
886 WHERE nfsphys_id = :phys_id;
889 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
890 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
891 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
898 /* setup_dnfp: check to see that the nfs physical partition does not have
899 * any filesystems assigned to it before allowing it to be deleted.
902 int setup_dnfp(struct query *q, char **argv, client *cl)
904 EXEC SQL BEGIN DECLARE SECTION;
907 EXEC SQL END DECLARE SECTION;
909 id = *(int *)argv[0];
911 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
912 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
913 AND np.mach_id = :id AND np.dir = :dir;
922 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
923 * argv[0] = filsys_id
924 * argv[1] = type if "update_quota" or "delete_quota"
925 * argv[2 or 1] = users_id or list_id
928 int setup_dqot(struct query *q, char **argv, client *cl)
930 EXEC SQL BEGIN DECLARE SECTION;
931 int quota, fs, id, physid;
933 EXEC SQL END DECLARE SECTION;
935 fs = *(int *)argv[0];
936 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
939 id = *(int *)argv[2];
944 id = *(int *)argv[1];
947 EXEC SQL SELECT quota INTO :quota FROM quota
948 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
949 EXEC SQL SELECT phys_id INTO :physid FROM filesys
950 WHERE filsys_id = :fs;
951 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
952 WHERE nfsphys_id = :physid;
961 * This routine fetches an appropriate value from the numvalues table.
962 * It is a little hack to get around the fact that SQL doesn't let you
963 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
965 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
966 * from within a setup_...() routine with the appropriate arguments.
968 * Correct functioning of this routine may depend on the assumption
969 * that this query is an APPEND.
972 int prefetch_value(struct query *q, char **argv, client *cl)
974 EXEC SQL BEGIN DECLARE SECTION;
975 char *name = q->validate->object_id;
977 EXEC SQL END DECLARE SECTION;
978 int status, limit, argc;
980 /* set next object id, limiting it if necessary */
981 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
982 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
985 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
988 /* fetch object id */
989 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
992 if (sqlca.sqlerrd[2] != 1)
995 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
996 sprintf(argv[argc], "%d", value);
1001 /* prefetch_filesys():
1002 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
1003 * Appends the filsys_id and the phys_id to the argv so they can be
1004 * referenced in an INSERT into a table other than filesys. Also
1005 * see comments at prefetch_value().
1007 * Assumes the existence of a row where filsys_id = argv[0], since a
1008 * filesys label has already been resolved to a filsys_id.
1010 int prefetch_filesys(struct query *q, char **argv, client *cl)
1012 EXEC SQL BEGIN DECLARE SECTION;
1014 EXEC SQL END DECLARE SECTION;
1017 fid = *(int *)argv[0];
1018 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
1022 argc = q->argc + q->vcnt;
1023 sprintf(argv[argc++], "%d", phid);
1024 sprintf(argv[argc], "%d", fid);
1033 int setup_ahst(struct query *q, char **argv, client *cl)
1035 EXEC SQL BEGIN DECLARE SECTION;
1036 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
1037 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
1038 int value, id, ssaddr, smask, shigh, slow, cnt;
1039 unsigned int saddr, mask, high, low;
1040 EXEC SQL END DECLARE SECTION;
1042 struct in_addr addr;
1044 id = *(int *)argv[0];
1046 if (!strcmp(q->shortname, "uhst"))
1049 EXEC SQL SELECT name, vendor, model, os
1050 INTO :oldname, :vendor, :model, :os
1051 FROM machine WHERE mach_id = :id;
1058 else if (q->version >= 6 && q->version < 8)
1063 /* Sanity check name, vendor, model, and os. */
1064 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
1065 !hostname_check(argv[row]))
1067 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
1068 !hostinfo_check(argv[row + 1], 0))
1070 if ((row == 0 || strcasecmp(argv[3], model)) &&
1071 !hostinfo_check(argv[row + 2], 1))
1073 if ((row == 0 || strcasecmp(argv[4], os)) &&
1074 !hostinfo_check(argv[row + 3], 0))
1077 /* check for duplicate name */
1079 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
1080 WHERE name = UPPER(:name);
1087 if (!strcmp(argv[9 + row + idx], "unassigned"))
1089 else if (!strcmp(argv[9 + row + idx], "unique"))
1091 if (*(int *)argv[8 + row + idx] == 0)
1098 value = ntohl(inet_addr(argv[9 + row + idx]));
1107 * an address or unique was specified.
1109 id = *(int *)argv[8 + row + idx];
1110 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1111 :shigh, :slow FROM subnet WHERE snet_id = :id;
1114 saddr = (unsigned) ssaddr;
1115 mask = (unsigned) smask;
1116 high = (unsigned) shigh;
1117 low = (unsigned) slow;
1121 * someone specified an IP address for the host record
1123 if ((value & mask) != saddr || value < low || value > high)
1126 * run the address argument through inet_addr(). This
1127 * has the effect that any out of bounds host addrs will
1128 * be converted to a valid host addr. We do this now
1129 * so that the uniqueness check works. We should also
1130 * link in an inet_addr() that returns an error for
1133 addr.s_addr = inet_addr(argv[9 + row + idx]);
1134 name = inet_ntoa(addr);
1135 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1136 WHERE address = :name;
1142 * make IP address is unique. If this a modify request
1143 * (row == 1), then we expect one record to exist.
1145 if (row == 0 || (row == 1 && cnt > 1))
1147 if (row == 1 && cnt == 1)
1149 EXEC SQL SELECT mach_id INTO :id FROM machine
1150 WHERE address = :name;
1151 if (id != *(int *)argv[0])
1159 * a "unique" address was specified. Walk through the
1160 * range specified in the network record, return
1161 * error if no room left.
1163 for (id = low; id <= high; id++)
1165 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1167 addr.s_addr = htonl(id);
1168 name = inet_ntoa(addr);
1169 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1170 WHERE address = :name;
1182 * we have an address in value. Convert it to a string and store it.
1184 addr.s_addr = htonl(value);
1185 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1188 strcpy(argv[9 + row + idx], "unassigned");
1190 /* status checking */
1191 value = atoi(argv[7 + row + idx]);
1192 if (row == 0 && !(value == 1 || value == 0))
1196 id = *(int *)argv[0];
1197 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1202 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1203 WHERE mach_id = :id;
1208 * If this is an update_host query, we're done.
1214 * For an add_host query, allocate and fill in a new machine id,
1215 * and then insert the creator id.
1217 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1220 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1228 int setup_ahal(struct query *q, char **argv, client *cl)
1230 EXEC SQL BEGIN DECLARE SECTION;
1233 EXEC SQL END DECLARE SECTION;
1237 if (!hostname_check(argv[0]))
1240 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1241 name = UPPER(:name);
1250 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1253 int setup_uhha(struct query *q, char **argv, client *cl)
1255 EXEC SQL BEGIN DECLARE SECTION;
1256 char *hwaddr = argv[1];
1258 EXEC SQL END DECLARE SECTION;
1261 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1263 for (p = hwaddr; *p; p++)
1270 if (p != hwaddr + 12)
1273 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1274 FROM machine WHERE hwaddr = :hwaddr;
1276 return MR_NOT_UNIQUE;
1282 /* setup_aprn(): Make sure name/duplexname don't conflict with
1283 * anything. If [ANY] was specified for the spooling host, pick the
1284 * least loaded print server that serves this kind of printer.
1286 int setup_aprn(struct query *q, char **argv, client *cl)
1290 EXEC SQL BEGIN DECLARE SECTION;
1291 int mid, usage, count;
1292 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1293 EXEC SQL END DECLARE SECTION;
1295 /* Check for aprn or uprn. */
1296 if (q->type == APPEND)
1301 name = argv[PRN_NAME + row];
1302 duplexname = argv[PRN_DUPLEXNAME + row];
1309 if (q->type == APPEND)
1311 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1312 WHERE name = :name OR duplexname = :name;
1316 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1317 WHERE ( name = :name OR duplexname = :name )
1318 AND name != :oldname;
1323 return MR_NOT_UNIQUE;
1328 if (q->type == APPEND)
1330 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1331 WHERE name = :duplexname OR duplexname = :duplexname;
1335 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1336 WHERE ( name = :duplexname OR duplexname = :duplexname )
1337 AND name != :oldname;
1343 return MR_NOT_UNIQUE;
1346 if (!strcmp(name, duplexname))
1347 return MR_NOT_UNIQUE;
1349 mid = *(int *)argv[PRN_RM + row];
1352 EXEC SQL DECLARE csr_rm CURSOR FOR
1353 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1355 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1357 AND ps.printer_types = s.string_id;
1360 EXEC SQL OPEN csr_rm;
1366 EXEC SQL FETCH csr_rm INTO :mid, :types;
1370 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1372 if (!strcasecmp(argv[PRN_TYPE + row], p))
1374 EXEC SQL SELECT COUNT(name) INTO :usage
1375 FROM printers WHERE rm = :mid;
1377 if (best < 0 || usage < best)
1380 *(int *)argv[PRN_RM + row] = mid;
1386 EXEC SQL CLOSE csr_rm;
1395 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1396 WHERE mach_id = :mid;
1404 int setup_dpsv(struct query *q, char **argv, client *cl)
1407 EXEC SQL BEGIN DECLARE SECTION;
1409 EXEC SQL END DECLARE SECTION;
1411 id = *(int *)argv[0];
1413 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1421 int setup_dcon(struct query *q, char *argv[], client *cl)
1423 EXEC SQL BEGIN DECLARE SECTION;
1425 char containername[CONTAINERS_NAME_SIZE];
1426 EXEC SQL END DECLARE SECTION;
1428 id = *(int *)argv[0];
1429 /* check to see if there are machines in this container */
1430 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1435 /* check to see if there are subcontainers in this container */
1437 /* get the container name */
1439 EXEC SQL SELECT name INTO :containername
1443 /* trim off the trailing spaces */
1444 strcpy(containername, strtrim(containername));
1446 EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1447 WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
1457 int setup_scli(struct query *q, char *argv[], client *cl)
1459 EXEC SQL BEGIN DECLARE SECTION;
1460 int cnt_id, list_id;
1461 EXEC SQL END DECLARE SECTION;
1463 cnt_id = *(int *)argv[0];
1464 /* Check if someone has already set the list for this container */
1465 EXEC SQL SELECT list_id INTO :list_id FROM containers
1466 WHERE cnt_id = :cnt_id;
1477 * validate the rfc1035/rfc1123-ness of a hostname
1480 int hostname_check(char *name)
1485 /* Sanity check name: must contain only letters, numerals, and
1486 * hyphen, and not start or end with a hyphen. Also make sure no
1487 * label (the thing the .s seperate) is longer than 63 characters,
1491 for (p = name, count = 0; *p; p++)
1494 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1495 (*p == '-' && p[1] == '.'))
1506 if (*(p - 1) == '-')
1511 int hostinfo_check(char *info, int num)
1518 /* Sanity check host hostinfo: must start with a letter (or number
1519 * if num is true), contain only letters, numerals, and hyphen, and
1520 * not end with a hyphen.
1523 if (!isalpha(*info) && (!num || !isdigit(*info)))
1525 for (p = info; *p; p++)
1527 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1528 (*p == '-' && p[1] == '.'))
1531 if (!isalnum(*(p - 1)))
1535 int setup_acon(struct query *q, char *argv[], client *cl)
1537 EXEC SQL BEGIN DECLARE SECTION;
1538 char containername[CONTAINERS_NAME_SIZE];
1539 EXEC SQL END DECLARE SECTION;
1543 memset(containername, 0, sizeof(containername));
1544 strcpy(containername, argv[0]);
1545 ptr = strrchr(containername, '/');
1546 /* sub container, check for parents */
1550 EXEC SQL SELECT * FROM containers
1551 WHERE lower(name) = lower(:containername);
1552 if (sqlca.sqlerrd[2] != 1)
1553 return MR_CONTAINER_NO_PARENT;
1556 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1562 int check_mailman_listname(char *name, const char *suffix)
1565 EXEC SQL BEGIN DECLARE SECTION;
1567 EXEC SQL END DECLARE SECTION;
1569 p = strstr(name, suffix);
1572 if (strlen(name) == (p - name + strlen(suffix)))
1574 /* list is of the form "name-suffix" */
1576 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
1577 WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1;