6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
13 static char *rcsid_qsupport_qc = "$Header$";
16 #include <mit-copyright.h>
19 #include "mr_server.h"
22 EXEC SQL INCLUDE SQLCA; /* SQL Communications Area */
23 EXEC SQL INCLUDE SQLDA; /* SQL Descriptor Area */
25 extern char *whoami, *strsave();
26 extern int ingres_errno, mr_errcode;
29 /* Specialized Access Routines */
31 /* access_user - verify that client name equals specified login name
33 * - since field validation routines are called first, a users_id is
34 * now in argv[0] instead of the login name.
37 access_user(q, argv, cl)
42 if (cl->users_id != *(int *)argv[0])
50 /* access_login - verify that client name equals specified login name
52 * argv[0...n] contain search info. q->
55 access_login(q, argv, cl)
61 EXEC SQL BEGIN DECLARE SECTION;
64 char stmt_1_str[SQL_LONG_STR];
65 EXEC SQL END DECLARE SECTION;
67 EXEC SQL DECLARE stmt_1 STATEMENT;
69 build_qual(q->qual, q->argc, argv, qual);
72 "SELECT users_id INTO %s FROM users WHERE %s",
75 EXEC SQL PREPARE stmt_1 FROM :stmt_1_str;
76 EXEC SQL DESCRIBE stmt_1 INTO SQLDA;
77 EXEC SQL EXECUTE stmt_1;
78 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1 || id != cl->users_id)
87 /* access_list - check access for most list operations
89 * Inputs: argv[0] - list_id
91 * argv[2] - member ID (only for queries "amtl" and "dmfl")
92 * argv[7] - group IID (only for query "ulis")
95 * - check that client is a member of the access control list
96 * - OR, if the query is add_member_to_list or delete_member_from_list
97 * and the list is public, allow access if client = member
100 access_list(q, argv, cl)
105 EXEC SQL BEGIN DECLARE SECTION;
106 int list_id, acl_id, flags, rowcount, gid;
108 EXEC SQL END DECLARE SECTION;
110 int client_id, status;
112 list_id = *(int *)argv[0];
113 EXEC SQL SELECT acl_id, acl_type, gid, public
114 INTO :acl_id, :acl_type, :gid, :flags
116 WHERE list_id = :list_id;
117 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
120 /* parse client structure */
121 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
124 /* if amtl or dmfl and list is public allow client to add or delete self */
125 if (((!strcmp("amtl", q->shortname) && flags) ||
126 (!strcmp("dmfl", q->shortname))) &&
127 (!strcmp("USER", argv[1]))) {
128 if (*(int *)argv[2] == client_id) return(MR_SUCCESS);
129 /* if update_list, don't allow them to change the GID */
130 } else if (!strcmp("ulis", q->shortname)) {
131 if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
132 (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
136 /* check for client in access control list */
137 status = find_member(acl_type, acl_id, client_type, client_id, 0);
138 if (!status) return(MR_PERM);
144 /* access_visible_list - allow access to list only if it is not hidden,
145 * or if the client is on the ACL
147 * Inputs: argv[0] - list_id
148 * cl - client identifier
151 access_visible_list(q, argv, cl)
156 EXEC SQL BEGIN DECLARE SECTION;
157 int list_id, acl_id, flags, rowcount;
159 EXEC SQL END DECLARE SECTION;
161 int client_id, status;
163 list_id = *(int *)argv[0];
164 EXEC SQL SELECT hidden, acl_id, acl_type
165 INTO :flags, :acl_id, :acl_type
167 WHERE list_id = :list_id;
168 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
174 /* parse client structure */
175 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
178 /* check for client in access control list */
179 status = find_member(acl_type, acl_id, client_type, client_id, 0);
187 /* access_vis_list_by_name - allow access to list only if it is not hidden,
188 * or if the client is on the ACL
190 * Inputs: argv[0] - list name
191 * cl - client identifier
194 access_vis_list_by_name(q, argv, cl)
199 EXEC SQL BEGIN DECLARE SECTION;
200 int acl_id, flags, rowcount;
201 char acl_type[9], *listname;
202 EXEC SQL END DECLARE SECTION;
204 int client_id, status;
207 EXEC SQL SELECT hidden, acl_id, acl_type
208 INTO :flags, :acl_id, :acl_type
210 WHERE name = :listname;
211 if (sqlca.sqlerrd[2] > 1) return(MR_WILDCARD);
212 if (sqlca.sqlcode == 100) return(MR_NO_MATCH);
216 /* parse client structure */
217 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
220 /* check for client in access control list */
221 status = find_member(acl_type, acl_id, client_type, client_id, 0);
229 /* access_member - allow user to access member of type "USER" and name matches
230 * username, or to access member of type "LIST" and list is one that user is
231 * on the acl of, or the list is visible.
234 access_member(q, argv, cl)
239 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
240 return(access_visible_list(q, &argv[1], cl));
242 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
243 if (cl->users_id == *(int *)argv[1])
251 /* access_qgli - special access routine for Qualified_get_lists. Allows
252 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
255 access_qgli(q, argv, cl)
260 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
266 /* access_service - allow access if user is on ACL of service. Don't
267 * allow access if a wildcard is used.
270 access_service(q, argv, cl)
275 EXEC SQL BEGIN DECLARE SECTION;
276 int acl_id, rowcount;
277 char *name, acl_type[9];
278 EXEC SQL END DECLARE SECTION;
279 int client_id, status;
284 EXEC SQL SELECT acl_id, acl_type
285 INTO :acl_id, :acl_type
288 if (sqlca.sqlerrd[2] > 1) return(MR_PERM);
289 /* parse client structure */
290 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
293 /* check for client in access control list */
294 status = find_member(acl_type, acl_id, client_type, client_id, 0);
295 if (!status) return(MR_PERM);
302 /* access_filesys - verify that client is owner or on owners list of filesystem
306 access_filesys(q, argv, cl)
311 EXEC SQL BEGIN DECLARE SECTION;
312 int users_id, list_id;
314 EXEC SQL END DECLARE SECTION;
315 int status, client_id;
319 EXEC SQL SELECT owner, owners
320 INTO :users_id, :list_id
323 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
326 if (users_id == cl->users_id)
328 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
330 status = find_member("LIST", list_id, client_type, client_id, 0);
341 /* Setup routine for add_user
343 * Inputs: argv[0] - login
348 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
349 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
352 setup_ausr(q, argv, cl)
354 register char *argv[];
357 EXEC SQL BEGIN DECLARE SECTION;
360 EXEC SQL END DECLARE SECTION;
363 /* this is currently disabled because we need an index on ID's
364 * before it can run in finite time.
366 mit_id = argv[U_MITID];
367 ## retrieve (rowcount = any(u.#mit_id where u.#mit_id = mit_id))
368 if (ingres_errno) return(mr_errcode);
369 if (rowcount) return(MR_EXISTS);
372 if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
373 if (set_next_object_id("uid", "users"))
374 return(MR_INGRES_ERR);
375 EXEC SQL SELECT value
379 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
381 sprintf(argv[1], "%d", nuid);
384 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
385 sprintf(argv[0], "#%s", argv[1]);
392 /* setup_dusr - verify that the user is no longer being referenced
393 * and may safely be deleted.
396 int setup_dusr(q, argv)
400 EXEC SQL BEGIN DECLARE SECTION;
402 EXEC SQL END DECLARE SECTION;
404 id = *(int *)argv[0];
406 /* For now, only allow users to be deleted if their status is 0 */
407 ## repeat retrieve (flag = u.status) where u.users_id = @id
408 if (flag != 0 && flag != 4)
411 ## repeat delete quota where quota.entity_id = @id and quota.type = "USER"
412 ## repeat delete krbmap where krbmap.users_id = @id
413 ## repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
414 ## and imembers.member_type = "USER"))
417 ## repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
420 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
421 ## list.acl_type = "USER"))
424 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
425 ## servers.acl_type = "USER"))
428 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
429 ## hostaccess.acl_type = "USER"))
438 /* setup_spop: verify that there is already a valid POP machine_id in the
439 * pop_id field. Also take care of keeping track of the post office usage.
441 int setup_spop(q, argv)
445 EXEC SQL BEGIN DECLARE SECTION;
448 EXEC SQL END DECLARE SECTION;
450 id = *(int *)argv[0];
451 ## repeat retrieve (type = u.potype, mid = u.pop_id,
452 ## flag = any(machine.name where machine.mach_id = u.pop_id
453 ## and u.pop_id != 0 and u.users_id = @id))
454 ## where u.users_id = @id
457 if (strcmp(strtrim(type), "POP"))
458 set_pop_usage(mid, 1);
463 /* setup_dpob: Take care of keeping track of the post office usage.
465 int setup_dpob(q, argv)
469 EXEC SQL BEGIN DECLARE SECTION;
472 EXEC SQL END DECLARE SECTION;
474 user = *(int *)argv[0];
475 EXEC SQL SELECT potype, pop_id
478 WHERE users_id = :user;
479 if (ingres_errno) return(mr_errcode);
481 if (!strcmp(strtrim(type), "POP"))
482 set_pop_usage(id, -1);
487 /* setup_dmac - verify that the machine is no longer being referenced
488 * and may safely be deleted.
491 int setup_dmac(q, argv)
495 EXEC SQL BEGIN DECLARE SECTION;
497 EXEC SQL END DECLARE SECTION;
499 id = *(int *)argv[0];
500 ## repeat retrieve (flag = any(users.login where users.potype = "POP"
501 ## and users.pop_id=@id))
504 ## repeat retrieve (flag = any(serverhosts.mach_id
505 ## where serverhosts.mach_id=@id))
508 ## repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
511 ## repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
514 ## repeat retrieve (flag = any(printcap.mach_id where printcap.mach_id=@id))
517 ## repeat retrieve (flag = any(printcap.quotaserver where printcap.quotaserver=@id))
520 ## repeat retrieve (flag = any(palladium.mach_id where palladium.mach_id=@id))
524 ## repeat delete mcmap where mcmap.mach_id = @id
525 if (ingres_errno) return(mr_errcode);
530 /* setup_dclu - verify that the cluster is no longer being referenced
531 * and may safely be deleted.
534 int setup_dclu(q, argv)
538 EXEC SQL BEGIN DECLARE SECTION;
540 EXEC SQL END DECLARE SECTION;
542 id = *(int *)argv[0];
543 ## repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
546 ## repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
555 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
556 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
557 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
558 * a -1 there. Remember that this is also used for ulis, with the indexes
562 int setup_alis(q, argv)
566 EXEC SQL BEGIN DECLARE SECTION;
568 EXEC SQL END DECLARE SECTION;
572 if (!strcmp(q->shortname, "alis"))
574 else if (!strcmp(q->shortname, "ulis"))
577 if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
578 if (atoi(argv[idx - 1])) {
579 if (set_next_object_id("gid", "list"))
580 return(MR_INGRES_ERR);
581 EXEC SQL SELECT value
585 if (ingres_errno) return(mr_errcode);
586 sprintf(argv[idx], "%d", ngid);
588 strcpy(argv[idx], "-1");
596 /* setup_dlist - verify that the list is no longer being referenced
597 * and may safely be deleted.
600 int setup_dlis(q, argv)
604 EXEC SQL BEGIN DECLARE SECTION;
606 EXEC SQL END DECLARE SECTION;
608 id = *(int *)argv[0];
609 ## repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
610 ## and imembers.member_type = "LIST"))
613 ## repeat retrieve (flag = any(imembers.member_id where imembers.list_id=@id))
616 ## repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
619 ## repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
622 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
623 ## list.acl_type = "LIST" and list.list_id != @id))
626 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
627 ## servers.acl_type = "LIST"))
630 ## repeat retrieve (flag = any(quota.entity_id where quota.entity_id=@id and
631 ## quota.type = "GROUP"))
634 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
635 ## hostaccess.acl_type = "LIST"))
638 ## repeat retrieve (flag = any(zephyr.class
639 ## where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
640 ## zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
641 ## zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
642 ## zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
651 /* setup_dsin - verify that the service is no longer being referenced
652 * and may safely be deleted.
655 int setup_dsin(q, argv)
659 EXEC SQL BEGIN DECLARE SECTION;
662 EXEC SQL END DECLARE SECTION;
665 ## repeat retrieve (flag = any(serverhosts.service
666 ## where serverhosts.service=uppercase(@name)))
669 EXEC SQL SELECT inprogress
681 /* setup_dshi - verify that the service-host is no longer being referenced
682 * and may safely be deleted.
685 int setup_dshi(q, argv)
689 EXEC SQL BEGIN DECLARE SECTION;
692 EXEC SQL END DECLARE SECTION;
695 id = *(int *)argv[1];
697 EXEC SQL SELECT inprogress
700 WHERE service = :name AND mach_id = :id;
710 ** setup_add_filesys - verify existance of referenced file systems
722 ** * extract directory prefix from name
723 ** * verify mach_id/dir in nfsphys
724 ** * verify access in {r, w, R, W}
726 ** Side effect: sets variable var_phys_id to the ID of the physical
727 ** filesystem (nfsphys_id for NFS, 0 for RVD)
730 ** MR_NFS - specified directory not exported
731 ** MR_FILESYS_ACCESS - invalid filesys access
735 ##static int var_phys_id;
743 EXEC SQL BEGIN DECLARE SECTION;
745 char ftype[32], *access;
746 EXEC SQL END DECLARE SECTION;
749 mach_id = *(int *)argv[2];
754 sprintf(ftype, "fs_access_%s", type);
755 ## retrieve (ok = any(alias.trans where alias.name = ftype and
756 ## alias.type = "TYPE" and alias.trans = access))
757 if (ingres_errno) return(mr_errcode);
758 if (ok == 0) return(MR_FILESYS_ACCESS);
760 if (!strcmp(type, "NFS"))
761 return (check_nfs(mach_id, name, access));
767 /* Verify the arguments, depending on the FStype. Also, if this is an
768 * NFS filesystem, then update any quotas for that filesystem to reflect
772 setup_ufil(q, argv, cl)
779 EXEC SQL BEGIN DECLARE SECTION;
781 char *entity, ftype[32], *access;
782 EXEC SQL END DECLARE SECTION;
785 mach_id = *(int *)argv[3];
789 fid = *(int *)argv[0];
793 sprintf(ftype, "fs_access_%s", type);
794 ## retrieve (total = any(alias.trans where alias.name = ftype and
795 ## alias.type = "TYPE" and alias.trans = access))
796 if (ingres_errno) return(mr_errcode);
797 if (total == 0) return(MR_FILESYS_ACCESS);
799 if (!strcmp(type, "NFS")) {
800 status = check_nfs(mach_id, name, access);
801 ## replace quota (phys_id = var_phys_id) where quota.filsys_id = fid
802 if (ingres_errno) return(mr_errcode);
804 } else if (!strcmp(type, "AFS")) {
806 ## retrieve (total = sum(quota.quota where quota.filsys_id = fid
807 ## and quota.phys_id != 0))
808 if (ingres_errno) return(mr_errcode);
810 ## append quota (quota = total, filsys_id = fid,
811 ## phys_id = 0, entity_id = 0, type = "ANY",
812 ## modtime = "now", modby = who, modwith = entity)
813 if (ingres_errno) return(mr_errcode);
816 ## replace quota (phys_id = 0) where quota.filsys_id = fid
817 if (ingres_errno) return(mr_errcode);
823 /* Find the NFS physical partition that the named directory is on.
824 * This is done by comparing the dir against the mount point of the
825 * partition. To make sure we get the correct match when there is
826 * more than one, we sort the query in reverse order by dir name.
829 ##check_nfs(mach_id, name, access)
830 EXEC SQL BEGIN DECLARE SECTION;
832 EXEC SQL END DECLARE SECTION;
836 EXEC SQL BEGIN DECLARE SECTION;
838 EXEC SQL END DECLARE SECTION;
845 ## range of np is nfsphys
846 ## repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
847 ## where np.#mach_id = @mach_id sort by #dir:d {
851 if (*cp1++ != *cp2) break;
865 /* setup_dfil: free any quota records and fsgroup info associated with
866 * a filesystem when it is deleted. Also adjust the allocation numbers.
869 setup_dfil(q, argv, cl)
874 EXEC SQL BEGIN DECLARE SECTION;
876 EXEC SQL END DECLARE SECTION;
878 id = *(int *)argv[0];
879 ## range of q is quota
880 ## range of n is nfsphys
881 ## repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
882 ## where n.nfsphys_id = filesys.phys_id and filesys.filsys_id = @id
884 ## repeat delete q where q.filsys_id = @id
885 ## repeat delete fsgroup where fsgroup.filsys_id = @id
886 ## repeat delete fsgroup where fsgroup.group_id = @id
887 if (ingres_errno) return(mr_errcode);
892 /* setup_dnfp: check to see that the nfs physical partition does not have
893 * any filesystems assigned to it before allowing it to be deleted.
896 setup_dnfp(q, argv, cl)
901 EXEC SQL BEGIN DECLARE SECTION;
904 EXEC SQL END DECLARE SECTION;
906 id = *(int *)argv[0];
908 ## repeat retrieve (exist = any(filesys.label where filesys.mach_id = @id
909 ## and filesys.phys_id = nfsphys.nfsphys_id and
910 ## nfsphys.mach_id = @id and nfsphys.#dir = @dir))
919 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
920 * argv[0] = filsys_id
921 * argv[1] = type if "update_quota" or "delete_quota"
922 * argv[2 or 1] = users_id or list_id
925 setup_dqot(q, argv, cl)
930 EXEC SQL BEGIN DECLARE SECTION;
933 EXEC SQL END DECLARE SECTION;
935 fs = *(int *)argv[0];
936 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
938 id = *(int *)argv[2];
941 id = *(int *)argv[1];
943 EXEC SQL SELECT quota_value
946 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
947 ## repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
948 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
949 if (ingres_errno) return(mr_errcode);
954 /* setup_sshi: don't exclusive lock the machine table during
955 * set_server_host_internal.
958 setup_sshi(q, argv, cl)
963 ## set lockmode session where readlock = system
967 /* setup add_kerberos_user_mapping: add the string to the string
968 * table if necessary.
971 setup_akum(q, argv, cl)
976 EXEC SQL BEGIN DECLARE SECTION;
979 EXEC SQL END DECLARE SECTION;
982 if (name_to_id(name, "STRING", &id) != MR_SUCCESS) {
983 if (q->type != APPEND) return(MR_STRING);
984 EXEC SQL SELECT value
987 WHERE name = "strings_id";
989 ## replace v (value = id) where v.#name = "strings_id"
990 ## append to strings (string_id = id, string = name)
991 cache_entry(name, "STRING", id);
993 if (ingres_errno) return(mr_errcode);
994 *(int *)argv[1] = id;
1000 /* FOLLOWUP ROUTINES */
1002 /* generic set_modtime routine. This takes the table name from the query,
1003 * and will update the modtime, modby, and modwho fields in the entry in
1004 * the table whose name field matches argv[0].
1007 set_modtime(q, argv, cl)
1012 EXEC SQL BEGIN DECLARE SECTION;
1013 char *name, *entity, *tbl;
1015 EXEC SQL END DECLARE SECTION;
1017 entity = cl->entity;
1018 who = cl->client_id;
1022 ## replace tbl (modtime = "now", modby = who, modwith = entity)
1023 ## where tbl.#name = name
1027 /* generic set_modtime_by_id routine. This takes the table name from
1028 * the query, and the id name from the validate record,
1029 * and will update the modtime, modby, and modwho fields in the entry in
1030 * the table whose id matches argv[0].
1033 set_modtime_by_id(q, argv, cl)
1038 EXEC SQL BEGIN DECLARE SECTION;
1039 char *entity, *tbl, *id_name;
1041 EXEC SQL END DECLARE SECTION;
1043 entity = cl->entity;
1044 who = cl->client_id;
1046 id_name = q->validate->object_id;
1048 id = *(int *)argv[0];
1049 ## replace tbl (modtime = "now", modby = who, modwith = entity)
1050 ## where tbl.id_name = id
1055 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
1058 set_finger_modtime(q, argv, cl)
1063 EXEC SQL BEGIN DECLARE SECTION;
1066 EXEC SQL END DECLARE SECTION;
1068 entity = cl->entity;
1069 who = cl->client_id;
1070 users_id = *(int *)argv[0];
1072 ## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
1073 ## where u.#users_id = @users_id
1078 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
1081 set_pobox_modtime(q, argv, cl)
1086 EXEC SQL BEGIN DECLARE SECTION;
1089 EXEC SQL END DECLARE SECTION;
1091 entity = cl->entity;
1092 who = cl->client_id;
1093 users_id = *(int *)argv[0];
1095 ## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
1096 ## where users.#users_id = @users_id
1101 /* Like set_modtime, but uppercases the name first.
1104 set_uppercase_modtime(q, argv, cl)
1109 EXEC SQL BEGIN DECLARE SECTION;
1110 char *name, *entity, *tbl;
1112 EXEC SQL END DECLARE SECTION;
1114 entity = cl->entity;
1115 who = cl->client_id;
1119 ## replace tbl (modtime = "now", modby = who, modwith = entity)
1120 ## where tbl.#name = uppercase(name)
1125 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
1126 * is necessary for add_machine_to_cluster becuase the table that query
1127 * operates on is "mcm", not "machine".
1130 set_mach_modtime_by_id(q, argv, cl)
1135 EXEC SQL BEGIN DECLARE SECTION;
1138 EXEC SQL END DECLARE SECTION;
1140 entity = cl->entity;
1141 who = cl->client_id;
1143 id = *(int *)argv[0];
1144 ## repeat replace machine (modtime = "now", modby = @who, modwith = @entity)
1145 ## where machine.mach_id = @id
1150 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
1151 * is necessary for add_cluster_data and delete_cluster_data becuase the
1152 * table that query operates on is "svc", not "cluster".
1155 set_cluster_modtime_by_id(q, argv, cl)
1160 EXEC SQL BEGIN DECLARE SECTION;
1163 EXEC SQL END DECLARE SECTION;
1165 entity = cl->entity;
1166 who = cl->client_id;
1168 id = *(int *)argv[0];
1169 ## repeat replace cluster (modtime = "now", modby = @who, modwith = @entity)
1170 ## where cluster.clu_id = @id
1175 /* sets the modtime on the serverhost where the service name is in argv[0]
1176 * and the mach_id is in argv[1].
1179 set_serverhost_modtime(q, argv, cl)
1184 EXEC SQL BEGIN DECLARE SECTION;
1185 char *entity, *serv;
1187 EXEC SQL END DECLARE SECTION;
1189 entity = cl->entity;
1190 who = cl->client_id;
1193 id = *(int *)argv[1];
1194 ## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
1195 ## where sh.service = uppercase(@serv) and sh.mach_id = @id
1200 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1201 * directory name is in argv[1].
1204 set_nfsphys_modtime(q, argv, cl)
1209 EXEC SQL BEGIN DECLARE SECTION;
1212 EXEC SQL END DECLARE SECTION;
1214 entity = cl->entity;
1215 who = cl->client_id;
1217 id = *(int *)argv[0];
1219 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1220 ## where np.#dir = @dir and np.mach_id = @id
1225 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1229 set_filesys_modtime(q, argv, cl)
1234 EXEC SQL BEGIN DECLARE SECTION;
1235 char *label, *entity;
1237 EXEC SQL END DECLARE SECTION;
1239 entity = cl->entity;
1240 who = cl->client_id;
1243 if (!strcmp(q->shortname, "ufil"))
1246 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1247 ## #phys_id = @var_phys_id) where fs.#label = @label
1252 /* sets the modtime on a zephyr class, where argv[0] contains the class
1256 set_zephyr_modtime(q, argv, cl)
1261 EXEC SQL BEGIN DECLARE SECTION;
1262 char *class, *entity;
1264 EXEC SQL END DECLARE SECTION;
1266 entity = cl->entity;
1267 who = cl->client_id;
1271 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1272 ## where z.#class = @class
1277 /* fixes the modby field. This will be the second to last thing in the
1278 * argv, the argv length is determined from the query structure. It is
1279 * passed as a pointer to an integer. This will either turn it into a
1280 * username, or # + the users_id.
1282 followup_fix_modby(q, sq, v, action, actarg, cl)
1284 register struct save_queue *sq;
1286 register int (*action)();
1287 register int actarg;
1291 char **argv, *malloc();
1295 while (sq_get_data(sq, &argv)) {
1298 status = id_to_name(id, "USER", &argv[i]);
1300 status = id_to_name(-id, "STRING", &argv[i]);
1301 if (status && status != MR_NO_MATCH)
1303 (*action)(q->vcnt, argv, actarg);
1304 for (j = 0; j < q->vcnt; j++)
1314 ** followup_ausr - add finger and pobox entries, set_user_modtime
1317 ** argv[0] - login (add_user)
1318 ** argv[3] - last name
1319 ** argv[4] - first name
1320 ** argv[5] - middle name
1324 followup_ausr(q, argv, cl)
1329 EXEC SQL BEGIN DECLARE SECTION;
1331 char *login, *entity;
1333 EXEC SQL END DECLARE SECTION;
1336 who = cl->client_id;
1337 entity = cl->entity;
1339 /* build fullname */
1340 if (strlen(argv[4]) && strlen(argv[5]))
1341 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1342 else if (strlen(argv[4]))
1343 sprintf(fullname, "%s %s", argv[4], argv[3]);
1345 sprintf(fullname, "%s", argv[3]);
1347 /* create finger entry, pobox & set modtime on user */
1348 ## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1349 ## #fullname=@fullname, mit_affil = u.mit_year,
1350 ## fmodtime="now", fmodby=@who, fmodwith=@entity,
1351 ## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1352 ## where u.#login = @login
1358 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1359 * type in argv[1]. Then completes the upcall to the user.
1361 * argv[2] is of the form "123:234" where the first integer is the machine
1362 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1363 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1367 followup_gpob(q, sq, v, action, actarg, cl)
1368 register struct query *q;
1369 register struct save_queue *sq;
1370 register struct validate *v;
1371 register int (*action)();
1375 char **argv, *index();
1377 int mid, sid, status;
1380 while (sq_get_data(sq, &argv)) {
1381 mr_trim_args(2, argv);
1383 p = index(argv[2], ':');
1385 mid = atoi(argv[2]);
1388 if (!strcmp(ptype, "POP")) {
1389 status = id_to_name(mid, "MACHINE", &argv[2]);
1390 if (status == MR_NO_MATCH)
1392 } else if (!strcmp(ptype, "SMTP")) {
1393 status = id_to_name(sid, "STRING", &argv[2]);
1394 if (status == MR_NO_MATCH)
1396 } else /* ptype == "NONE" */ {
1399 if (status) return(status);
1401 if (!strcmp(q->shortname, "gpob")) {
1402 sid = atoi(argv[4]);
1404 status = id_to_name(sid, "USER", &argv[4]);
1406 status = id_to_name(-sid, "STRING", &argv[4]);
1408 if (status && status != MR_NO_MATCH) return(status);
1410 (*action)(q->vcnt, argv, actarg);
1412 /* free saved data */
1420 return (MR_SUCCESS);
1424 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1425 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1426 * proper name based on the type, and repace that string in the argv.
1427 * Also fixes the modby field by called followup_fix_modby.
1430 followup_glin(q, sq, v, action, actarg, cl)
1431 register struct query *q;
1432 register struct save_queue *sq;
1433 register struct validate *v;
1434 register int (*action)();
1438 char **argv, *malloc(), *realloc(), *type;
1439 int id, i, idx, status;
1442 if (!strcmp(q->shortname, "gsin"))
1445 while (sq_get_data(sq, &argv)) {
1446 mr_trim_args(q->vcnt, argv);
1448 id = atoi(argv[i = q->vcnt - 2]);
1450 status = id_to_name(id, "USER", &argv[i]);
1452 status = id_to_name(-id, "STRING", &argv[i]);
1453 if (status && status != MR_NO_MATCH)
1456 id = atoi(argv[idx]);
1457 type = argv[idx - 1];
1459 if (!strcmp(type, "LIST")) {
1460 status = id_to_name(id, "LIST", &argv[idx]);
1461 } else if (!strcmp(type, "USER")) {
1462 status = id_to_name(id, "USER", &argv[idx]);
1463 } else if (!strcmp(type, "KERBEROS")) {
1464 status = id_to_name(id, "STRING", &argv[idx]);
1465 } else if (!strcmp(type, "NONE")) {
1468 argv[idx] = strsave("NONE");
1472 argv[idx] = strsave("???");
1474 if (status && status != MR_NO_MATCH)
1477 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1478 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1479 strcpy(argv[6], UNIQUE_GID);
1483 (*action)(q->vcnt, argv, actarg);
1485 /* free saved data */
1486 for (i = 0; i < q->vcnt; i++)
1492 return (MR_SUCCESS);
1496 /* followup_gqot: Fix the entity name, directory name & modby fields
1497 * argv[0] = filsys_id
1499 * argv[2] = entity_id
1500 * argv[3] = ascii(quota)
1503 followup_gqot(q, sq, v, action, actarg, cl)
1505 register struct save_queue *sq;
1507 register int (*action)();
1508 register int actarg;
1512 char **argv, *malloc();
1513 EXEC SQL BEGIN DECLARE SECTION;
1516 EXEC SQL END DECLARE SECTION;
1519 if (!strcmp(q->name, "get_quota") ||
1520 !strcmp(q->name, "get_quota_by_filesys"))
1524 while (sq_get_data(sq, &argv)) {
1526 switch (argv[1][0]) {
1528 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1532 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1536 argv[2] = strsave("system:anyuser");
1540 argv[2] = malloc(8);
1541 sprintf(argv[2], "%d", id);
1544 id = atoi(argv[idx]);
1546 argv[idx] = malloc(256);
1550 EXEC SQL SELECT name
1553 WHERE label = :label;
1558 WHERE nfsphys_id = :id;
1560 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1) {
1561 sprintf(argv[idx], "#%d", id);
1564 id = atoi(argv[idx+3]);
1566 status = id_to_name(id, "USER", &argv[idx+3]);
1568 status = id_to_name(-id, "STRING", &argv[idx+3]);
1569 if (status && status != MR_NO_MATCH)
1571 (*action)(q->vcnt, argv, actarg);
1572 for (j = 0; j < q->vcnt; j++)
1581 /* followup_aqot: Add allocation to nfsphys after creating quota.
1582 * argv[0] = filsys_id
1583 * argv[1] = type if "add_quota" or "update_quota"
1585 * argv[3 or 2] = ascii(quota)
1588 followup_aqot(q, argv, cl)
1593 EXEC SQL BEGIN DECLARE SECTION;
1594 int quota, id, fs, who;
1595 char *entity, *qtype;
1596 EXEC SQL END DECLARE SECTION;
1598 fs = *(int *)argv[0];
1599 if (!strcmp(q->name, "add_quota") || !strcmp(q->name, "update_quota")) {
1601 id = *(int *)argv[2];
1602 quota = atoi(argv[3]);
1605 id = *(int *)argv[1];
1606 quota = atoi(argv[2]);
1608 who = cl->client_id;
1609 entity = cl->entity;
1611 ## repeat replace q (modtime = "now", modby = @who, modwith = @entity)
1612 ## where q.filsys_id = @fs and q.type = @qtype and q.entity_id = @id
1613 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1614 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1615 if (ingres_errno) return(mr_errcode);
1620 followup_gpce(q, sq, v, action, actarg, cl)
1622 register struct save_queue *sq;
1624 register int (*action)();
1625 register int actarg;
1629 char **argv, *malloc();
1633 while (sq_get_data(sq, &argv)) {
1634 id = atoi(argv[PCAP_QSERVER]);
1635 status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
1636 if (status) return (status);
1639 status = id_to_name(id, "USER", &argv[i]);
1641 status = id_to_name(-id, "STRING", &argv[i]);
1642 if (status && status != MR_NO_MATCH)
1644 (*action)(q->vcnt, argv, actarg);
1645 for (j = 0; j < q->vcnt; j++)
1657 followup_gzcl(q, sq, v, action, actarg, cl)
1658 register struct query *q;
1659 register struct save_queue *sq;
1660 register struct validate *v;
1661 register int (*action)();
1668 while (sq_get_data(sq, &argv)) {
1669 mr_trim_args(q->vcnt, argv);
1671 id = atoi(argv[i = q->vcnt - 2]);
1673 status = id_to_name(id, "USER", &argv[i]);
1675 status = id_to_name(-id, "STRING", &argv[i]);
1676 if (status && status != MR_NO_MATCH)
1679 for (i = 1; i < 8; i+=2) {
1680 id = atoi(argv[i+1]);
1681 if (!strcmp(argv[i], "LIST")) {
1682 status = id_to_name(id, "LIST", &argv[i+1]);
1683 } else if (!strcmp(argv[i], "USER")) {
1684 status = id_to_name(id, "USER", &argv[i+1]);
1685 } else if (!strcmp(argv[i], "KERBEROS")) {
1686 status = id_to_name(id, "STRING", &argv[i+1]);
1687 } else if (!strcmp(argv[i], "NONE")) {
1690 argv[i+1] = strsave("NONE");
1694 argv[i+1] = strsave("???");
1696 if (status && status != MR_NO_MATCH)
1701 (*action)(q->vcnt, argv, actarg);
1703 /* free saved data */
1704 for (i = 0; i < q->vcnt; i++)
1716 followup_gsha(q, sq, v, action, actarg, cl)
1717 register struct query *q;
1718 register struct save_queue *sq;
1719 register struct validate *v;
1720 register int (*action)();
1727 while (sq_get_data(sq, &argv)) {
1728 mr_trim_args(q->vcnt, argv);
1732 status = id_to_name(id, "USER", &argv[4]);
1734 status = id_to_name(-id, "STRING", &argv[4]);
1735 if (status && status != MR_NO_MATCH)
1739 if (!strcmp(argv[1], "LIST")) {
1740 status = id_to_name(id, "LIST", &argv[2]);
1741 } else if (!strcmp(argv[1], "USER")) {
1742 status = id_to_name(id, "USER", &argv[2]);
1743 } else if (!strcmp(argv[1], "KERBEROS")) {
1744 status = id_to_name(id, "STRING", &argv[2]);
1745 } else if (!strcmp(argv[1], "NONE")) {
1748 argv[2] = strsave("NONE");
1752 argv[2] = strsave("???");
1754 if (status && status != MR_NO_MATCH)
1758 (*action)(q->vcnt, argv, actarg);
1760 /* free saved data */
1761 for (i = 0; i < q->vcnt; i++)
1771 /* Special query routines */
1773 /* set_pobox - this does all of the real work.
1774 * argv = user_id, type, box
1775 * if type is POP, then box should be a machine, and its ID should be put in
1776 * pop_id. If type is SMTP, then box should be a string and its ID should
1777 * be put in box_id. If type is NONE, then box doesn't matter.
1780 int set_pobox(q, argv, cl)
1785 EXEC SQL BEGIN DECLARE SECTION;
1787 char *box, potype[9];
1788 EXEC SQL END DECLARE SECTION;
1792 user = *(int *)argv[0];
1793 EXEC SQL SELECT pop_id, potype
1796 WHERE users_id = :user;
1797 if (ingres_errno) return(mr_errcode);
1798 if (!strcmp(strtrim(potype), "POP"))
1799 set_pop_usage(id, -1);
1801 if (!strcmp(argv[1], "POP")) {
1802 status = name_to_id(box, "MACHINE", &id);
1803 if (status == MR_NO_MATCH)
1807 ## repeat replace users (#potype = "POP", pop_id = @id)
1808 ## where users.users_id = @user
1809 set_pop_usage(id, 1);
1810 } else if (!strcmp(argv[1], "SMTP")) {
1811 if (index(box, '/') || index(box, '|'))
1812 return(MR_BAD_CHAR);
1813 status = name_to_id(box, "STRING", &id);
1814 if (status == MR_NO_MATCH) {
1815 EXEC SQL SELECT value
1818 WHERE name = "strings_id";
1820 ## repeat replace values_tbl.(value = @id) where values_tbl.name = "strings_id"
1821 ## append to strings (string_id = id, string = box)
1824 ## repeat replace users (#potype = "SMTP", box_id = @id)
1825 ## where users.users_id = @user
1826 } else /* argv[1] == "NONE" */ {
1827 ## repeat replace users (#potype = "NONE") where users.users_id = @user
1830 set_pobox_modtime(q, argv, cl);
1831 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1832 ## where tblstats.#table = "users"
1833 if (ingres_errno) return(mr_errcode);
1838 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1839 * each list. This is tricky: first build a queue of all requested
1840 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1843 get_list_info(q, aargv, cl, action, actarg)
1844 register struct query *q;
1847 register int (*action)();
1850 char *argv[13], *malloc(), *realloc();
1851 EXEC SQL BEGIN DECLARE SECTION;
1852 char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1853 char maillist[5], grp[5], gid[6], acl_name[256], desc[256], modtime[27];
1854 char modby[256], modwith[9];
1855 int id, rowcount, acl_id, hid, modby_id;
1856 EXEC SQL END DECLARE SECTION;
1857 int returned, status;
1858 struct save_queue *sq, *sq_create();
1860 returned = rowcount = 0;
1864 EXEC SQL DECLARE l_cursor CURSOR FOR
1867 WHERE L.name = :name;
1868 EXEC SQL OPEN l_cursor;
1870 EXEC SQL FETCH l_cursor INTO :id;
1871 if (sqlca.sqlcode != 0) break;
1872 sq_save_data(sq, id);
1875 EXEC SQL CLOSE l_cursor;
1876 if (ingres_errno) return(mr_errcode);
1878 return(MR_NO_MATCH);
1880 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1881 argv[4] = maillist; argv[5] = grp; argv[6] = gid; argv[7] = acl_type;
1882 argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
1884 while (sq_get_data(sq, &id)) {
1888 ## repeat retrieve (listname = l.#name, active = text(l.#active),
1889 ## public = text(l.#public), hidden = text(l.#hidden),
1890 ## hid = l.#hidden, maillist = text(l.#maillist),
1891 ## group = text(l.#grp), gid = text(l.#gid),
1892 ## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1893 ## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1894 ## modwith =l.#modwith)
1895 ## where l.list_id = @id
1896 if (ingres_errno) return(mr_errcode);
1898 if (atoi(gid) == -1)
1899 argv[6] = UNIQUE_GID;
1901 argv[8] = malloc(0);
1902 if (!strcmp(acl_type, "LIST")) {
1903 status = id_to_name(acl_id, "LIST", &argv[8]);
1904 } else if (!strcmp(acl_type, "USER")) {
1905 status = id_to_name(acl_id, "USER", &argv[8]);
1906 } else if (!strcmp(acl_type, "KERBEROS")) {
1907 status = id_to_name(acl_id, "STRING", &argv[8]);
1908 } else if (!strcmp(acl_type, "NONE")) {
1911 argv[8] = strsave("NONE");
1915 argv[8] = strsave("???");
1917 if (status && status != MR_NO_MATCH) return(status);
1919 argv[11] = malloc(0);
1921 status = id_to_name(modby_id, "USER", &argv[11]);
1923 status = id_to_name(-modby_id, "STRING", &argv[11]);
1924 if (status && status != MR_NO_MATCH) return(status);
1926 mr_trim_args(q->vcnt, argv);
1928 (*action)(q->vcnt, argv, actarg);
1934 if (ingres_errno) return(mr_errcode);
1935 return (MR_SUCCESS);
1939 /* Add_member_to_list: do list flattening as we go! MAXLISTDEPTH is
1940 * how many different ancestors a member is allowed to have.
1943 #define MAXLISTDEPTH 1024
1945 int add_member_to_list(q, argv, cl)
1950 EXEC SQL BEGIN DECLARE SECTION;
1951 int id, lid, mid, exist, error, who, ref;
1952 char *mtype, dtype[9], *entity;
1953 EXEC SQL END DECLARE SECTION;
1954 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
1955 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
1957 char *dtypes[MAXLISTDEPTH];
1958 char *iargv[3], *buf;
1960 EXEC SQL DECLARE m_cursor_a CURSOR FOR
1961 SELECT M.list_id, M.ref_count
1963 WHERE M.member_id = :lid AND M.member_type = "LIST";
1964 EXEC SQL OPEN m_cursor_a;
1966 lid = *(int *)argv[0];
1968 mid = *(int *)argv[2];
1969 /* if the member is already a direct member of the list, punt */
1970 ## repeat retrieve (exist = any(m.list_id where m.list_id=@lid and
1971 ## m.member_id = @mid and m.member_type = @mtype
1972 ## and m.direct = 1))
1975 if (!strcasecmp(mtype, "STRING")) {
1977 status = id_to_name(mid, "STRING", &buf);
1978 if (status) return(status);
1979 if (index(buf, '/') || index(buf, '|')) {
1981 return(MR_BAD_CHAR);
1990 EXEC SQL FETCH m_cursor_a INTO :id, :ref;
1991 if (sqlca.sqlcode != 0) break;
1993 ancestors[acount++] = id;
1994 if (acount >= MAXLISTDEPTH) {
1995 return(MR_INTERNAL);
1998 if (ingres_errno) return(mr_errcode);
1999 if (acount >= MAXLISTDEPTH) {
2000 return(MR_INTERNAL);
2002 EXEC SQL CLOSE m_cursor_a;
2003 descendants[0] = mid;
2010 if (!strcmp(mtype, "LIST")) {
2011 EXEC SQL DECLARE m_cursor_l CURSOR FOR
2012 SELECT M.member_id, M.memeber_type, M.ref_count
2014 WHERE M.list_id = :mid;
2015 EXEC SQL OPEN m_cursor_l;
2017 EXEC SQL FETCH m_cursor_l INTO :id, :dtype, :ref;
2018 if (sqlca.sqlcode != 0) break;
2021 dtypes[dcount] = "LIST";
2024 dtypes[dcount] = "USER";
2027 dtypes[dcount] = "STRING";
2030 dtypes[dcount] = "KERBEROS";
2036 descendants[dcount++] = id;
2037 if (dcount >= MAXLISTDEPTH) {
2041 EXEC SQL CLOSE m_cursor_l;
2042 if (ingres_errno) return(mr_errcode);
2044 return(MR_INTERNAL);
2046 for (a = 0; a < acount; a++) {
2048 for (d = 0; d < dcount; d++) {
2049 mid = descendants[d];
2051 if (mid == lid && !strcmp(mtype, "LIST")) {
2052 return(MR_LISTLOOP);
2054 ## repeat retrieve (exist = any(m.ref_count where m.list_id = @lid
2055 ## and m.member_id = @mid
2056 ## and m.member_type = @mtype))
2057 ref = aref[a] * dref[d];
2059 if (a == 0 && d == 0)
2060 ## replace m (ref_count = m.ref_count+ref, direct = 1)
2061 ## where m.list_id = lid and m.member_id = mid and
2062 ## m.member_type = mtype
2064 ## replace m (ref_count = m.ref_count+ref)
2065 ## where m.list_id = lid and m.member_id = mid and
2066 ## m.member_type = mtype
2068 incremental_clear_before();
2069 if (a == 0 && d == 0)
2070 ## append imembers (list_id=lid, member_id = mid, direct = 1,
2071 ## member_type=mtype, ref_count = 1)
2073 ## append imembers (list_id=lid, member_id = mid,
2074 ## member_type=mtype, ref_count = ref)
2075 iargv[0] = (char *)lid;
2077 iargv[2] = (char *)mid;
2078 incremental_after("members", 0, iargv);
2082 lid = *(int *)argv[0];
2083 entity = cl->entity;
2084 who = cl->client_id;
2085 ## repeat replace list (modtime = "now", modby = @who, modwith = @entity)
2086 ## where list.#list_id = @lid
2087 if (ingres_errno) return(mr_errcode);
2092 /* Delete_member_from_list: do list flattening as we go!
2095 int delete_member_from_list(q, argv, cl)
2100 EXEC SQL BEGIN DECLARE SECTION;
2101 int id, lid, mid, cnt, exist, error, who, ref;
2102 char *mtype, dtype[9], *entity;
2103 EXEC SQL END DECLARE SECTION;
2104 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2105 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2106 char *dtypes[MAXLISTDEPTH];
2109 ## range of m is imembers
2110 lid = *(int *)argv[0];
2112 mid = *(int *)argv[2];
2113 /* if the member is not a direct member of the list, punt */
2114 ## repeat retrieve (exist = any(m.list_id where m.list_id=@lid and
2115 ## m.member_id = @mid and m.member_type = @mtype
2116 ## and m.direct = 1))
2117 if (ingres_errno) return(mr_errcode);
2119 return(MR_NO_MATCH);
2124 EXEC SQL DECLARE m3_cursor CURSOR FOR
2125 SELECT M.list_id, M.ref_count
2127 WHERE M.member_id = :lid AND M.member_type = "LIST";
2128 EXEC SQL OPEN m3_cursor;
2130 EXEC SQL FETCH m3_cursor INTO :id, :ref;
2131 if (sqlca.sqlcode != 0) break;
2133 ancestors[acount++] = id;
2134 if (acount >= MAXLISTDEPTH)
2137 EXEC SQL CLOSE m3_cursor;
2138 if (ingres_errno) return(mr_errcode);
2139 if (acount >= MAXLISTDEPTH)
2140 return(MR_INTERNAL);
2141 descendants[0] = mid;
2146 if (!strcmp(mtype, "LIST")) {
2147 EXEC SQL DECLARE m4_cursor CURSOR FOR
2148 SELECT M.member_id, M.memeber_type, M.ref_count
2150 WHERE M.list_id = :mid;
2151 EXEC SQL OPEN m4_cursor;
2153 EXEC SQL FETCH m4_cursor INTO :id, :dtype, :ref;
2154 if (sqlca.sqlcode != 0) break;
2157 dtypes[dcount] = "LIST";
2160 dtypes[dcount] = "USER";
2163 dtypes[dcount] = "STRING";
2166 dtypes[dcount] = "KERBEROS";
2172 descendants[dcount++] = id;
2173 if (dcount >= MAXLISTDEPTH)
2176 EXEC SQL CLOSE m4_cursor;
2177 if (ingres_errno) return(mr_errcode);
2179 return(MR_INTERNAL);
2181 EXEC SQL DECLARE m5_cursor CURSOR FOR
2184 WHERE M.list_id = :lid AND M.member_id = :mid AND M.member_type = :mtype;
2185 EXEC SQL OPEN m5_cursor;
2186 for (a = 0; a < acount; a++) {
2188 for (d = 0; d < dcount; d++) {
2189 mid = descendants[d];
2191 if (mid == lid && !strcmp(mtype, "LIST")) {
2192 return(MR_LISTLOOP);
2194 EXEC SQL FETCH m5_cursor INTO :cnt;
2195 if (sqlca.sqlcode != 0) break;
2196 ref = aref[a] * dref[d];
2198 iargv[0] = (char *)lid;
2200 iargv[2] = (char *)mid;
2201 incremental_before("members", 0, iargv);
2204 WHERE list_id = :lid AND member_id = :mid
2205 AND member_type = :mtype;
2206 incremental_clear_after();
2207 } else if (a == 0 && d == 0) {
2208 EXEC SQL UPDATE imembers
2209 SET ref_count = ref_count - :ref, direct = 0
2210 WHERE list_id = :lid AND member_id = :mid
2211 AND member_type = :mtype;
2213 EXEC SQL UPDATE imembers
2214 SET ref_count = ref_count - :ref
2215 WHERE list_id = :lid AND member_id = :mid
2216 AND member_type = :mtype;
2220 EXEC SQL CLOSE m5_cursor;
2221 lid = *(int *)argv[0];
2222 entity = cl->entity;
2223 who = cl->client_id;
2224 EXEC SQL UPDATE list
2225 SET modtime = "now", modby = :who, modwith = :entity
2226 WHERE list = :list_id;
2227 if (ingres_errno) return(mr_errcode);
2232 /* get_ace_use - given a type and a name, return a type and a name.
2233 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2234 * and argv[1] will contain the ID of the entity in question. The R*
2235 * types mean to recursively look at every containing list, not just
2236 * when the object in question is a direct member. On return, the
2237 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2240 int get_ace_use(q, argv, cl, action, actarg)
2248 EXEC SQL BEGIN DECLARE SECTION;
2250 int aid, listid, id;
2251 EXEC SQL END DECLARE SECTION;
2252 struct save_queue *sq, *sq_create();
2255 aid = *(int *)argv[1];
2256 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2257 !strcmp(atype, "KERBEROS")) {
2258 return(get_ace_internal(atype, aid, action, actarg));
2262 if (!strcmp(atype, "RLIST")) {
2263 sq_save_data(sq, aid);
2264 /* get all the list_id's of containing lists */
2265 EXEC SQL DECLARE m6_cursor CURSOR FOR
2268 WHERE M.member_type = "LIST" AND M.member_id = :id;
2269 EXEC SQL OPEN m6_cursor;
2271 EXEC SQL FETCH m6_cursor INTO :listid;
2272 if (sqlca.sqlcode != 0) break;
2273 sq_save_unique_data(sq, listid);
2275 /* now process each one */
2276 while (sq_get_data(sq, &id)) {
2277 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2280 EXEC SQL CLOSE m6_cursor;
2283 if (!strcmp(atype, "RUSER")) {
2284 EXEC SQL DECLARE m7_cursor CURSOR FOR
2287 WHERE M.member_type = "USER" AND M.member_id = :aid;
2288 EXEC SQL OPEN m7_cursor;
2290 EXEC SQL FETCH m7_cursor INTO :listid;
2291 if (sqlca.sqlcode != 0) break;
2292 sq_save_data(sq, listid);
2294 /* now process each one */
2295 while (sq_get_data(sq, &id)) {
2296 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2299 if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2301 EXEC SQL CLOSE m7_cursor;
2304 if (!strcmp(atype, "RKERBERO")) {
2305 EXEC SQL DECLARE m8_cursor CURSOR FOR
2308 WHERE M.member_type = "KERBEROS" AND M.member_id = :aid;
2309 EXEC SQL OPEN m8_cursor;
2311 EXEC SQL FETCH m8_cursor INTO :listid;
2312 if (sqlca.sqlcode != 0) break;
2313 sq_save_data(sq, listid);
2315 /* now process each one */
2316 while (sq_get_data(sq, &id)) {
2317 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2320 if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2322 EXEC SQL CLOSE m8_cursor;
2326 if (ingres_errno) return(mr_errcode);
2327 if (!found) return(MR_NO_MATCH);
2332 /* This looks up a single list or user for ace use. atype must be "USER"
2333 * or "LIST", and aid is the ID of the corresponding object. This is used
2334 * by get_ace_use above.
2337 ##get_ace_internal(atype, aid, action, actarg)
2338 EXEC SQL BEGIN DECLARE SECTION;
2341 EXEC SQL END DECLARE SECTION;
2347 EXEC SQL BEGIN DECLARE SECTION;
2349 EXEC SQL END DECLARE SECTION;
2352 EXEC SQL DECLARE F1_cursor CURSOR FOR
2355 WHERE F.owners = :aid;
2356 EXEC SQL OPEN F1_cursor;
2358 EXEC SQL DECLARE C1_cursor CURSOR FOR
2361 WHERE C.list_id = :aid;
2362 EXEC SQL OPEN C1_cursor;
2364 if (!strcmp(atype, "LIST")) {
2365 rargv[0] = "FILESYS";
2367 EXEC SQL FETCH F1_cursor INTO :name;
2368 if (sqlca.sqlcode != 0) break;
2369 (*action)(2, rargv, actarg);
2374 EXEC SQL FETCH C1_cursor INTO :name;
2375 if (sqlca.sqlcode != 0) break;
2376 (*action)(2, rargv, actarg);
2379 } else if (!strcmp(atype, "USER")) {
2380 rargv[0] = "FILESYS";
2382 EXEC SQL FETCH F1_cursor INTO :name;
2383 if (sqlca.sqlcode != 0) break;
2384 (*action)(2, rargv, actarg);
2388 EXEC SQL CLOSE F1_cursor;
2389 EXEC SQL CLOSE C1_cursor;
2392 EXEC SQL DECLARE l8_cursor CURSOR FOR
2395 WHERE L.acl_type = :atype AND L.acl_id = :aid;
2396 EXEC SQL OPEN l8_cursor;
2399 EXEC SQL FETCH l8_cursor INTO :name;
2400 if (sqlca.sqlcode != 0) break;
2401 (*action)(2, rargv, actarg);
2404 EXEC SQL CLOSE l8_cursor;
2406 rargv[0] = "SERVICE";
2407 EXEC SQL DECLARE s_cursor CURSOR FOR
2410 WHERE S.acl_type = :atype AND S.acl_id = :aid;
2411 EXEC SQL OPEN s_cursor;
2414 EXEC SQL FETCH s_cursor INTO :name;
2415 if (sqlca.sqlcode != 0) break;
2416 (*action)(2, rargv, actarg);
2419 EXEC SQL CLOSE s_cursor;
2421 rargv[0] = "HOSTACCESS";
2422 EXEC SQL DECLARE h_cursor CURSOR FOR
2424 FROM MACHINE M, HOSTACCESS H
2425 WHERE M.mach_id = H.mach_id
2426 AND H.acl_type = :atype AND H.acl_id = :aid;
2427 EXEC SQL OPEN h_cursor;
2429 EXEC SQL FETCH h_cursor INTO :name;
2430 if (sqlca.sqlcode != 0) break;
2431 (*action)(2, rargv, actarg);
2434 EXEC SQL CLOSE h_cursor;
2436 rargv[0] = "ZEPHYR";
2437 EXEC SQL DECLARE z_cursor CURSOR FOR
2440 WHERE Z.xmt_type = :atype AND Z.xmt_id = :aid OR
2441 Z.sub_type = :atype AND Z.sub_id = :aid OR
2442 Z.iws_type = :atype AND Z.iws_id = :aid OR
2443 Z.iui_type = :atype AND Z.iui_id = :aid;
2445 EXEC SQL OPEN z_cursor;
2447 EXEC SQL FETCH h_cursor INTO :name;
2448 if (sqlca.sqlcode != 0) break;
2449 (*action)(2, rargv, actarg);
2452 EXEC SQL CLOSE z_cursor;
2454 if (!found) return(MR_NO_MATCH);
2459 /* get_lists_of_member - given a type and a name, return the name and flags
2460 * of all of the lists of the given member. The member_type is one of
2461 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2462 * and argv[1] will contain the ID of the entity in question. The R*
2463 * types mean to recursively look at every containing list, not just
2464 * when the object in question is a direct member.
2467 int get_lists_of_member(q, argv, cl, action, actarg)
2474 int found = 0, direct = 1;
2476 EXEC SQL BEGIN DECLARE SECTION;
2478 int aid, listid, id;
2479 char name[33], active[5], public[5], hidden[5], maillist[5], grp[5];
2480 EXEC SQL END DECLARE SECTION;
2483 aid = *(int *)argv[1];
2484 if (!strcmp(atype, "RLIST")) {
2488 if (!strcmp(atype, "RUSER")) {
2492 if (!strcmp(atype, "RSTRING")) {
2496 if (!strcmp(atype, "RKERBEROS")) {
2505 rargv[4] = maillist;
2507 ## range of m is imembers
2509 ## repeat retrieve (name = list.#name, active = text(list.#active),
2510 ## public = text(list.#public), hidden = text(list.#hidden),
2511 ## maillist = text(list.#maillist), grp = text(list.#group))
2512 ## where list.list_id = m.list_id and m.direct = 1 and
2513 ## m.member_type = @atype and m.member_id = @aid {
2514 (*action)(6, rargv, actarg);
2518 ## repeat retrieve (name = list.#name, active = text(list.#active),
2519 ## public = text(list.#public), hidden = text(list.#hidden),
2520 ## maillist = text(list.#maillist), grp = text(list.#group))
2521 ## where list.list_id = m.list_id and
2522 ## m.member_type = @atype and m.member_id = @aid {
2523 (*action)(6, rargv, actarg);
2528 if (ingres_errno) return(mr_errcode);
2529 if (!found) return(MR_NO_MATCH);
2534 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2535 * the five flags associated with each list. It will return the name of
2536 * each list that meets the quailifications. It does this by building a
2537 * where clause based on the arguments, then doing a retrieve.
2540 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
2542 int qualified_get_lists(q, argv, cl, action, actarg)
2549 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2550 "l", "name", lflags));
2554 /** get_members_of_list - optimized query for retrieval of list members
2557 ** argv[0] - list_id
2560 ** - retrieve USER members, then LIST members, then STRING members
2563 get_members_of_list(q, argv, cl, action, actarg)
2570 EXEC SQL BEGIN DECLARE SECTION;
2571 int list_id, member_id;
2572 char member_name[129], member_type[9];
2573 EXEC SQL END DECLARE SECTION;
2576 struct save_queue *sq;
2578 list_id = *(int *)argv[0];
2582 EXEC SQL DECLARE m9_cursor CURSOR FOR
2583 SELECT M.member_type, M.member_id
2585 WHERE M.list_id = :list_id AND M.direct = 1;
2586 EXEC SQL OPEN m9_cursor;
2588 EXEC SQL FETCH m9_cursor INTO :member_type, :member_id;
2589 if (sqlca.sqlcode != 0) break;
2592 sq_save_data(sq, (member_type[0] << 24) | (member_id & 0xffffff));
2594 EXEC SQL CLOSE m9_cursor;
2595 if (members <= 49) {
2596 targv[1] = malloc(0);
2597 while (sq_remove_data(sq, &member_id)) {
2598 switch (member_id >> 24) {
2601 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
2602 (*action)(2, targv, actarg);
2606 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
2607 (*action)(2, targv, actarg);
2610 targv[0] = "STRING";
2611 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2612 (*action)(2, targv, actarg);
2615 targv[0] = "KERBEROS";
2616 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2617 (*action)(2, targv, actarg);
2621 return(MR_INTERNAL);
2630 targv[1] = member_name;
2632 ## range of m is imembers
2633 ## repeat retrieve (member_name = users.login)
2634 ## where m.#list_id = @list_id and m.#member_type = "USER"
2635 ## and m.#member_id = users.users_id and m.direct = 1
2636 ## sort by #member_name
2638 (*action)(2, targv, actarg);
2640 if (ingres_errno) return(mr_errcode);
2643 ## repeat retrieve (member_name = list.name)
2644 ## where m.#list_id = @list_id and m.#member_type = "LIST"
2645 ## and m.#member_id = list.#list_id and m.direct = 1
2646 ## sort by #member_name
2648 (*action)(2, targv, actarg);
2650 if (ingres_errno) return(mr_errcode);
2652 targv[0] = "STRING";
2653 ## repeat retrieve (member_name = strings.string)
2654 ## where m.#list_id = @list_id and m.#member_type = "STRING"
2655 ## and m.#member_id = strings.string_id and m.direct = 1
2656 ## sort by #member_name
2658 (*action)(2, targv, actarg);
2660 if (ingres_errno) return(mr_errcode);
2662 targv[0] = "KERBEROS";
2663 ## repeat retrieve (member_name = strings.string)
2664 ## where m.#list_id = @list_id and m.#member_type = "KERBEROS"
2665 ## and m.#member_id = strings.string_id and m.direct = 1
2666 ## sort by #member_name
2668 (*action)(2, targv, actarg);
2670 if (ingres_errno) return(mr_errcode);
2676 /* count_members_of_list: this is a simple query, but it cannot be done
2677 * through the dispatch table.
2680 int count_members_of_list(q, argv, cl, action, actarg)
2687 EXEC SQL BEGIN DECLARE SECTION;
2689 EXEC SQL END DECLARE SECTION;
2690 char *rargv[1], countbuf[5];
2692 list = *(int *)argv[0];
2693 rargv[0] = countbuf;
2694 ## repeat retrieve (ct = count(imembers.list_id
2695 ## where imembers.list_id = @list and
2696 ## imembers.direct = 1))
2697 if (ingres_errno) return(mr_errcode);
2698 sprintf(countbuf, "%d", ct);
2699 (*action)(1, rargv, actarg);
2704 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2705 * the three flags associated with each service. It will return the name of
2706 * each service that meets the quailifications. It does this by building a
2707 * where clause based on the arguments, then doing a retrieve.
2710 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2712 int qualified_get_server(q, argv, cl, action, actarg)
2719 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2720 "s", "name", sflags));
2724 /* generic qualified get routine, used by qualified_get_lists,
2725 * qualified_get_server, and qualified_get_serverhost.
2727 * start - a simple where clause, must not be empty
2728 * range - the name of the range variable
2729 * field - the field to return
2730 * flags - an array of strings, names of the flag variables
2733 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2743 EXEC SQL BEGIN DECLARE SECTION;
2744 char name[33], qual[256], *rvar, *rtbl, *rfield;
2746 char stmt_2_str[SQL_LONG_STR];
2747 EXEC SQL END DECLARE SECTION;
2748 char *rargv[1], buf[32];
2750 EXEC SQL DECLARE stmt_2 STATEMENT;
2751 EXEC SQL DECLARE r9_cursor CURSOR FOR stmt_2;
2753 strcpy(qual, start);
2754 for (i = 0; i < q->argc; i++) {
2755 if (!strcmp(argv[i], "TRUE")) {
2756 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2757 (void) strcat(qual, buf);
2758 } else if (!strcmp(argv[i], "FALSE")) {
2759 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2760 (void) strcat(qual, buf);
2769 sprintf( stmt_2_str, "SELECT %s FROM RTBL R WHERE %s",
2772 EXEC SQL PREPARE stmt_2 FROM :stmt_2_str;
2773 EXEC SQL DESCRIBE stnt_2 INTO SQLDA;
2775 EXEC SQL OPEN r9_cursor;
2777 EXEC SQL FETCH r9_cursor INTO :name;
2778 if (sqlca.sqlcode != 0) break;
2779 (*action)(1, rargv, actarg);
2781 EXEC SQL CLOSE r9_cursor;
2782 if (ingres_errno) return(mr_errcode);
2783 if (sqlca.sqlcode == 100) return(MR_NO_MATCH);
2788 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2789 * the five flags associated with each serverhost. It will return the name of
2790 * each service and host that meets the quailifications. It does this by
2791 * building a where clause based on the arguments, then doing a retrieve.
2794 static char *shflags[6] = { "service", "enable", "override", "success",
2795 "inprogress", "hosterror" };
2797 int qualified_get_serverhost(q, argv, cl, action, actarg)
2804 EXEC SQL BEGIN DECLARE SECTION;
2805 char sname[33], mname[33], qual[256];
2807 char stmt_3_str[SQL_LONG_STR];
2808 EXEC SQL END DECLARE SECTION;
2809 char *rargv[2], buf[32];
2811 EXEC SQL DECLARE stmt_3 STATEMENT;
2812 EXEC SQL DECLARE s9_cursor CURSOR FOR stmt_3;
2814 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2816 for (i = 1; i < q->argc; i++) {
2817 if (!strcmp(argv[i], "TRUE")) {
2818 sprintf(buf, " and sh.%s != 0", shflags[i]);
2820 } else if (!strcmp(argv[i], "FALSE")) {
2821 sprintf(buf, " and sh.%s = 0", shflags[i]);
2828 sprintf( stmt_3_str,
2829 "SELECT S.service, M.name FROM SERVERHOSTS S, MACHINE M WHERE %s",
2831 EXEC SQL PREPARE stmt_3 FROM :stmt_3_str;
2832 EXEC SQL DESCRIBE stnt_3 INTO SQLDA;
2834 EXEC SQL OPEN s9_cursor;
2836 EXEC SQL FETCH s9_cursor INTO :sname, :mname;
2837 if (sqlca.sqlcode != 0) break;
2838 (*action)(2, rargv, actarg);
2840 EXEC SQL CLOSE s9_cursor;
2841 if (ingres_errno) return(mr_errcode);
2842 if (sqlca.sqlcode == 100) return(MR_NO_MATCH);
2847 /* register_user - change user's login name and allocate a pobox, group,
2848 * filesystem, and quota for them. The user's status must start out as 0,
2849 * and is left as 2. Arguments are: user's UID, new login name, and user's
2850 * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY,
2851 * MR_FS_STAFF, MR_FS_MISC).
2854 register_user(q, argv, cl)
2859 EXEC SQL BEGIN DECLARE SECTION;
2860 char *login, dir[65], *entity, *directory, machname[33];
2861 int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2862 int size, alloc, pid, m_id;
2863 EXEC SQL END DECLARE SECTION;
2864 char buffer[256], *aargv[3];
2867 entity = cl->entity;
2868 who = cl->client_id;
2870 uid = atoi(argv[0]);
2872 utype = atoi(argv[2]);
2874 ## range of u is users
2875 ## range of l is list
2876 ## range of sh is serverhosts
2877 ## range of n is nfsphys
2878 ## range of m is machine
2881 EXEC SQL DECLARE u_cursor CURSOR FOR
2884 WHERE U.uid = :uid AND (U.status = 0 OR U.status = 5 OR U.status = 6);
2885 EXEC SQL OPEN u_cursor;
2887 EXEC SQL FETCH u_cursor INTO :users_id;
2888 if (sqlca.sqlcode != 0) break;
2890 if (sqlca.sqlcode == 100) return(MR_NO_MATCH);
2891 if (sqlca.sqlerrd[2] > 1) return(MR_NOT_UNIQUE);
2893 /* check new login name */
2894 ## repeat retrieve (flag = any(u.#login where u.#login = @login and
2895 ## u.#users_id != users_id))
2896 if (ingres_errno) return(mr_errcode);
2897 if (flag) return(MR_IN_USE);
2898 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2899 if (ingres_errno) return(mr_errcode);
2900 if (flag) return(MR_IN_USE);
2901 ## repeat retrieve (flag = any(filesys.#label where filesys.#label = @login))
2902 if (ingres_errno) return(mr_errcode);
2903 if (flag) return(MR_IN_USE);
2904 com_err(whoami, 0, "new login name OK");
2906 /* choose place for pobox, put in mid */
2908 ## repeat retrieve (mid = sh.mach_id, machname = m.name)
2909 ## where sh.service = "POP" and m.mach_id = sh.mach_id and
2910 ## sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2911 if (ingres_errno) return(mr_errcode);
2912 if (sqlca.sqlcode == 100) return(MR_NO_POBOX);
2914 /* change login name, set pobox */
2915 sprintf(buffer, "u.users_id = %d", users_id);
2916 incremental_before("users", buffer, 0);
2917 ## repeat replace u (#login = @login, status = 2, modtime = "now",
2918 ## modby = @who, modwith = @entity, potype="POP",
2919 ## pop_id = @mid, pmodtime="now", pmodby=@who,
2920 ## pmodwith=@entity)
2921 ## where u.#users_id = @users_id
2922 if (ingres_errno) return(mr_errcode);
2923 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2924 return(MR_INTERNAL);
2925 set_pop_usage(mid, 1);
2926 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2928 incremental_after("users", buffer, 0);
2930 /* create group list */
2931 if (set_next_object_id("gid", "list"))
2933 if (set_next_object_id("list_id", "list"))
2936 EXEC SQL DECLARE v_cursor CURSOR FOR
2939 WHERE V.name = "list_id";
2940 EXEC SQL OPEN v_cursor;
2942 EXEC SQL FETCH v_cursor INTO :list_id;
2943 if (sqlca.sqlcode != 0) break;
2945 EXEC SQL CLOSE v_cursor;
2947 if (ingres_errno) return(mr_errcode);
2948 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2949 return(MR_INTERNAL);
2950 incremental_clear_before();
2951 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2952 ## public = 0, hidden = 0, maillist = 0, group = 1,
2953 ## #gid = values_tbl.value, desc = "User Group",
2954 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2955 ## modby = @who, modwith = @entity)
2956 ## where values_tbl.name = "gid"
2957 if (ingres_errno) return(mr_errcode);
2958 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2959 return(MR_INTERNAL);
2960 sprintf(buffer, "l.list_id = %d", list_id);
2961 incremental_after("list", buffer, 0);
2962 aargv[0] = (char *) list_id;
2964 aargv[2] = (char *) users_id;
2965 incremental_clear_before();
2966 ## repeat append imembers (#list_id = @list_id, member_type = "USER",
2967 ## member_id = @users_id, ref_count = 1, direct = 1)
2968 if (ingres_errno) return(mr_errcode);
2969 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2970 return(MR_INTERNAL);
2972 incremental_after("members", 0, aargv);
2973 com_err(whoami, 0, "group list created");
2975 /* decide where to put filesystem */
2978 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2979 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2980 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2981 maxsize = size - alloc;
2984 directory = strsave(dir);
2989 if (ingres_errno) return(mr_errcode);
2991 return(MR_NO_FILESYS);
2993 /* create filesystem */
2994 if (set_next_object_id("filsys_id", "filesys"))
2996 incremental_clear_before();
2997 ## repeat append filesys (filsys_id = values_tbl.value, phys_id = @pid,
2998 ## label = @login, type = "NFS", mach_id = @m_id,
2999 ## name = @directory + "/" + @login,
3000 ## mount = "/mit/" + @login,
3001 ## access = "w", comments = "User Locker",
3002 ## owner = @users_id, owners = @list_id, createflg = 1,
3003 ## lockertype = "HOMEDIR", modtime = "now",
3004 ## modby = @who, modwith = @entity)
3005 ## where values_tbl.name = "filsys_id"
3006 if (ingres_errno) return(mr_errcode);
3007 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3008 return(MR_INTERNAL);
3009 incremental_after("filesys",
3010 "fs.filsys_id = values_tbl.value and values_tbl.name = \"filsys_id\"",
3012 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
3016 ## repeat retrieve (quota = values_tbl.value) where values_tbl.name = "def_quota"
3017 if (ingres_errno) return(mr_errcode);
3018 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3019 return(MR_NO_QUOTA);
3020 incremental_clear_before();
3021 ## repeat append #quota (entity_id = @users_id, filsys_id = values_tbl.value,
3023 ## #quota = @quota, phys_id = @pid, modtime = "now",
3024 ## modby = @who, modwith = @entity)
3025 ## where values_tbl.name = "filsys_id"
3026 if (ingres_errno) return(mr_errcode);
3027 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3028 return(MR_INTERNAL);
3029 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
3030 ## where nfsphys.nfsphys_id = filesys.#phys_id and
3031 ## filesys.filsys_id = values_tbl.value and values_tbl.name = "filsys_id"
3032 if (ingres_errno) return(mr_errcode);
3033 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3034 return(MR_INTERNAL);
3038 sprintf(buffer, "q.entity_id = %d and q.filsys_id = values_tbl.value and q.type = \"USER\" and values_tbl.name = \"filsys_id\"", users_id);
3039 incremental_after("quota", buffer, aargv);
3040 com_err(whoami, 0, "quota of %d assigned", quota);
3041 if (ingres_errno) return(mr_errcode);
3043 cache_entry(login, "USER", users_id);
3045 EXEC SQL UPDATE tblstats
3046 SET updates = tblstats.updates + 1, modtime = "now"
3047 WHERE table_name = "users"
3049 EXEC SQL UPDATE tblstats
3050 SET appends = tblstats.appends + 1, modtime = "now"
3051 WHERE table_name = "list" OR table_name = "filesys"
3052 OR table_name = "quota";
3054 if (ingres_errno) return(mr_errcode);
3060 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
3064 ** delta (will be +/- 1)
3067 ** - incr/decr value field in serverhosts table for pop/mach_id
3071 static int set_pop_usage(id, count)
3075 EXEC SQL BEGIN DECLARE SECTION;
3078 EXEC SQL END DECLARE SECTION;
3080 EXEC SQL UPDATE serverhosts
3081 SET value1 = value1 + :n
3082 WHERE service = "POP" AND mach_id = :mach_id;
3084 if (ingres_errno) return(mr_errcode);
3090 /* Validation Routines */
3092 validate_row(q, argv, v)
3093 register struct query *q;
3095 register struct validate *v;
3097 EXEC SQL BEGIN DECLARE SECTION;
3103 EXEC SQL END DECLARE SECTION;
3105 /* build where clause */
3106 build_qual(v->qual, v->argc, argv, qual);
3108 /* setup ingres variables */
3113 if (log_flags & LOG_VALID)
3114 /* tell the logfile what we're doing */
3115 com_err(whoami, 0, "validating row: %s", qual);
3117 /* look for the record */
3118 ## range of rvar is tbl
3119 ## retrieve (rowcount = count(rvar.name where qual))
3120 if (ingres_errno) return(mr_errcode);
3121 if (rowcount == 0) return(MR_NO_MATCH);
3122 if (rowcount > 1) return(MR_NOT_UNIQUE);
3126 validate_fields(q, argv, vo, n)
3128 register char *argv[];
3129 register struct valobj *vo;
3132 register int status;
3137 if (log_flags & LOG_VALID)
3138 com_err(whoami, 0, "validating %s in %s: %s",
3139 vo->namefield, vo->table, argv[vo->index]);
3140 status = validate_name(argv, vo);
3144 if (log_flags & LOG_VALID)
3145 com_err(whoami, 0, "validating %s in %s: %s",
3146 vo->idfield, vo->table, argv[vo->index]);
3147 status = validate_id(argv, vo);
3151 if (log_flags & LOG_VALID)
3152 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
3153 status = validate_date(argv, vo);
3157 if (log_flags & LOG_VALID)
3158 com_err(whoami, 0, "validating %s type: %s",
3159 vo->table, argv[vo->index]);
3160 status = validate_type(argv, vo);
3164 if (log_flags & LOG_VALID)
3165 com_err(whoami, 0, "validating typed data (%s): %s",
3166 argv[vo->index - 1], argv[vo->index]);
3167 status = validate_typedata(q, argv, vo);
3171 if (log_flags & LOG_VALID)
3172 com_err(whoami, 0, "validating rename %s in %s",
3173 argv[vo->index], vo->table);
3174 status = validate_rename(argv, vo);
3178 if (log_flags & LOG_VALID)
3179 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
3180 status = validate_chars(argv[vo->index]);
3188 status = lock_table(vo);
3192 if (status != MR_EXISTS) return(status);
3196 if (ingres_errno) return(mr_errcode);
3201 /* validate_chars: verify that there are no illegal characters in
3202 * the string. Legal characters are printing chars other than
3203 * ", *, ?, \, [ and ].
3205 static int illegalchars[] = {
3206 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
3207 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
3208 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
3209 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
3210 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
3211 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
3212 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
3213 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
3214 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3215 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3216 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3217 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3218 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3219 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3220 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3221 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3228 if (illegalchars[*s++])
3229 return(MR_BAD_CHAR);
3234 validate_id(argv, vo)
3236 register struct valobj *vo;
3238 EXEC SQL BEGIN DECLARE SECTION;
3244 EXEC SQL END DECLARE SECTION;
3249 name = argv[vo->index];
3251 namefield = vo->namefield;
3252 idfield = vo->idfield;
3254 if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
3255 !strcmp(tbl, "machine") ||
3256 !strcmp(tbl, "filesys") ||
3257 !strcmp(tbl, "list") ||
3258 !strcmp(tbl, "cluster") ||
3259 !strcmp(tbl, "string")) {
3260 if (!strcmp(tbl, "machine"))
3261 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3262 status = name_to_id(name, tbl, &id);
3264 *(int *)argv[vo->index] = id;
3266 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
3272 if (!strcmp(namefield, "uid")) {
3273 ## retrieve (id = tbl.idfield) where tbl.namefield = int4(name)
3274 if (ingres_errno) return(mr_errcode);
3276 ## retrieve (id = table.idfield) where table.namefield = name
3277 if (ingres_errno) return(mr_errcode);
3279 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3281 *(int *)argv[vo->index] = id;
3285 validate_name(argv, vo)
3287 register struct valobj *vo;
3289 EXEC SQL BEGIN DECLARE SECTION;
3294 EXEC SQL END DECLARE SECTION;
3297 name = argv[vo->index];
3299 namefield = vo->namefield;
3300 if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
3301 for (c = name; *c; c++)
3305 ## retrieve (rowcount = countu(tbl.namefield
3306 ## where tbl.namefield = name))
3307 if (ingres_errno) return(mr_errcode);
3308 return ((rowcount == 1) ? MR_EXISTS : vo->error);
3311 validate_date(argv, vo)
3315 EXEC SQL BEGIN DECLARE SECTION;
3319 EXEC SQL END DECLARE SECTION;
3321 idate = argv[vo->index];
3323 ## retrieve (dd = interval("years", date(idate) - date("today")))
3324 if (sqlca.sqlcode < 0 || dd > 5.0) return(MR_DATE);
3329 validate_rename(argv, vo)
3333 EXEC SQL BEGIN DECLARE SECTION;
3334 char *name, *tbl, *namefield, *idfield;
3336 EXEC SQL END DECLARE SECTION;
3340 c = name = argv[vo->index];
3342 if (illegalchars[*c++])
3343 return(MR_BAD_CHAR);
3345 /* minor kludge to upcasify machine names */
3346 if (!strcmp(tbl, "machine"))
3347 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3348 namefield = vo->namefield;
3349 idfield = vo->idfield;
3352 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3354 ## retrieve (id = any(tbl.namefield where tbl.namefield = name))
3355 if (ingres_errno) return(mr_errcode);
3361 status = name_to_id(name, tbl, &id);
3362 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3369 validate_type(argv, vo)
3371 register struct valobj *vo;
3373 EXEC SQL BEGIN DECLARE SECTION;
3377 EXEC SQL END DECLARE SECTION;
3380 typename = vo->table;
3381 c = value = argv[vo->index];
3383 if (illegalchars[*c++])
3384 return(MR_BAD_CHAR);
3386 /* uppercase type fields */
3387 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
3389 ## repeat retrieve (exist = any(alias.trans where alias.name = @typename and
3390 ## alias.type = "TYPE" and alias.trans = @value))
3391 if (ingres_errno) return(mr_errcode);
3392 return (exist ? MR_EXISTS : vo->error);
3395 /* validate member or type-specific data field */
3397 validate_typedata(q, argv, vo)
3398 register struct query *q;
3399 register char *argv[];
3400 register struct valobj *vo;
3402 EXEC SQL BEGIN DECLARE SECTION;
3405 char data_type[129];
3407 EXEC SQL END DECLARE SECTION;
3413 /* get named object */
3414 name = argv[vo->index];
3416 /* get field type string (known to be at index-1) */
3417 field_type = argv[vo->index-1];
3419 /* get corresponding data type associated with field type name */
3420 ## repeat retrieve (data_type = alias.trans)
3421 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
3422 if (ingres_errno) return(mr_errcode);
3423 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3426 /* now retrieve the record id corresponding to the named object */
3427 if (index(data_type, ' '))
3428 *index(data_type, ' ') = 0;
3429 if (!strcmp(data_type, "user")) {
3431 status = name_to_id(name, data_type, &id);
3432 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3434 if (status) return(status);
3435 } else if (!strcmp(data_type, "list")) {
3437 status = name_to_id(name, data_type, &id);
3438 if (status && status == MR_NOT_UNIQUE)
3440 if (status == MR_NO_MATCH) {
3441 /* if idfield is non-zero, then if argv[0] matches the string
3442 * that we're trying to resolve, we should get the value of
3443 * values_tbl.[idfield] for the id.
3445 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3446 set_next_object_id(q->validate->object_id, q->rtable);
3448 ## repeat retrieve (id = values_tbl.value) where values_tbl.#name = @name
3449 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3453 } else if (status) return(status);
3454 } else if (!strcmp(data_type, "machine")) {
3456 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3457 status = name_to_id(name, data_type, &id);
3458 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3460 if (status) return(status);
3461 } else if (!strcmp(data_type, "string")) {
3463 status = name_to_id(name, data_type, &id);
3464 if (status && status == MR_NOT_UNIQUE)
3466 if (status == MR_NO_MATCH) {
3467 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3468 ## retrieve (id = values_tbl.value) where values_tbl.#name = "strings_id"
3470 ## replace values_tbl.(value = id) where values_tbl.#name = "strings_id"
3471 ## append to strings (string_id = id, string = name)
3472 } else if (status) return(status);
3473 } else if (!strcmp(data_type, "none")) {
3479 /* now set value in argv */
3480 *(int *)argv[vo->index] = id;
3486 /* Lock the table named by the validation object */
3491 EXEC SQL BEGIN DECLARE SECTION;
3492 char *tbl, *idfield;
3494 EXEC SQL END DECLARE SECTION;
3497 idfield = vo->idfield;
3498 ## replace tbl (modtime = "now") where tbl.idfield = 0
3499 if (ingres_errno) return(mr_errcode);
3500 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3507 /* Check the database at startup time. For now this just resets the
3508 * inprogress flags that the DCM uses.
3511 sanity_check_database()