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, lid;
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 lid = *(int *)argv[0];
401 if (acl_access_check(lid, cl))
405 for (p = (unsigned char *) name; *p; p++)
407 if (badlistchars[*p])
411 for (p = (unsigned char *) desc; *p; p++)
417 /* Check that it doesn't conflict with a pre-existing weirdly-cased
419 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
420 WHERE LOWER(name) = :name AND name != :name;
424 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1)
426 if (atoi(argv[5 + idx]))
428 if ((err = set_next_object_id("gid", LIST_TABLE, 1)))
430 EXEC SQL SELECT value INTO :ngid FROM numvalues
434 sprintf(argv[6 + idx], "%d", ngid);
437 strcpy(argv[6 + idx], "-1");
440 /* Don't let someone rename a list to one of the magic mailman names
441 * (foo-admin, etc) if foo already exists as a mailman list.
443 for (i = 0; mailman_suffixes[i]; i++)
445 if ((err = check_mailman_listname(name, mailman_suffixes[i]))
450 if (q->version >= 10)
452 /* Don't let them take this name for a mailman list if we can't
453 * reserve the -admin, -owner, and -request names.
455 if (atoi(argv[8 + idx]))
457 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
458 WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
459 name = :name || '-request');
464 /* Handle the [ANY] case for mailman server. */
465 mailman_id = *(int *)argv[9 + idx];
466 if (mailman_id == -1)
468 EXEC SQL DECLARE csr_mailman CURSOR FOR
469 SELECT mach_id FROM serverhosts WHERE service = 'MAILMAN'
473 EXEC SQL OPEN csr_mailman;
479 EXEC SQL FETCH csr_mailman INTO :mailman_id;
483 EXEC SQL SELECT COUNT(name) INTO :usage FROM list
484 WHERE mailman_id = :mailman_id;
486 if (best < 0 || usage < best)
489 *(int *)argv[9 + idx] = mailman_id;
493 EXEC SQL CLOSE csr_mailman;
503 /* Client too old to know about the mailman code.
504 * Use existing value of mailman boolean in the table.
505 * Don't do this for add_list from an old client, since the row
506 * they're creating won't exist yet, and there's no way for them to
507 * create a list with the mailman bit set, anyway.
511 EXEC SQL SELECT mailman INTO :mailman FROM list WHERE list_id = :lid;
514 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
515 WHERE (name = :name || '-admin' OR name = :name || '-owner' OR
516 name = :name || '-request');
523 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
530 /* setup_dlis - verify that the list is no longer being referenced
531 * and may safely be deleted.
534 int setup_dlis(struct query *q, char *argv[], client *cl)
537 EXEC SQL BEGIN DECLARE SECTION;
539 EXEC SQL END DECLARE SECTION;
541 id = *(int *)argv[0];
543 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
544 WHERE member_id = :id AND member_type = 'LIST';
548 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
549 WHERE member_id = :id AND member_type = 'LIST';
553 EXEC SQL SELECT COUNT(member_id) INTO :cnt FROM imembers
558 EXEC SQL SELECT COUNT(label) INTO :cnt FROM filesys WHERE owners = :id;
562 EXEC SQL SELECT COUNT(tag) INTO :cnt FROM capacls WHERE list_id = :id;
566 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
567 WHERE acl_id = :id AND acl_type = 'LIST' AND list_id != :id;
571 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
572 WHERE memacl_id = :id AND memacl_type = 'LIST' AND list_id != :id;
576 EXEC SQL SELECT COUNT(name) INTO :cnt FROM servers
577 WHERE acl_id = :id AND acl_type = 'LIST';
581 EXEC SQL SELECT COUNT(entity_id) INTO :cnt FROM quota
582 WHERE entity_id = :id AND type = 'GROUP';
586 EXEC SQL SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
587 WHERE acl_id = :id AND acl_type = 'LIST';
591 EXEC SQL SELECT COUNT(class) INTO :cnt FROM zephyr z
592 WHERE z.xmt_type = 'LIST' AND z.xmt_id = :id
593 OR z.sub_type = 'LIST' AND z.sub_id = :id
594 OR z.iws_type = 'LIST' AND z.iws_id = :id
595 OR z.iui_type = 'LIST' AND z.iui_id = :id
596 OR z.owner_type = 'LIST' and z.owner_id = :id;
600 EXEC SQL SELECT COUNT(name) INTO :cnt FROM printers
601 WHERE lpc_acl = :id OR ac = :id;
605 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM printservers
606 WHERE owner_type = 'LIST' AND owner_id = :id
611 EXEC SQL SELECT count(name) INTO :cnt FROM containers
612 WHERE acl_id = :id AND acl_type = 'LIST';
616 EXEC SQL SELECT count(name) INTO :cnt FROM containers
617 WHERE memacl_id = :id AND memacl_type = 'LIST';
625 /* setup_dsin - verify that the service is no longer being referenced
626 * and may safely be deleted.
629 int setup_dsin(struct query *q, char *argv[], client *cl)
631 EXEC SQL BEGIN DECLARE SECTION;
634 EXEC SQL END DECLARE SECTION;
637 EXEC SQL SELECT COUNT(service) INTO :cnt FROM serverhosts
638 WHERE service = UPPER(:svrname);
642 EXEC SQL SELECT inprogress INTO :ec FROM servers
643 WHERE name = UPPER(:svrname);
653 /* setup_dshi - verify that the service-host is no longer being referenced
654 * and may safely be deleted.
657 int setup_dshi(struct query *q, char *argv[], client *cl)
659 EXEC SQL BEGIN DECLARE SECTION;
662 EXEC SQL END DECLARE SECTION;
665 id = *(int *)argv[1];
667 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
668 WHERE service = UPPER(:svrname) AND mach_id = :id;
679 ** setup_add_filesys - verify existance of referenced file systems
685 ** argv[5] - rwaccess
690 ** - for type = NFS/IMAP:
691 ** * extract directory prefix from name
692 ** * verify mach_id/dir in nfsphys
693 ** * verify rwaccess in {r, w, R, W}
695 ** Side effect: sets variable _var_phys_id to the ID of the physical
696 ** filesystem (nfsphys_id for NFS, 0 for RVD)
699 ** MR_NFS - specified directory not exported
700 ** MR_FILESYS_ACCESS - invalid filesys access
704 EXEC SQL BEGIN DECLARE SECTION;
706 EXEC SQL END DECLARE SECTION;
708 int setup_afil(struct query *q, char *argv[], client *cl)
712 EXEC SQL BEGIN DECLARE SECTION;
714 char ftype[FILESYS_TYPE_SIZE + 10], *rwaccess;
715 EXEC SQL END DECLARE SECTION;
718 mach_id = *(int *)argv[2];
723 sprintf(ftype, "fs_access_%s", type);
724 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
725 WHERE name = :ftype AND type = 'TYPE' and trans = :rwaccess;
729 return MR_FILESYS_ACCESS;
731 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
734 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
735 return check_nfs(mach_id, name, rwaccess);
741 /* Verify the arguments, depending on the FStype. Also, if this is an
742 * NFS filesystem, then update any quotas for that filesystem to reflect
746 int setup_ufil(struct query *q, char *argv[], client *cl)
750 EXEC SQL BEGIN DECLARE SECTION;
751 int fid, total, who, ok;
752 char *entity, ftype[FILESYS_TYPE_SIZE + 10], *access;
753 short int total_null;
754 EXEC SQL END DECLARE SECTION;
758 mach_id = *(int *)argv[3];
761 fid = *(int *)argv[0];
765 sprintf(ftype, "fs_access_%s", type);
766 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
767 WHERE name = :ftype AND type = 'TYPE' AND trans = :access;
771 return MR_FILESYS_ACCESS;
773 EXEC SQL SELECT type INTO :ftype FROM filesys
774 WHERE filsys_id = :fid;
778 if (!strcmp(type, "NFS") || !strcmp(type, "IMAP"))
780 status = check_nfs(mach_id, name, access);
781 EXEC SQL UPDATE quota SET phys_id = :_var_phys_id
782 WHERE filsys_id = :fid;
787 else if (!strcmp(type, "AFS") && strcmp(strtrim(ftype), "AFS")
788 && strcmp(strtrim(ftype), "ERR"))
791 EXEC SQL DELETE FROM quota
792 WHERE type = 'ANY' AND filsys_id = :fid;
793 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
794 WHERE filsys_id = :fid AND phys_id != 0;
797 if (!total_null && (total != 0))
799 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
800 type, modtime, modby, modwith)
801 VALUES (:total, :fid, 0, 0, 'ANY', SYSDATE, :who, :entity);
808 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
816 /* Find the NFS physical partition that the named directory is on.
817 * This is done by comparing the dir against the mount point of the
818 * partition. To make sure we get the correct match when there is
819 * more than one, we sort the query in reverse order by dir name.
822 int check_nfs(int mach_id, char *name, char *access)
824 EXEC SQL BEGIN DECLARE SECTION;
825 char dir[NFSPHYS_DIR_SIZE];
827 EXEC SQL END DECLARE SECTION;
833 EXEC SQL DECLARE csr101 CURSOR FOR
834 SELECT nfsphys_id, dir FROM nfsphys
839 EXEC SQL OPEN csr101;
844 EXEC SQL FETCH csr101 INTO :_var_phys_id, :dir;
861 EXEC SQL CLOSE csr101;
868 /* setup_dfil: free any quota records and fsgroup info associated with
869 * a filesystem when it is deleted. Also adjust the allocation numbers.
872 int setup_dfil(struct query *q, char **argv, client *cl)
874 EXEC SQL BEGIN DECLARE SECTION;
875 int id, total, phys_id;
877 EXEC SQL END DECLARE SECTION;
879 id = *(int *)argv[0];
880 EXEC SQL SELECT SUM (quota) INTO :total:none FROM quota
881 WHERE filsys_id = :id;
886 /** What if there are multiple phys_id's per f/s? (bad data) **/
887 EXEC SQL SELECT phys_id INTO :phys_id FROM filesys
888 WHERE filsys_id = :id;
889 EXEC SQL UPDATE nfsphys SET allocated = allocated - :total
890 WHERE nfsphys_id = :phys_id;
893 EXEC SQL DELETE FROM quota WHERE filsys_id = :id;
894 EXEC SQL DELETE FROM fsgroup WHERE filsys_id = :id;
895 EXEC SQL DELETE FROM fsgroup WHERE group_id = :id;
902 /* setup_dnfp: check to see that the nfs physical partition does not have
903 * any filesystems assigned to it before allowing it to be deleted.
906 int setup_dnfp(struct query *q, char **argv, client *cl)
908 EXEC SQL BEGIN DECLARE SECTION;
911 EXEC SQL END DECLARE SECTION;
913 id = *(int *)argv[0];
915 EXEC SQL SELECT count(fs.rowid) INTO :cnt FROM filesys fs, nfsphys np
916 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
917 AND np.mach_id = :id AND np.dir = :dir;
926 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
927 * argv[0] = filsys_id
928 * argv[1] = type if "update_quota" or "delete_quota"
929 * argv[2 or 1] = users_id or list_id
932 int setup_dqot(struct query *q, char **argv, client *cl)
934 EXEC SQL BEGIN DECLARE SECTION;
935 int quota, fs, id, physid;
937 EXEC SQL END DECLARE SECTION;
939 fs = *(int *)argv[0];
940 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota"))
943 id = *(int *)argv[2];
948 id = *(int *)argv[1];
951 EXEC SQL SELECT quota INTO :quota FROM quota
952 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
953 EXEC SQL SELECT phys_id INTO :physid FROM filesys
954 WHERE filsys_id = :fs;
955 EXEC SQL UPDATE nfsphys SET allocated = allocated - :quota
956 WHERE nfsphys_id = :physid;
965 * This routine fetches an appropriate value from the numvalues table.
966 * It is a little hack to get around the fact that SQL doesn't let you
967 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
969 * It is called from the query table as (*v->pre_rtn)(q, Argv, cl) or
970 * from within a setup_...() routine with the appropriate arguments.
972 * Correct functioning of this routine may depend on the assumption
973 * that this query is an APPEND.
976 int prefetch_value(struct query *q, char **argv, client *cl)
978 EXEC SQL BEGIN DECLARE SECTION;
979 char *name = q->validate->object_id;
981 EXEC SQL END DECLARE SECTION;
982 int status, limit, argc;
984 /* set next object id, limiting it if necessary */
985 if (!strcmp(name, "unix_uid") || !strcmp(name, "gid"))
986 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
989 if ((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
992 /* fetch object id */
993 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name = :name;
996 if (sqlca.sqlerrd[2] != 1)
999 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
1000 sprintf(argv[argc], "%d", value);
1005 /* prefetch_filesys():
1006 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
1007 * Appends the filsys_id and the phys_id to the argv so they can be
1008 * referenced in an INSERT into a table other than filesys. Also
1009 * see comments at prefetch_value().
1011 * Assumes the existence of a row where filsys_id = argv[0], since a
1012 * filesys label has already been resolved to a filsys_id.
1014 int prefetch_filesys(struct query *q, char **argv, client *cl)
1016 EXEC SQL BEGIN DECLARE SECTION;
1018 EXEC SQL END DECLARE SECTION;
1021 fid = *(int *)argv[0];
1022 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
1026 argc = q->argc + q->vcnt;
1027 sprintf(argv[argc++], "%d", phid);
1028 sprintf(argv[argc], "%d", fid);
1037 int setup_ahst(struct query *q, char **argv, client *cl)
1039 EXEC SQL BEGIN DECLARE SECTION;
1040 char *name, oldname[MACHINE_NAME_SIZE], vendor[MACHINE_VENDOR_SIZE];
1041 char model[MACHINE_MODEL_SIZE], os[MACHINE_OS_SIZE];
1042 int value, id, ssaddr, smask, shigh, slow, cnt;
1043 unsigned int saddr, mask, high, low;
1044 EXEC SQL END DECLARE SECTION;
1046 struct in_addr addr;
1048 id = *(int *)argv[0];
1050 if (!strcmp(q->shortname, "uhst"))
1053 EXEC SQL SELECT name, vendor, model, os
1054 INTO :oldname, :vendor, :model, :os
1055 FROM machine WHERE mach_id = :id;
1062 else if (q->version >= 6 && q->version < 8)
1067 /* Sanity check name, vendor, model, and os. */
1068 if ((row == 0 || strcasecmp(argv[1], oldname)) &&
1069 !hostname_check(argv[row]))
1071 if ((row == 0 || strcasecmp(argv[2], vendor)) &&
1072 !hostinfo_check(argv[row + 1], 0))
1074 if ((row == 0 || strcasecmp(argv[3], model)) &&
1075 !hostinfo_check(argv[row + 2], 1))
1077 if ((row == 0 || strcasecmp(argv[4], os)) &&
1078 !hostinfo_check(argv[row + 3], 0))
1081 /* check for duplicate name */
1083 EXEC SQL SELECT count(mach_id) INTO :cnt FROM hostalias
1084 WHERE name = UPPER(:name);
1091 if (!strcmp(argv[9 + row + idx], "unassigned"))
1093 else if (!strcmp(argv[9 + row + idx], "unique"))
1095 if (*(int *)argv[8 + row + idx] == 0)
1102 value = ntohl(inet_addr(argv[9 + row + idx]));
1111 * an address or unique was specified.
1113 id = *(int *)argv[8 + row + idx];
1114 EXEC SQL SELECT saddr, mask, high, low INTO :ssaddr, :smask,
1115 :shigh, :slow FROM subnet WHERE snet_id = :id;
1118 saddr = (unsigned) ssaddr;
1119 mask = (unsigned) smask;
1120 high = (unsigned) shigh;
1121 low = (unsigned) slow;
1125 * someone specified an IP address for the host record
1127 if ((value & mask) != saddr || value < low || value > high)
1130 * run the address argument through inet_addr(). This
1131 * has the effect that any out of bounds host addrs will
1132 * be converted to a valid host addr. We do this now
1133 * so that the uniqueness check works. We should also
1134 * link in an inet_addr() that returns an error for
1137 addr.s_addr = inet_addr(argv[9 + row + idx]);
1138 name = inet_ntoa(addr);
1139 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1140 WHERE address = :name;
1146 * make IP address is unique. If this a modify request
1147 * (row == 1), then we expect one record to exist.
1149 if (row == 0 || (row == 1 && cnt > 1))
1151 if (row == 1 && cnt == 1)
1153 EXEC SQL SELECT mach_id INTO :id FROM machine
1154 WHERE address = :name;
1155 if (id != *(int *)argv[0])
1163 * a "unique" address was specified. Walk through the
1164 * range specified in the network record, return
1165 * error if no room left.
1167 for (id = low; id <= high; id++)
1169 if (((id & 0xff) == 0) || ((id & 0xff) == 255))
1171 addr.s_addr = htonl(id);
1172 name = inet_ntoa(addr);
1173 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine
1174 WHERE address = :name;
1186 * we have an address in value. Convert it to a string and store it.
1188 addr.s_addr = htonl(value);
1189 strcpy(argv[9 + row + idx], inet_ntoa(addr));
1192 strcpy(argv[9 + row + idx], "unassigned");
1194 /* status checking */
1195 value = atoi(argv[7 + row + idx]);
1196 if (row == 0 && !(value == 1 || value == 0))
1200 id = *(int *)argv[0];
1201 EXEC SQL SELECT status INTO :cnt FROM machine WHERE mach_id = :id;
1206 EXEC SQL UPDATE machine SET statuschange = SYSDATE
1207 WHERE mach_id = :id;
1212 * If this is an update_host query, we're done.
1218 * For an add_host query, allocate and fill in a new machine id,
1219 * and then insert the creator id.
1221 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1224 sprintf(argv[q->argc + q->vcnt + 1], "%d", cl->client_id);
1232 int setup_ahal(struct query *q, char **argv, client *cl)
1234 EXEC SQL BEGIN DECLARE SECTION;
1237 EXEC SQL END DECLARE SECTION;
1241 if (!hostname_check(argv[0]))
1244 EXEC SQL SELECT count(mach_id) INTO :cnt FROM machine WHERE
1245 name = UPPER(:name);
1254 /* setup_uhha(): Check characters in hwaddr, and make sure it's not
1257 int setup_uhha(struct query *q, char **argv, client *cl)
1259 EXEC SQL BEGIN DECLARE SECTION;
1260 char *hwaddr = argv[1];
1262 EXEC SQL END DECLARE SECTION;
1265 if (*hwaddr && strcasecmp(hwaddr, "unknown"))
1267 for (p = hwaddr; *p; p++)
1274 if (p != hwaddr + 12)
1277 EXEC SQL SELECT COUNT(hwaddr) INTO :count
1278 FROM machine WHERE hwaddr = :hwaddr;
1280 return MR_NOT_UNIQUE;
1286 /* setup_aprn(): Make sure name/duplexname don't conflict with
1287 * anything. If [ANY] was specified for the spooling host, pick the
1288 * least loaded print server that serves this kind of printer.
1290 int setup_aprn(struct query *q, char **argv, client *cl)
1294 EXEC SQL BEGIN DECLARE SECTION;
1295 int mid, usage, count;
1296 char types[STRINGS_STRING_SIZE], *hwaddr, *name, *duplexname, *oldname;
1297 EXEC SQL END DECLARE SECTION;
1299 /* Check for aprn or uprn. */
1300 if (q->type == APPEND)
1305 name = argv[PRN_NAME + row];
1306 duplexname = argv[PRN_DUPLEXNAME + row];
1313 if (q->type == APPEND)
1315 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1316 WHERE name = :name OR duplexname = :name;
1320 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1321 WHERE ( name = :name OR duplexname = :name )
1322 AND name != :oldname;
1327 return MR_NOT_UNIQUE;
1332 if (q->type == APPEND)
1334 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1335 WHERE name = :duplexname OR duplexname = :duplexname;
1339 EXEC SQL SELECT COUNT(name) INTO :count FROM printers
1340 WHERE ( name = :duplexname OR duplexname = :duplexname )
1341 AND name != :oldname;
1347 return MR_NOT_UNIQUE;
1350 if (!strcmp(name, duplexname))
1351 return MR_NOT_UNIQUE;
1353 mid = *(int *)argv[PRN_RM + row];
1356 EXEC SQL DECLARE csr_rm CURSOR FOR
1357 SELECT ps.mach_id, s.string FROM printservers ps, strings s
1359 ( SELECT mach_id FROM serverhosts WHERE service = 'PRINT'
1361 AND ps.printer_types = s.string_id;
1364 EXEC SQL OPEN csr_rm;
1370 EXEC SQL FETCH csr_rm INTO :mid, :types;
1374 for (p = strtok(types, ", "); p; p = strtok(NULL, ", "))
1376 if (!strcasecmp(argv[PRN_TYPE + row], p))
1378 EXEC SQL SELECT COUNT(name) INTO :usage
1379 FROM printers WHERE rm = :mid;
1381 if (best < 0 || usage < best)
1384 *(int *)argv[PRN_RM + row] = mid;
1390 EXEC SQL CLOSE csr_rm;
1399 EXEC SQL SELECT mach_id INTO :mid FROM printservers
1400 WHERE mach_id = :mid;
1408 int setup_dpsv(struct query *q, char **argv, client *cl)
1411 EXEC SQL BEGIN DECLARE SECTION;
1413 EXEC SQL END DECLARE SECTION;
1415 id = *(int *)argv[0];
1417 EXEC SQL SELECT COUNT(rm) INTO :cnt FROM printers
1425 int setup_dcon(struct query *q, char *argv[], client *cl)
1427 EXEC SQL BEGIN DECLARE SECTION;
1429 char containername[CONTAINERS_NAME_SIZE];
1430 EXEC SQL END DECLARE SECTION;
1432 id = *(int *)argv[0];
1433 /* check to see if there are machines in this container */
1434 EXEC SQL SELECT COUNT(mach_id) INTO :cnt FROM mcntmap
1439 /* check to see if there are subcontainers in this container */
1441 /* get the container name */
1443 EXEC SQL SELECT name INTO :containername
1447 /* trim off the trailing spaces */
1448 strcpy(containername, strtrim(containername));
1450 EXEC SQL SELECT COUNT(cnt_id) INTO :cnt FROM containers
1451 WHERE LOWER(name) LIKE LOWER(:containername || '/' || '%');
1461 int setup_scli(struct query *q, char *argv[], client *cl)
1463 EXEC SQL BEGIN DECLARE SECTION;
1464 int cnt_id, list_id;
1465 EXEC SQL END DECLARE SECTION;
1467 cnt_id = *(int *)argv[0];
1468 /* Check if someone has already set the list for this container */
1469 EXEC SQL SELECT list_id INTO :list_id FROM containers
1470 WHERE cnt_id = :cnt_id;
1481 * validate the rfc1035/rfc1123-ness of a hostname
1484 int hostname_check(char *name)
1489 /* Sanity check name: must contain only letters, numerals, and
1490 * hyphen, and not start or end with a hyphen. Also make sure no
1491 * label (the thing the .s seperate) is longer than 63 characters,
1495 for (p = name, count = 0; *p; p++)
1498 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1499 (*p == '-' && p[1] == '.'))
1510 if (*(p - 1) == '-')
1515 int hostinfo_check(char *info, int num)
1522 /* Sanity check host hostinfo: must start with a letter (or number
1523 * if num is true), contain only letters, numerals, and hyphen, and
1524 * not end with a hyphen.
1527 if (!isalpha(*info) && (!num || !isdigit(*info)))
1529 for (p = info; *p; p++)
1531 if ((!isalnum(*p) && *p != '-' && *p != '.') ||
1532 (*p == '-' && p[1] == '.'))
1535 if (!isalnum(*(p - 1)))
1539 int setup_acon(struct query *q, char *argv[], client *cl)
1541 EXEC SQL BEGIN DECLARE SECTION;
1542 char containername[CONTAINERS_NAME_SIZE];
1543 EXEC SQL END DECLARE SECTION;
1547 memset(containername, 0, sizeof(containername));
1548 strcpy(containername, argv[0]);
1549 ptr = strrchr(containername, '/');
1550 /* sub container, check for parents */
1554 EXEC SQL SELECT * FROM containers
1555 WHERE lower(name) = lower(:containername);
1556 if (sqlca.sqlerrd[2] != 1)
1557 return MR_CONTAINER_NO_PARENT;
1560 if ((mr_errcode = prefetch_value(q, argv, cl)) != MR_SUCCESS)
1566 int check_mailman_listname(char *name, const char *suffix)
1569 EXEC SQL BEGIN DECLARE SECTION;
1571 EXEC SQL END DECLARE SECTION;
1573 p = strstr(name, suffix);
1576 if (strlen(name) == (p - name + strlen(suffix)))
1578 /* list is of the form "name-suffix" */
1580 EXEC SQL SELECT COUNT(name) INTO :cnt FROM list
1581 WHERE name = SUBSTR(:name, 1, :i) AND mailman = 1;