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>
18 #include "mr_server.h"
20 EXEC SQL INCLUDE SQLCA; /* SQL Communications Area */
21 EXEC SQL INCLUDE SQLDA; /* SQL Descriptor Area */
23 extern char *whoami, *strsave();
24 extern int ingres_errno, mr_errcode;
27 /* Specialized Access Routines */
29 /* access_user - verify that client name equals specified login name
31 * - since field validation routines are called first, a users_id is
32 * now in argv[0] instead of the login name.
35 access_user(q, argv, cl)
40 if (cl->users_id != *(int *)argv[0])
48 /* access_login - verify that client name equals specified login name
50 * argv[0...n] contain search info. q->
53 access_login(q, argv, cl)
59 EXEC SQL BEGIN DECLARE SECTION;
62 char stmt_1_str[SQL_LONG_STR];
63 EXEC SQL END DECLARE SECTION;
65 EXEC SQL DECLARE stmt_1 STATEMENT;
67 build_qual(q->qual, q->argc, argv, qual);
70 "SELECT users_id INTO %s FROM users WHERE %s",
73 EXEC SQL PREPARE stmt_1 FROM :stmt_1_str;
74 EXEC SQL DESCRIBE stmt_1 INTO SQLDA;
75 EXEC SQL EXECUTE stmt_1;
76 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1 || id != cl->users_id)
85 /* access_list - check access for most list operations
87 * Inputs: argv[0] - list_id
89 * argv[2] - member ID (only for queries "amtl" and "dmfl")
90 * argv[7] - group IID (only for query "ulis")
93 * - check that client is a member of the access control list
94 * - OR, if the query is add_member_to_list or delete_member_from_list
95 * and the list is public, allow access if client = member
98 access_list(q, argv, cl)
103 EXEC SQL BEGIN DECLARE SECTION;
104 int list_id, acl_id, flags, rowcount, gid;
106 EXEC SQL END DECLARE SECTION;
108 int client_id, status;
110 list_id = *(int *)argv[0];
111 EXEC SQL SELECT acl_id, acl_type, gid, public
112 INTO :acl_id, :acl_type, :gid, :flags
114 WHERE list_id = :list_id;
115 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
118 /* parse client structure */
119 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
122 /* if amtl or dmfl and list is public allow client to add or delete self */
123 if (((!strcmp("amtl", q->shortname) && flags) ||
124 (!strcmp("dmfl", q->shortname))) &&
125 (!strcmp("USER", argv[1]))) {
126 if (*(int *)argv[2] == client_id) return(MR_SUCCESS);
127 /* if update_list, don't allow them to change the GID */
128 } else if (!strcmp("ulis", q->shortname)) {
129 if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
130 (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
134 /* check for client in access control list */
135 status = find_member(acl_type, acl_id, client_type, client_id, 0);
136 if (!status) return(MR_PERM);
142 /* access_visible_list - allow access to list only if it is not hidden,
143 * or if the client is on the ACL
145 * Inputs: argv[0] - list_id
146 * cl - client identifier
149 access_visible_list(q, argv, cl)
154 EXEC SQL BEGIN DECLARE SECTION;
155 int list_id, acl_id, flags, rowcount;
157 EXEC SQL END DECLARE SECTION;
159 int client_id, status;
161 list_id = *(int *)argv[0];
162 EXEC SQL SELECT hidden, acl_id, acl_type
163 INTO :flags, :acl_id, :acl_type
165 WHERE list_id = :list_id;
166 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
172 /* parse client structure */
173 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
176 /* check for client in access control list */
177 status = find_member(acl_type, acl_id, client_type, client_id, 0);
185 /* access_vis_list_by_name - allow access to list only if it is not hidden,
186 * or if the client is on the ACL
188 * Inputs: argv[0] - list name
189 * cl - client identifier
192 access_vis_list_by_name(q, argv, cl)
197 EXEC SQL BEGIN DECLARE SECTION;
198 int acl_id, flags, rowcount;
199 char acl_type[9], *listname;
200 EXEC SQL END DECLARE SECTION;
202 int client_id, status;
205 EXEC SQL SELECT hidden, acl_id, acl_type
206 INTO :flags, :acl_id, :acl_type
208 WHERE name = :listname;
209 if (sqlca.sqlerrd[2] > 1) return(MR_WILDCARD);
210 if (sqlca.sqlcode == 100) return(MR_NO_MATCH);
214 /* parse client structure */
215 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
218 /* check for client in access control list */
219 status = find_member(acl_type, acl_id, client_type, client_id, 0);
227 /* access_member - allow user to access member of type "USER" and name matches
228 * username, or to access member of type "LIST" and list is one that user is
229 * on the acl of, or the list is visible.
232 access_member(q, argv, cl)
237 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
238 return(access_visible_list(q, &argv[1], cl));
240 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
241 if (cl->users_id == *(int *)argv[1])
249 /* access_qgli - special access routine for Qualified_get_lists. Allows
250 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
253 access_qgli(q, argv, cl)
258 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
264 /* access_service - allow access if user is on ACL of service. Don't
265 * allow access if a wildcard is used.
268 access_service(q, argv, cl)
273 EXEC SQL BEGIN DECLARE SECTION;
274 int acl_id, rowcount;
275 char *name, acl_type[9];
276 EXEC SQL END DECLARE SECTION;
277 int client_id, status;
282 EXEC SQL SELECT acl_id, acl_type
283 INTO :acl_id, :acl_type
286 if (sqlca.sqlerrd[2] > 1) return(MR_PERM);
287 /* parse client structure */
288 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
291 /* check for client in access control list */
292 status = find_member(acl_type, acl_id, client_type, client_id, 0);
293 if (!status) return(MR_PERM);
300 /* access_filesys - verify that client is owner or on owners list of filesystem
304 access_filesys(q, argv, cl)
309 EXEC SQL BEGIN DECLARE SECTION;
310 int users_id, list_id;
312 EXEC SQL END DECLARE SECTION;
313 int status, client_id;
317 EXEC SQL SELECT owner, owners
318 INTO :users_id, :list_id
321 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
324 if (users_id == cl->users_id)
326 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
328 status = find_member("LIST", list_id, client_type, client_id, 0);
339 /* Setup routine for add_user
341 * Inputs: argv[0] - login
346 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
347 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
350 setup_ausr(q, argv, cl)
352 register char *argv[];
355 EXEC SQL BEGIN DECLARE SECTION;
358 EXEC SQL END DECLARE SECTION;
361 /* this is currently disabled because we need an index on ID's
362 * before it can run in finite time.
364 mit_id = argv[U_MITID];
365 ## retrieve (rowcount = any(u.#mit_id where u.#mit_id = mit_id))
366 if (ingres_errno) return(mr_errcode);
367 if (rowcount) return(MR_EXISTS);
370 if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
371 if (set_next_object_id("uid", "users"))
372 return(MR_INGRES_ERR);
373 EXEC SQL SELECT value
377 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
379 sprintf(argv[1], "%d", nuid);
382 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
383 sprintf(argv[0], "#%s", argv[1]);
390 /* setup_dusr - verify that the user is no longer being referenced
391 * and may safely be deleted.
394 int setup_dusr(q, argv)
398 EXEC SQL BEGIN DECLARE SECTION;
400 EXEC SQL END DECLARE SECTION;
402 id = *(int *)argv[0];
404 /* For now, only allow users to be deleted if their status is 0 */
405 ## repeat retrieve (flag = u.status) where u.users_id = @id
406 if (flag != 0 && flag != 4)
409 ## repeat delete quota where quota.entity_id = @id and quota.type = "USER"
410 ## repeat delete krbmap where krbmap.users_id = @id
411 ## repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
412 ## and imembers.member_type = "USER"))
415 ## repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
418 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
419 ## list.acl_type = "USER"))
422 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
423 ## servers.acl_type = "USER"))
426 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
427 ## hostaccess.acl_type = "USER"))
436 /* setup_spop: verify that there is already a valid POP machine_id in the
437 * pop_id field. Also take care of keeping track of the post office usage.
439 int setup_spop(q, argv)
443 EXEC SQL BEGIN DECLARE SECTION;
446 EXEC SQL END DECLARE SECTION;
448 id = *(int *)argv[0];
449 ## repeat retrieve (type = u.potype, mid = u.pop_id,
450 ## flag = any(machine.name where machine.mach_id = u.pop_id
451 ## and u.pop_id != 0 and u.users_id = @id))
452 ## where u.users_id = @id
455 if (strcmp(strtrim(type), "POP"))
456 set_pop_usage(mid, 1);
461 /* setup_dpob: Take care of keeping track of the post office usage.
463 int setup_dpob(q, argv)
467 EXEC SQL BEGIN DECLARE SECTION;
470 EXEC SQL END DECLARE SECTION;
472 user = *(int *)argv[0];
473 EXEC SQL SELECT potype, pop_id
476 WHERE users_id = :user;
477 if (ingres_errno) return(mr_errcode);
479 if (!strcmp(strtrim(type), "POP"))
480 set_pop_usage(id, -1);
485 /* setup_dmac - verify that the machine is no longer being referenced
486 * and may safely be deleted.
489 int setup_dmac(q, argv)
493 EXEC SQL BEGIN DECLARE SECTION;
495 EXEC SQL END DECLARE SECTION;
497 id = *(int *)argv[0];
498 ## repeat retrieve (flag = any(users.login where users.potype = "POP"
499 ## and users.pop_id=@id))
502 ## repeat retrieve (flag = any(serverhosts.mach_id
503 ## where serverhosts.mach_id=@id))
506 ## repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
509 ## repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
512 ## repeat retrieve (flag = any(printcap.mach_id where printcap.mach_id=@id))
515 ## repeat retrieve (flag = any(printcap.quotaserver where printcap.quotaserver=@id))
518 ## repeat retrieve (flag = any(palladium.mach_id where palladium.mach_id=@id))
522 ## repeat delete mcmap where mcmap.mach_id = @id
523 if (ingres_errno) return(mr_errcode);
528 /* setup_dclu - verify that the cluster is no longer being referenced
529 * and may safely be deleted.
532 int setup_dclu(q, argv)
536 EXEC SQL BEGIN DECLARE SECTION;
538 EXEC SQL END DECLARE SECTION;
540 id = *(int *)argv[0];
541 ## repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
544 ## repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
553 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
554 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
555 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
556 * a -1 there. Remember that this is also used for ulis, with the indexes
560 int setup_alis(q, argv)
564 EXEC SQL BEGIN DECLARE SECTION;
566 EXEC SQL END DECLARE SECTION;
570 if (!strcmp(q->shortname, "alis"))
572 else if (!strcmp(q->shortname, "ulis"))
575 if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
576 if (atoi(argv[idx - 1])) {
577 if (set_next_object_id("gid", "list"))
578 return(MR_INGRES_ERR);
579 EXEC SQL SELECT value
583 if (ingres_errno) return(mr_errcode);
584 sprintf(argv[idx], "%d", ngid);
586 strcpy(argv[idx], "-1");
594 /* setup_dlist - verify that the list is no longer being referenced
595 * and may safely be deleted.
598 int setup_dlis(q, argv)
602 EXEC SQL BEGIN DECLARE SECTION;
604 EXEC SQL END DECLARE SECTION;
606 id = *(int *)argv[0];
607 ## repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
608 ## and imembers.member_type = "LIST"))
611 ## repeat retrieve (flag = any(imembers.member_id where imembers.list_id=@id))
614 ## repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
617 ## repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
620 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
621 ## list.acl_type = "LIST" and list.list_id != @id))
624 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
625 ## servers.acl_type = "LIST"))
628 ## repeat retrieve (flag = any(quota.entity_id where quota.entity_id=@id and
629 ## quota.type = "GROUP"))
632 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
633 ## hostaccess.acl_type = "LIST"))
636 ## repeat retrieve (flag = any(zephyr.class
637 ## where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
638 ## zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
639 ## zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
640 ## zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
649 /* setup_dsin - verify that the service is no longer being referenced
650 * and may safely be deleted.
653 int setup_dsin(q, argv)
657 EXEC SQL BEGIN DECLARE SECTION;
660 EXEC SQL END DECLARE SECTION;
663 ## repeat retrieve (flag = any(serverhosts.service
664 ## where serverhosts.service=uppercase(@name)))
667 EXEC SQL SELECT inprogress
679 /* setup_dshi - verify that the service-host is no longer being referenced
680 * and may safely be deleted.
683 int setup_dshi(q, argv)
687 EXEC SQL BEGIN DECLARE SECTION;
690 EXEC SQL END DECLARE SECTION;
693 id = *(int *)argv[1];
695 EXEC SQL SELECT inprogress
698 WHERE service = :name AND mach_id = :id;
708 ** setup_add_filesys - verify existance of referenced file systems
720 ** * extract directory prefix from name
721 ** * verify mach_id/dir in nfsphys
722 ** * verify access in {r, w, R, W}
724 ** Side effect: sets variable var_phys_id to the ID of the physical
725 ** filesystem (nfsphys_id for NFS, 0 for RVD)
728 ** MR_NFS - specified directory not exported
729 ** MR_FILESYS_ACCESS - invalid filesys access
733 ##static int var_phys_id;
741 EXEC SQL BEGIN DECLARE SECTION;
743 char ftype[32], *access;
744 EXEC SQL END DECLARE SECTION;
747 mach_id = *(int *)argv[2];
752 sprintf(ftype, "fs_access_%s", type);
753 ## retrieve (ok = any(alias.trans where alias.name = ftype and
754 ## alias.type = "TYPE" and alias.trans = access))
755 if (ingres_errno) return(mr_errcode);
756 if (ok == 0) return(MR_FILESYS_ACCESS);
758 if (!strcmp(type, "NFS"))
759 return (check_nfs(mach_id, name, access));
765 /* Verify the arguments, depending on the FStype. Also, if this is an
766 * NFS filesystem, then update any quotas for that filesystem to reflect
770 setup_ufil(q, argv, cl)
777 EXEC SQL BEGIN DECLARE SECTION;
779 char *entity, ftype[32], *access;
780 EXEC SQL END DECLARE SECTION;
783 mach_id = *(int *)argv[3];
787 fid = *(int *)argv[0];
791 sprintf(ftype, "fs_access_%s", type);
792 ## retrieve (total = any(alias.trans where alias.name = ftype and
793 ## alias.type = "TYPE" and alias.trans = access))
794 if (ingres_errno) return(mr_errcode);
795 if (total == 0) return(MR_FILESYS_ACCESS);
797 if (!strcmp(type, "NFS")) {
798 status = check_nfs(mach_id, name, access);
799 ## replace quota (phys_id = var_phys_id) where quota.filsys_id = fid
800 if (ingres_errno) return(mr_errcode);
802 } else if (!strcmp(type, "AFS")) {
804 ## retrieve (total = sum(quota.quota where quota.filsys_id = fid
805 ## and quota.phys_id != 0))
806 if (ingres_errno) return(mr_errcode);
808 ## append quota (quota = total, filsys_id = fid,
809 ## phys_id = 0, entity_id = 0, type = "ANY",
810 ## modtime = "now", modby = who, modwith = entity)
811 if (ingres_errno) return(mr_errcode);
814 ## replace quota (phys_id = 0) where quota.filsys_id = fid
815 if (ingres_errno) return(mr_errcode);
821 /* Find the NFS physical partition that the named directory is on.
822 * This is done by comparing the dir against the mount point of the
823 * partition. To make sure we get the correct match when there is
824 * more than one, we sort the query in reverse order by dir name.
827 ##check_nfs(mach_id, name, access)
828 EXEC SQL BEGIN DECLARE SECTION;
830 EXEC SQL END DECLARE SECTION;
834 EXEC SQL BEGIN DECLARE SECTION;
836 EXEC SQL END DECLARE SECTION;
843 ## range of np is nfsphys
844 ## repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
845 ## where np.#mach_id = @mach_id sort by #dir:d {
849 if (*cp1++ != *cp2) break;
863 /* setup_dfil: free any quota records and fsgroup info associated with
864 * a filesystem when it is deleted. Also adjust the allocation numbers.
867 setup_dfil(q, argv, cl)
872 EXEC SQL BEGIN DECLARE SECTION;
874 EXEC SQL END DECLARE SECTION;
876 id = *(int *)argv[0];
877 ## range of q is quota
878 ## range of n is nfsphys
879 ## repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
880 ## where n.nfsphys_id = filesys.phys_id and filesys.filsys_id = @id
882 ## repeat delete q where q.filsys_id = @id
883 ## repeat delete fsgroup where fsgroup.filsys_id = @id
884 ## repeat delete fsgroup where fsgroup.group_id = @id
885 if (ingres_errno) return(mr_errcode);
890 /* setup_dnfp: check to see that the nfs physical partition does not have
891 * any filesystems assigned to it before allowing it to be deleted.
894 setup_dnfp(q, argv, cl)
899 EXEC SQL BEGIN DECLARE SECTION;
902 EXEC SQL END DECLARE SECTION;
904 id = *(int *)argv[0];
906 ## repeat retrieve (exist = any(filesys.label where filesys.mach_id = @id
907 ## and filesys.phys_id = nfsphys.nfsphys_id and
908 ## nfsphys.mach_id = @id and nfsphys.#dir = @dir))
917 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
918 * argv[0] = filsys_id
919 * argv[1] = type if "update_quota" or "delete_quota"
920 * argv[2 or 1] = users_id or list_id
923 setup_dqot(q, argv, cl)
928 EXEC SQL BEGIN DECLARE SECTION;
931 EXEC SQL END DECLARE SECTION;
933 fs = *(int *)argv[0];
934 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
936 id = *(int *)argv[2];
939 id = *(int *)argv[1];
941 EXEC SQL SELECT quota_value
944 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
945 ## repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
946 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
947 if (ingres_errno) return(mr_errcode);
952 /* setup_sshi: don't exclusive lock the machine table during
953 * set_server_host_internal.
956 setup_sshi(q, argv, cl)
961 ## set lockmode session where readlock = system
965 /* setup add_kerberos_user_mapping: add the string to the string
966 * table if necessary.
969 setup_akum(q, argv, cl)
974 EXEC SQL BEGIN DECLARE SECTION;
977 EXEC SQL END DECLARE SECTION;
980 if (name_to_id(name, "STRING", &id) != MR_SUCCESS) {
981 if (q->type != APPEND) return(MR_STRING);
982 EXEC SQL SELECT value
985 WHERE name = "strings_id";
987 ## replace v (value = id) where v.#name = "strings_id"
988 ## append to strings (string_id = id, string = name)
989 cache_entry(name, "STRING", id);
991 if (ingres_errno) return(mr_errcode);
992 *(int *)argv[1] = id;
998 /* FOLLOWUP ROUTINES */
1000 /* generic set_modtime routine. This takes the table name from the query,
1001 * and will update the modtime, modby, and modwho fields in the entry in
1002 * the table whose name field matches argv[0].
1005 set_modtime(q, argv, cl)
1010 EXEC SQL BEGIN DECLARE SECTION;
1011 char *name, *entity, *tbl;
1013 EXEC SQL END DECLARE SECTION;
1015 entity = cl->entity;
1016 who = cl->client_id;
1020 ## replace tbl (modtime = "now", modby = who, modwith = entity)
1021 ## where tbl.#name = name
1025 /* generic set_modtime_by_id routine. This takes the table name from
1026 * the query, and the id name from the validate record,
1027 * and will update the modtime, modby, and modwho fields in the entry in
1028 * the table whose id matches argv[0].
1031 set_modtime_by_id(q, argv, cl)
1036 EXEC SQL BEGIN DECLARE SECTION;
1037 char *entity, *tbl, *id_name;
1039 EXEC SQL END DECLARE SECTION;
1041 entity = cl->entity;
1042 who = cl->client_id;
1044 id_name = q->validate->object_id;
1046 id = *(int *)argv[0];
1047 ## replace tbl (modtime = "now", modby = who, modwith = entity)
1048 ## where tbl.id_name = id
1053 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
1056 set_finger_modtime(q, argv, cl)
1061 EXEC SQL BEGIN DECLARE SECTION;
1064 EXEC SQL END DECLARE SECTION;
1066 entity = cl->entity;
1067 who = cl->client_id;
1068 users_id = *(int *)argv[0];
1070 ## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
1071 ## where u.#users_id = @users_id
1076 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
1079 set_pobox_modtime(q, argv, cl)
1084 EXEC SQL BEGIN DECLARE SECTION;
1087 EXEC SQL END DECLARE SECTION;
1089 entity = cl->entity;
1090 who = cl->client_id;
1091 users_id = *(int *)argv[0];
1093 ## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
1094 ## where users.#users_id = @users_id
1099 /* Like set_modtime, but uppercases the name first.
1102 set_uppercase_modtime(q, argv, cl)
1107 EXEC SQL BEGIN DECLARE SECTION;
1108 char *name, *entity, *tbl;
1110 EXEC SQL END DECLARE SECTION;
1112 entity = cl->entity;
1113 who = cl->client_id;
1117 ## replace tbl (modtime = "now", modby = who, modwith = entity)
1118 ## where tbl.#name = uppercase(name)
1123 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
1124 * is necessary for add_machine_to_cluster becuase the table that query
1125 * operates on is "mcm", not "machine".
1128 set_mach_modtime_by_id(q, argv, cl)
1133 EXEC SQL BEGIN DECLARE SECTION;
1136 EXEC SQL END DECLARE SECTION;
1138 entity = cl->entity;
1139 who = cl->client_id;
1141 id = *(int *)argv[0];
1142 ## repeat replace machine (modtime = "now", modby = @who, modwith = @entity)
1143 ## where machine.mach_id = @id
1148 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
1149 * is necessary for add_cluster_data and delete_cluster_data becuase the
1150 * table that query operates on is "svc", not "cluster".
1153 set_cluster_modtime_by_id(q, argv, cl)
1158 EXEC SQL BEGIN DECLARE SECTION;
1161 EXEC SQL END DECLARE SECTION;
1163 entity = cl->entity;
1164 who = cl->client_id;
1166 id = *(int *)argv[0];
1167 ## repeat replace cluster (modtime = "now", modby = @who, modwith = @entity)
1168 ## where cluster.clu_id = @id
1173 /* sets the modtime on the serverhost where the service name is in argv[0]
1174 * and the mach_id is in argv[1].
1177 set_serverhost_modtime(q, argv, cl)
1182 EXEC SQL BEGIN DECLARE SECTION;
1183 char *entity, *serv;
1185 EXEC SQL END DECLARE SECTION;
1187 entity = cl->entity;
1188 who = cl->client_id;
1191 id = *(int *)argv[1];
1192 ## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
1193 ## where sh.service = uppercase(@serv) and sh.mach_id = @id
1198 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1199 * directory name is in argv[1].
1202 set_nfsphys_modtime(q, argv, cl)
1207 EXEC SQL BEGIN DECLARE SECTION;
1210 EXEC SQL END DECLARE SECTION;
1212 entity = cl->entity;
1213 who = cl->client_id;
1215 id = *(int *)argv[0];
1217 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1218 ## where np.#dir = @dir and np.mach_id = @id
1223 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1227 set_filesys_modtime(q, argv, cl)
1232 EXEC SQL BEGIN DECLARE SECTION;
1233 char *label, *entity;
1235 EXEC SQL END DECLARE SECTION;
1237 entity = cl->entity;
1238 who = cl->client_id;
1241 if (!strcmp(q->shortname, "ufil"))
1244 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1245 ## #phys_id = @var_phys_id) where fs.#label = @label
1250 /* sets the modtime on a zephyr class, where argv[0] contains the class
1254 set_zephyr_modtime(q, argv, cl)
1259 EXEC SQL BEGIN DECLARE SECTION;
1260 char *class, *entity;
1262 EXEC SQL END DECLARE SECTION;
1264 entity = cl->entity;
1265 who = cl->client_id;
1269 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1270 ## where z.#class = @class
1275 /* fixes the modby field. This will be the second to last thing in the
1276 * argv, the argv length is determined from the query structure. It is
1277 * passed as a pointer to an integer. This will either turn it into a
1278 * username, or # + the users_id.
1280 followup_fix_modby(q, sq, v, action, actarg, cl)
1282 register struct save_queue *sq;
1284 register int (*action)();
1285 register int actarg;
1289 char **argv, *malloc();
1293 while (sq_get_data(sq, &argv)) {
1296 status = id_to_name(id, "USER", &argv[i]);
1298 status = id_to_name(-id, "STRING", &argv[i]);
1299 if (status && status != MR_NO_MATCH)
1301 (*action)(q->vcnt, argv, actarg);
1302 for (j = 0; j < q->vcnt; j++)
1312 ** followup_ausr - add finger and pobox entries, set_user_modtime
1315 ** argv[0] - login (add_user)
1316 ** argv[3] - last name
1317 ** argv[4] - first name
1318 ** argv[5] - middle name
1322 followup_ausr(q, argv, cl)
1327 EXEC SQL BEGIN DECLARE SECTION;
1329 char *login, *entity;
1331 EXEC SQL END DECLARE SECTION;
1334 who = cl->client_id;
1335 entity = cl->entity;
1337 /* build fullname */
1338 if (strlen(argv[4]) && strlen(argv[5]))
1339 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1340 else if (strlen(argv[4]))
1341 sprintf(fullname, "%s %s", argv[4], argv[3]);
1343 sprintf(fullname, "%s", argv[3]);
1345 /* create finger entry, pobox & set modtime on user */
1346 ## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1347 ## #fullname=@fullname, mit_affil = u.mit_year,
1348 ## fmodtime="now", fmodby=@who, fmodwith=@entity,
1349 ## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1350 ## where u.#login = @login
1356 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1357 * type in argv[1]. Then completes the upcall to the user.
1359 * argv[2] is of the form "123:234" where the first integer is the machine
1360 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1361 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1365 followup_gpob(q, sq, v, action, actarg, cl)
1366 register struct query *q;
1367 register struct save_queue *sq;
1368 register struct validate *v;
1369 register int (*action)();
1373 char **argv, *index();
1375 int mid, sid, status;
1378 while (sq_get_data(sq, &argv)) {
1379 mr_trim_args(2, argv);
1381 p = index(argv[2], ':');
1383 mid = atoi(argv[2]);
1386 if (!strcmp(ptype, "POP")) {
1387 status = id_to_name(mid, "MACHINE", &argv[2]);
1388 if (status == MR_NO_MATCH)
1390 } else if (!strcmp(ptype, "SMTP")) {
1391 status = id_to_name(sid, "STRING", &argv[2]);
1392 if (status == MR_NO_MATCH)
1394 } else /* ptype == "NONE" */ {
1397 if (status) return(status);
1399 if (!strcmp(q->shortname, "gpob")) {
1400 sid = atoi(argv[4]);
1402 status = id_to_name(sid, "USER", &argv[4]);
1404 status = id_to_name(-sid, "STRING", &argv[4]);
1406 if (status && status != MR_NO_MATCH) return(status);
1408 (*action)(q->vcnt, argv, actarg);
1410 /* free saved data */
1418 return (MR_SUCCESS);
1422 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1423 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1424 * proper name based on the type, and repace that string in the argv.
1425 * Also fixes the modby field by called followup_fix_modby.
1428 followup_glin(q, sq, v, action, actarg, cl)
1429 register struct query *q;
1430 register struct save_queue *sq;
1431 register struct validate *v;
1432 register int (*action)();
1436 char **argv, *malloc(), *realloc(), *type;
1437 int id, i, idx, status;
1440 if (!strcmp(q->shortname, "gsin"))
1443 while (sq_get_data(sq, &argv)) {
1444 mr_trim_args(q->vcnt, argv);
1446 id = atoi(argv[i = q->vcnt - 2]);
1448 status = id_to_name(id, "USER", &argv[i]);
1450 status = id_to_name(-id, "STRING", &argv[i]);
1451 if (status && status != MR_NO_MATCH)
1454 id = atoi(argv[idx]);
1455 type = argv[idx - 1];
1457 if (!strcmp(type, "LIST")) {
1458 status = id_to_name(id, "LIST", &argv[idx]);
1459 } else if (!strcmp(type, "USER")) {
1460 status = id_to_name(id, "USER", &argv[idx]);
1461 } else if (!strcmp(type, "KERBEROS")) {
1462 status = id_to_name(id, "STRING", &argv[idx]);
1463 } else if (!strcmp(type, "NONE")) {
1466 argv[idx] = strsave("NONE");
1470 argv[idx] = strsave("???");
1472 if (status && status != MR_NO_MATCH)
1475 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1476 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1477 strcpy(argv[6], UNIQUE_GID);
1481 (*action)(q->vcnt, argv, actarg);
1483 /* free saved data */
1484 for (i = 0; i < q->vcnt; i++)
1490 return (MR_SUCCESS);
1494 /* followup_gqot: Fix the entity name, directory name & modby fields
1495 * argv[0] = filsys_id
1497 * argv[2] = entity_id
1498 * argv[3] = ascii(quota)
1501 followup_gqot(q, sq, v, action, actarg, cl)
1503 register struct save_queue *sq;
1505 register int (*action)();
1506 register int actarg;
1510 char **argv, *malloc();
1511 EXEC SQL BEGIN DECLARE SECTION;
1514 EXEC SQL END DECLARE SECTION;
1517 if (!strcmp(q->name, "get_quota") ||
1518 !strcmp(q->name, "get_quota_by_filesys"))
1522 while (sq_get_data(sq, &argv)) {
1524 switch (argv[1][0]) {
1526 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1530 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1534 argv[2] = strsave("system:anyuser");
1538 argv[2] = malloc(8);
1539 sprintf(argv[2], "%d", id);
1542 id = atoi(argv[idx]);
1544 argv[idx] = malloc(256);
1548 EXEC SQL SELECT name
1551 WHERE label = :label;
1556 WHERE nfsphys_id = :id;
1558 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1) {
1559 sprintf(argv[idx], "#%d", id);
1562 id = atoi(argv[idx+3]);
1564 status = id_to_name(id, "USER", &argv[idx+3]);
1566 status = id_to_name(-id, "STRING", &argv[idx+3]);
1567 if (status && status != MR_NO_MATCH)
1569 (*action)(q->vcnt, argv, actarg);
1570 for (j = 0; j < q->vcnt; j++)
1579 /* followup_aqot: Add allocation to nfsphys after creating quota.
1580 * argv[0] = filsys_id
1581 * argv[1] = type if "add_quota" or "update_quota"
1583 * argv[3 or 2] = ascii(quota)
1586 followup_aqot(q, argv, cl)
1591 EXEC SQL BEGIN DECLARE SECTION;
1592 int quota, id, fs, who;
1593 char *entity, *qtype;
1594 EXEC SQL END DECLARE SECTION;
1596 fs = *(int *)argv[0];
1597 if (!strcmp(q->name, "add_quota") || !strcmp(q->name, "update_quota")) {
1599 id = *(int *)argv[2];
1600 quota = atoi(argv[3]);
1603 id = *(int *)argv[1];
1604 quota = atoi(argv[2]);
1606 who = cl->client_id;
1607 entity = cl->entity;
1609 ## repeat replace q (modtime = "now", modby = @who, modwith = @entity)
1610 ## where q.filsys_id = @fs and q.type = @qtype and q.entity_id = @id
1611 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1612 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1613 if (ingres_errno) return(mr_errcode);
1618 followup_gpce(q, sq, v, action, actarg, cl)
1620 register struct save_queue *sq;
1622 register int (*action)();
1623 register int actarg;
1627 char **argv, *malloc();
1631 while (sq_get_data(sq, &argv)) {
1632 id = atoi(argv[PCAP_QSERVER]);
1633 status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
1634 if (status) return (status);
1637 status = id_to_name(id, "USER", &argv[i]);
1639 status = id_to_name(-id, "STRING", &argv[i]);
1640 if (status && status != MR_NO_MATCH)
1642 (*action)(q->vcnt, argv, actarg);
1643 for (j = 0; j < q->vcnt; j++)
1655 followup_gzcl(q, sq, v, action, actarg, cl)
1656 register struct query *q;
1657 register struct save_queue *sq;
1658 register struct validate *v;
1659 register int (*action)();
1666 while (sq_get_data(sq, &argv)) {
1667 mr_trim_args(q->vcnt, argv);
1669 id = atoi(argv[i = q->vcnt - 2]);
1671 status = id_to_name(id, "USER", &argv[i]);
1673 status = id_to_name(-id, "STRING", &argv[i]);
1674 if (status && status != MR_NO_MATCH)
1677 for (i = 1; i < 8; i+=2) {
1678 id = atoi(argv[i+1]);
1679 if (!strcmp(argv[i], "LIST")) {
1680 status = id_to_name(id, "LIST", &argv[i+1]);
1681 } else if (!strcmp(argv[i], "USER")) {
1682 status = id_to_name(id, "USER", &argv[i+1]);
1683 } else if (!strcmp(argv[i], "KERBEROS")) {
1684 status = id_to_name(id, "STRING", &argv[i+1]);
1685 } else if (!strcmp(argv[i], "NONE")) {
1688 argv[i+1] = strsave("NONE");
1692 argv[i+1] = strsave("???");
1694 if (status && status != MR_NO_MATCH)
1699 (*action)(q->vcnt, argv, actarg);
1701 /* free saved data */
1702 for (i = 0; i < q->vcnt; i++)
1714 followup_gsha(q, sq, v, action, actarg, cl)
1715 register struct query *q;
1716 register struct save_queue *sq;
1717 register struct validate *v;
1718 register int (*action)();
1725 while (sq_get_data(sq, &argv)) {
1726 mr_trim_args(q->vcnt, argv);
1730 status = id_to_name(id, "USER", &argv[4]);
1732 status = id_to_name(-id, "STRING", &argv[4]);
1733 if (status && status != MR_NO_MATCH)
1737 if (!strcmp(argv[1], "LIST")) {
1738 status = id_to_name(id, "LIST", &argv[2]);
1739 } else if (!strcmp(argv[1], "USER")) {
1740 status = id_to_name(id, "USER", &argv[2]);
1741 } else if (!strcmp(argv[1], "KERBEROS")) {
1742 status = id_to_name(id, "STRING", &argv[2]);
1743 } else if (!strcmp(argv[1], "NONE")) {
1746 argv[2] = strsave("NONE");
1750 argv[2] = strsave("???");
1752 if (status && status != MR_NO_MATCH)
1756 (*action)(q->vcnt, argv, actarg);
1758 /* free saved data */
1759 for (i = 0; i < q->vcnt; i++)
1769 /* Special query routines */
1771 /* set_pobox - this does all of the real work.
1772 * argv = user_id, type, box
1773 * if type is POP, then box should be a machine, and its ID should be put in
1774 * pop_id. If type is SMTP, then box should be a string and its ID should
1775 * be put in box_id. If type is NONE, then box doesn't matter.
1778 int set_pobox(q, argv, cl)
1783 EXEC SQL BEGIN DECLARE SECTION;
1785 char *box, potype[9];
1786 EXEC SQL END DECLARE SECTION;
1790 user = *(int *)argv[0];
1791 EXEC SQL SELECT pop_id, potype
1794 WHERE users_id = :user;
1795 if (ingres_errno) return(mr_errcode);
1796 if (!strcmp(strtrim(potype), "POP"))
1797 set_pop_usage(id, -1);
1799 if (!strcmp(argv[1], "POP")) {
1800 status = name_to_id(box, "MACHINE", &id);
1801 if (status == MR_NO_MATCH)
1805 ## repeat replace users (#potype = "POP", pop_id = @id)
1806 ## where users.users_id = @user
1807 set_pop_usage(id, 1);
1808 } else if (!strcmp(argv[1], "SMTP")) {
1809 if (index(box, '/') || index(box, '|'))
1810 return(MR_BAD_CHAR);
1811 status = name_to_id(box, "STRING", &id);
1812 if (status == MR_NO_MATCH) {
1813 EXEC SQL SELECT value
1816 WHERE name = "strings_id";
1818 ## repeat replace values_tbl.(value = @id) where values_tbl.name = "strings_id"
1819 ## append to strings (string_id = id, string = box)
1822 ## repeat replace users (#potype = "SMTP", box_id = @id)
1823 ## where users.users_id = @user
1824 } else /* argv[1] == "NONE" */ {
1825 ## repeat replace users (#potype = "NONE") where users.users_id = @user
1828 set_pobox_modtime(q, argv, cl);
1829 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1830 ## where tblstats.#table = "users"
1831 if (ingres_errno) return(mr_errcode);
1836 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1837 * each list. This is tricky: first build a queue of all requested
1838 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1841 get_list_info(q, aargv, cl, action, actarg)
1842 register struct query *q;
1845 register int (*action)();
1848 char *argv[13], *malloc(), *realloc();
1849 EXEC SQL BEGIN DECLARE SECTION;
1850 char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1851 char maillist[5], grp[5], gid[6], acl_name[256], desc[256], modtime[27];
1852 char modby[256], modwith[9];
1853 int id, rowcount, acl_id, hid, modby_id;
1854 EXEC SQL END DECLARE SECTION;
1855 int returned, status;
1856 struct save_queue *sq, *sq_create();
1858 returned = rowcount = 0;
1862 EXEC SQL DECLARE l_cursor CURSOR FOR
1865 WHERE L.name = :name;
1866 EXEC SQL OPEN l_cursor;
1868 EXEC SQL FETCH l_cursor INTO :id;
1869 if (sqlca.sqlcode != 0) break;
1870 sq_save_data(sq, id);
1873 EXEC SQL CLOSE l_cursor;
1874 if (ingres_errno) return(mr_errcode);
1876 return(MR_NO_MATCH);
1878 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1879 argv[4] = maillist; argv[5] = grp; argv[6] = gid; argv[7] = acl_type;
1880 argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
1882 while (sq_get_data(sq, &id)) {
1886 ## repeat retrieve (listname = l.#name, active = text(l.#active),
1887 ## public = text(l.#public), hidden = text(l.#hidden),
1888 ## hid = l.#hidden, maillist = text(l.#maillist),
1889 ## group = text(l.#grp), gid = text(l.#gid),
1890 ## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1891 ## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1892 ## modwith =l.#modwith)
1893 ## where l.list_id = @id
1894 if (ingres_errno) return(mr_errcode);
1896 if (atoi(gid) == -1)
1897 argv[6] = UNIQUE_GID;
1899 argv[8] = malloc(0);
1900 if (!strcmp(acl_type, "LIST")) {
1901 status = id_to_name(acl_id, "LIST", &argv[8]);
1902 } else if (!strcmp(acl_type, "USER")) {
1903 status = id_to_name(acl_id, "USER", &argv[8]);
1904 } else if (!strcmp(acl_type, "KERBEROS")) {
1905 status = id_to_name(acl_id, "STRING", &argv[8]);
1906 } else if (!strcmp(acl_type, "NONE")) {
1909 argv[8] = strsave("NONE");
1913 argv[8] = strsave("???");
1915 if (status && status != MR_NO_MATCH) return(status);
1917 argv[11] = malloc(0);
1919 status = id_to_name(modby_id, "USER", &argv[11]);
1921 status = id_to_name(-modby_id, "STRING", &argv[11]);
1922 if (status && status != MR_NO_MATCH) return(status);
1924 mr_trim_args(q->vcnt, argv);
1926 (*action)(q->vcnt, argv, actarg);
1932 if (ingres_errno) return(mr_errcode);
1933 return (MR_SUCCESS);
1937 /* Add_member_to_list: do list flattening as we go! MAXLISTDEPTH is
1938 * how many different ancestors a member is allowed to have.
1941 #define MAXLISTDEPTH 1024
1943 int add_member_to_list(q, argv, cl)
1948 EXEC SQL BEGIN DECLARE SECTION;
1949 int id, lid, mid, exist, error, who, ref;
1950 char *mtype, dtype[9], *entity;
1951 EXEC SQL END DECLARE SECTION;
1952 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
1953 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
1955 char *dtypes[MAXLISTDEPTH];
1956 char *iargv[3], *buf;
1958 EXEC SQL DECLARE m_cursor_a CURSOR FOR
1959 SELECT M.list_id, M.ref_count
1961 WHERE M.member_id = :lid AND M.member_type = "LIST";
1962 EXEC SQL OPEN m_cursor_a;
1964 lid = *(int *)argv[0];
1966 mid = *(int *)argv[2];
1967 /* if the member is already a direct member of the list, punt */
1968 ## repeat retrieve (exist = any(m.list_id where m.list_id=@lid and
1969 ## m.member_id = @mid and m.member_type = @mtype
1970 ## and m.direct = 1))
1973 if (!strcasecmp(mtype, "STRING")) {
1975 status = id_to_name(mid, "STRING", &buf);
1976 if (status) return(status);
1977 if (index(buf, '/') || index(buf, '|')) {
1979 return(MR_BAD_CHAR);
1988 EXEC SQL FETCH m_cursor_a INTO :id, :ref;
1989 if (sqlca.sqlcode != 0) break;
1991 ancestors[acount++] = id;
1992 if (acount >= MAXLISTDEPTH) {
1993 return(MR_INTERNAL);
1996 if (ingres_errno) return(mr_errcode);
1997 if (acount >= MAXLISTDEPTH) {
1998 return(MR_INTERNAL);
2000 EXEC SQL CLOSE m_cursor_a;
2001 descendants[0] = mid;
2008 if (!strcmp(mtype, "LIST")) {
2009 EXEC SQL DECLARE m_cursor_l CURSOR FOR
2010 SELECT M.member_id, M.memeber_type, M.ref_count
2012 WHERE M.list_id = :mid;
2013 EXEC SQL OPEN m_cursor_l;
2015 EXEC SQL FETCH m_cursor_l INTO :id, :dtype, :ref;
2016 if (sqlca.sqlcode != 0) break;
2019 dtypes[dcount] = "LIST";
2022 dtypes[dcount] = "USER";
2025 dtypes[dcount] = "STRING";
2028 dtypes[dcount] = "KERBEROS";
2034 descendants[dcount++] = id;
2035 if (dcount >= MAXLISTDEPTH) {
2039 EXEC SQL CLOSE m_cursor_l;
2040 if (ingres_errno) return(mr_errcode);
2042 return(MR_INTERNAL);
2044 for (a = 0; a < acount; a++) {
2046 for (d = 0; d < dcount; d++) {
2047 mid = descendants[d];
2049 if (mid == lid && !strcmp(mtype, "LIST")) {
2050 return(MR_LISTLOOP);
2052 ## repeat retrieve (exist = any(m.ref_count where m.list_id = @lid
2053 ## and m.member_id = @mid
2054 ## and m.member_type = @mtype))
2055 ref = aref[a] * dref[d];
2057 if (a == 0 && d == 0)
2058 ## replace m (ref_count = m.ref_count+ref, direct = 1)
2059 ## where m.list_id = lid and m.member_id = mid and
2060 ## m.member_type = mtype
2062 ## replace m (ref_count = m.ref_count+ref)
2063 ## where m.list_id = lid and m.member_id = mid and
2064 ## m.member_type = mtype
2066 incremental_clear_before();
2067 if (a == 0 && d == 0)
2068 ## append imembers (list_id=lid, member_id = mid, direct = 1,
2069 ## member_type=mtype, ref_count = 1)
2071 ## append imembers (list_id=lid, member_id = mid,
2072 ## member_type=mtype, ref_count = ref)
2073 iargv[0] = (char *)lid;
2075 iargv[2] = (char *)mid;
2076 incremental_after("members", 0, iargv);
2080 lid = *(int *)argv[0];
2081 entity = cl->entity;
2082 who = cl->client_id;
2083 ## repeat replace list (modtime = "now", modby = @who, modwith = @entity)
2084 ## where list.#list_id = @lid
2085 if (ingres_errno) return(mr_errcode);
2090 /* Delete_member_from_list: do list flattening as we go!
2093 int delete_member_from_list(q, argv, cl)
2098 EXEC SQL BEGIN DECLARE SECTION;
2099 int id, lid, mid, cnt, exist, error, who, ref;
2100 char *mtype, dtype[9], *entity;
2101 EXEC SQL END DECLARE SECTION;
2102 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2103 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2104 char *dtypes[MAXLISTDEPTH];
2107 ## range of m is imembers
2108 lid = *(int *)argv[0];
2110 mid = *(int *)argv[2];
2111 /* if the member is not a direct member of the list, punt */
2112 ## repeat retrieve (exist = any(m.list_id where m.list_id=@lid and
2113 ## m.member_id = @mid and m.member_type = @mtype
2114 ## and m.direct = 1))
2115 if (ingres_errno) return(mr_errcode);
2117 return(MR_NO_MATCH);
2122 EXEC SQL DECLARE m3_cursor CURSOR FOR
2123 SELECT M.list_id, M.ref_count
2125 WHERE M.member_id = :lid AND M.member_type = "LIST";
2126 EXEC SQL OPEN m3_cursor;
2128 EXEC SQL FETCH m3_cursor INTO :id, :ref;
2129 if (sqlca.sqlcode != 0) break;
2131 ancestors[acount++] = id;
2132 if (acount >= MAXLISTDEPTH)
2135 EXEC SQL CLOSE m3_cursor;
2136 if (ingres_errno) return(mr_errcode);
2137 if (acount >= MAXLISTDEPTH)
2138 return(MR_INTERNAL);
2139 descendants[0] = mid;
2144 if (!strcmp(mtype, "LIST")) {
2145 EXEC SQL DECLARE m4_cursor CURSOR FOR
2146 SELECT M.member_id, M.memeber_type, M.ref_count
2148 WHERE M.list_id = :mid;
2149 EXEC SQL OPEN m4_cursor;
2151 EXEC SQL FETCH m4_cursor INTO :id, :dtype, :ref;
2152 if (sqlca.sqlcode != 0) break;
2155 dtypes[dcount] = "LIST";
2158 dtypes[dcount] = "USER";
2161 dtypes[dcount] = "STRING";
2164 dtypes[dcount] = "KERBEROS";
2170 descendants[dcount++] = id;
2171 if (dcount >= MAXLISTDEPTH)
2174 EXEC SQL CLOSE m4_cursor;
2175 if (ingres_errno) return(mr_errcode);
2177 return(MR_INTERNAL);
2179 EXEC SQL DECLARE m5_cursor CURSOR FOR
2182 WHERE M.list_id = :lid AND M.member_id = :mid AND M.member_type = :mtype;
2183 EXEC SQL OPEN m5_cursor;
2184 for (a = 0; a < acount; a++) {
2186 for (d = 0; d < dcount; d++) {
2187 mid = descendants[d];
2189 if (mid == lid && !strcmp(mtype, "LIST")) {
2190 return(MR_LISTLOOP);
2192 EXEC SQL FETCH m5_cursor INTO :cnt;
2193 if (sqlca.sqlcode != 0) break;
2194 ref = aref[a] * dref[d];
2196 iargv[0] = (char *)lid;
2198 iargv[2] = (char *)mid;
2199 incremental_before("members", 0, iargv);
2202 WHERE list_id = :lid AND member_id = :mid
2203 AND member_type = :mtype;
2204 incremental_clear_after();
2205 } else if (a == 0 && d == 0) {
2206 EXEC SQL UPDATE imembers
2207 SET ref_count = ref_count - :ref, direct = 0
2208 WHERE list_id = :lid AND member_id = :mid
2209 AND member_type = :mtype;
2211 EXEC SQL UPDATE imembers
2212 SET ref_count = ref_count - :ref
2213 WHERE list_id = :lid AND member_id = :mid
2214 AND member_type = :mtype;
2218 EXEC SQL CLOSE m5_cursor;
2219 lid = *(int *)argv[0];
2220 entity = cl->entity;
2221 who = cl->client_id;
2222 EXEC SQL UPDATE list
2223 SET modtime = "now", modby = :who, modwith = :entity
2224 WHERE list = :list_id;
2225 if (ingres_errno) return(mr_errcode);
2230 /* get_ace_use - given a type and a name, return a type and a name.
2231 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2232 * and argv[1] will contain the ID of the entity in question. The R*
2233 * types mean to recursively look at every containing list, not just
2234 * when the object in question is a direct member. On return, the
2235 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2238 int get_ace_use(q, argv, cl, action, actarg)
2246 EXEC SQL BEGIN DECLARE SECTION;
2248 int aid, listid, id;
2249 EXEC SQL END DECLARE SECTION;
2250 struct save_queue *sq, *sq_create();
2253 aid = *(int *)argv[1];
2254 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2255 !strcmp(atype, "KERBEROS")) {
2256 return(get_ace_internal(atype, aid, action, actarg));
2260 if (!strcmp(atype, "RLIST")) {
2261 sq_save_data(sq, aid);
2262 /* get all the list_id's of containing lists */
2263 EXEC SQL DECLARE m6_cursor CURSOR FOR
2266 WHERE M.member_type = "LIST" AND M.member_id = :id;
2267 EXEC SQL OPEN m6_cursor;
2269 EXEC SQL FETCH m6_cursor INTO :listid;
2270 if (sqlca.sqlcode != 0) break;
2271 sq_save_unique_data(sq, listid);
2273 /* now process each one */
2274 while (sq_get_data(sq, &id)) {
2275 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2278 EXEC SQL CLOSE m6_cursor;
2281 if (!strcmp(atype, "RUSER")) {
2282 EXEC SQL DECLARE m7_cursor CURSOR FOR
2285 WHERE M.member_type = "USER" AND M.member_id = :aid;
2286 EXEC SQL OPEN m7_cursor;
2288 EXEC SQL FETCH m7_cursor INTO :listid;
2289 if (sqlca.sqlcode != 0) break;
2290 sq_save_data(sq, listid);
2292 /* now process each one */
2293 while (sq_get_data(sq, &id)) {
2294 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2297 if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2299 EXEC SQL CLOSE m7_cursor;
2302 if (!strcmp(atype, "RKERBERO")) {
2303 EXEC SQL DECLARE m8_cursor CURSOR FOR
2306 WHERE M.member_type = "KERBEROS" AND M.member_id = :aid;
2307 EXEC SQL OPEN m8_cursor;
2309 EXEC SQL FETCH m8_cursor INTO :listid;
2310 if (sqlca.sqlcode != 0) break;
2311 sq_save_data(sq, listid);
2313 /* now process each one */
2314 while (sq_get_data(sq, &id)) {
2315 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2318 if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2320 EXEC SQL CLOSE m8_cursor;
2324 if (ingres_errno) return(mr_errcode);
2325 if (!found) return(MR_NO_MATCH);
2330 /* This looks up a single list or user for ace use. atype must be "USER"
2331 * or "LIST", and aid is the ID of the corresponding object. This is used
2332 * by get_ace_use above.
2335 ##get_ace_internal(atype, aid, action, actarg)
2336 EXEC SQL BEGIN DECLARE SECTION;
2339 EXEC SQL END DECLARE SECTION;
2345 EXEC SQL BEGIN DECLARE SECTION;
2347 EXEC SQL END DECLARE SECTION;
2350 EXEC SQL DECLARE F1_cursor CURSOR FOR
2353 WHERE F.owners = :aid;
2354 EXEC SQL OPEN F1_cursor;
2356 EXEC SQL DECLARE C1_cursor CURSOR FOR
2359 WHERE C.list_id = :aid;
2360 EXEC SQL OPEN C1_cursor;
2362 if (!strcmp(atype, "LIST")) {
2363 rargv[0] = "FILESYS";
2365 EXEC SQL FETCH F1_cursor INTO :name;
2366 if (sqlca.sqlcode != 0) break;
2367 (*action)(2, rargv, actarg);
2372 EXEC SQL FETCH C1_cursor INTO :name;
2373 if (sqlca.sqlcode != 0) break;
2374 (*action)(2, rargv, actarg);
2377 } else if (!strcmp(atype, "USER")) {
2378 rargv[0] = "FILESYS";
2380 EXEC SQL FETCH F1_cursor INTO :name;
2381 if (sqlca.sqlcode != 0) break;
2382 (*action)(2, rargv, actarg);
2386 EXEC SQL CLOSE F1_cursor;
2387 EXEC SQL CLOSE C1_cursor;
2390 EXEC SQL DECLARE l8_cursor CURSOR FOR
2393 WHERE L.acl_type = :atype AND L.acl_id = :aid;
2394 EXEC SQL OPEN l8_cursor;
2397 EXEC SQL FETCH l8_cursor INTO :name;
2398 if (sqlca.sqlcode != 0) break;
2399 (*action)(2, rargv, actarg);
2402 EXEC SQL CLOSE l8_cursor;
2404 rargv[0] = "SERVICE";
2405 EXEC SQL DECLARE s_cursor CURSOR FOR
2408 WHERE S.acl_type = :atype AND S.acl_id = :aid;
2409 EXEC SQL OPEN s_cursor;
2412 EXEC SQL FETCH s_cursor INTO :name;
2413 if (sqlca.sqlcode != 0) break;
2414 (*action)(2, rargv, actarg);
2417 EXEC SQL CLOSE s_cursor;
2419 rargv[0] = "HOSTACCESS";
2420 EXEC SQL DECLARE h_cursor CURSOR FOR
2422 FROM MACHINE M, HOSTACCESS H
2423 WHERE M.mach_id = H.mach_id
2424 AND H.acl_type = :atype AND H.acl_id = :aid;
2425 EXEC SQL OPEN h_cursor;
2427 EXEC SQL FETCH h_cursor INTO :name;
2428 if (sqlca.sqlcode != 0) break;
2429 (*action)(2, rargv, actarg);
2432 EXEC SQL CLOSE h_cursor;
2434 rargv[0] = "ZEPHYR";
2435 EXEC SQL DECLARE z_cursor CURSOR FOR
2438 WHERE Z.xmt_type = :atype AND Z.xmt_id = :aid OR
2439 Z.sub_type = :atype AND Z.sub_id = :aid OR
2440 Z.iws_type = :atype AND Z.iws_id = :aid OR
2441 Z.iui_type = :atype AND Z.iui_id = :aid;
2443 EXEC SQL OPEN z_cursor;
2445 EXEC SQL FETCH h_cursor INTO :name;
2446 if (sqlca.sqlcode != 0) break;
2447 (*action)(2, rargv, actarg);
2450 EXEC SQL CLOSE z_cursor;
2452 if (!found) return(MR_NO_MATCH);
2457 /* get_lists_of_member - given a type and a name, return the name and flags
2458 * of all of the lists of the given member. The member_type is one of
2459 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2460 * and argv[1] will contain the ID of the entity in question. The R*
2461 * types mean to recursively look at every containing list, not just
2462 * when the object in question is a direct member.
2465 int get_lists_of_member(q, argv, cl, action, actarg)
2472 int found = 0, direct = 1;
2474 EXEC SQL BEGIN DECLARE SECTION;
2476 int aid, listid, id;
2477 char name[33], active[5], public[5], hidden[5], maillist[5], grp[5];
2478 EXEC SQL END DECLARE SECTION;
2481 aid = *(int *)argv[1];
2482 if (!strcmp(atype, "RLIST")) {
2486 if (!strcmp(atype, "RUSER")) {
2490 if (!strcmp(atype, "RSTRING")) {
2494 if (!strcmp(atype, "RKERBEROS")) {
2503 rargv[4] = maillist;
2505 ## range of m is imembers
2507 ## repeat retrieve (name = list.#name, active = text(list.#active),
2508 ## public = text(list.#public), hidden = text(list.#hidden),
2509 ## maillist = text(list.#maillist), grp = text(list.#group))
2510 ## where list.list_id = m.list_id and m.direct = 1 and
2511 ## m.member_type = @atype and m.member_id = @aid {
2512 (*action)(6, rargv, actarg);
2516 ## repeat retrieve (name = list.#name, active = text(list.#active),
2517 ## public = text(list.#public), hidden = text(list.#hidden),
2518 ## maillist = text(list.#maillist), grp = text(list.#group))
2519 ## where list.list_id = m.list_id and
2520 ## m.member_type = @atype and m.member_id = @aid {
2521 (*action)(6, rargv, actarg);
2526 if (ingres_errno) return(mr_errcode);
2527 if (!found) return(MR_NO_MATCH);
2532 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2533 * the five flags associated with each list. It will return the name of
2534 * each list that meets the quailifications. It does this by building a
2535 * where clause based on the arguments, then doing a retrieve.
2538 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
2540 int qualified_get_lists(q, argv, cl, action, actarg)
2547 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2548 "l", "name", lflags));
2552 /** get_members_of_list - optimized query for retrieval of list members
2555 ** argv[0] - list_id
2558 ** - retrieve USER members, then LIST members, then STRING members
2561 get_members_of_list(q, argv, cl, action, actarg)
2568 EXEC SQL BEGIN DECLARE SECTION;
2569 int list_id, member_id;
2570 char member_name[129], member_type[9];
2571 EXEC SQL END DECLARE SECTION;
2574 struct save_queue *sq;
2576 list_id = *(int *)argv[0];
2580 EXEC SQL DECLARE m9_cursor CURSOR FOR
2581 SELECT M.member_type, M.member_id
2583 WHERE M.list_id = :list_id AND M.direct = 1;
2584 EXEC SQL OPEN m9_cursor;
2586 EXEC SQL FETCH m9_cursor INTO :member_type, :member_id;
2587 if (sqlca.sqlcode != 0) break;
2590 sq_save_data(sq, (member_type[0] << 24) | (member_id & 0xffffff));
2592 EXEC SQL CLOSE m9_cursor;
2593 if (members <= 49) {
2594 targv[1] = malloc(0);
2595 while (sq_remove_data(sq, &member_id)) {
2596 switch (member_id >> 24) {
2599 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
2600 (*action)(2, targv, actarg);
2604 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
2605 (*action)(2, targv, actarg);
2608 targv[0] = "STRING";
2609 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2610 (*action)(2, targv, actarg);
2613 targv[0] = "KERBEROS";
2614 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2615 (*action)(2, targv, actarg);
2619 return(MR_INTERNAL);
2628 targv[1] = member_name;
2630 ## range of m is imembers
2631 ## repeat retrieve (member_name = users.login)
2632 ## where m.#list_id = @list_id and m.#member_type = "USER"
2633 ## and m.#member_id = users.users_id and m.direct = 1
2634 ## sort by #member_name
2636 (*action)(2, targv, actarg);
2638 if (ingres_errno) return(mr_errcode);
2641 ## repeat retrieve (member_name = list.name)
2642 ## where m.#list_id = @list_id and m.#member_type = "LIST"
2643 ## and m.#member_id = list.#list_id and m.direct = 1
2644 ## sort by #member_name
2646 (*action)(2, targv, actarg);
2648 if (ingres_errno) return(mr_errcode);
2650 targv[0] = "STRING";
2651 ## repeat retrieve (member_name = strings.string)
2652 ## where m.#list_id = @list_id and m.#member_type = "STRING"
2653 ## and m.#member_id = strings.string_id and m.direct = 1
2654 ## sort by #member_name
2656 (*action)(2, targv, actarg);
2658 if (ingres_errno) return(mr_errcode);
2660 targv[0] = "KERBEROS";
2661 ## repeat retrieve (member_name = strings.string)
2662 ## where m.#list_id = @list_id and m.#member_type = "KERBEROS"
2663 ## and m.#member_id = strings.string_id and m.direct = 1
2664 ## sort by #member_name
2666 (*action)(2, targv, actarg);
2668 if (ingres_errno) return(mr_errcode);
2674 /* count_members_of_list: this is a simple query, but it cannot be done
2675 * through the dispatch table.
2678 int count_members_of_list(q, argv, cl, action, actarg)
2685 EXEC SQL BEGIN DECLARE SECTION;
2687 EXEC SQL END DECLARE SECTION;
2688 char *rargv[1], countbuf[5];
2690 list = *(int *)argv[0];
2691 rargv[0] = countbuf;
2692 ## repeat retrieve (ct = count(imembers.list_id
2693 ## where imembers.list_id = @list and
2694 ## imembers.direct = 1))
2695 if (ingres_errno) return(mr_errcode);
2696 sprintf(countbuf, "%d", ct);
2697 (*action)(1, rargv, actarg);
2702 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2703 * the three flags associated with each service. It will return the name of
2704 * each service that meets the quailifications. It does this by building a
2705 * where clause based on the arguments, then doing a retrieve.
2708 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2710 int qualified_get_server(q, argv, cl, action, actarg)
2717 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2718 "s", "name", sflags));
2722 /* generic qualified get routine, used by qualified_get_lists,
2723 * qualified_get_server, and qualified_get_serverhost.
2725 * start - a simple where clause, must not be empty
2726 * range - the name of the range variable
2727 * field - the field to return
2728 * flags - an array of strings, names of the flag variables
2731 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2741 EXEC SQL BEGIN DECLARE SECTION;
2742 char name[33], qual[256], *rvar, *rtbl, *rfield;
2744 char stmt_2_str[SQL_LONG_STR];
2745 EXEC SQL END DECLARE SECTION;
2746 char *rargv[1], buf[32];
2748 EXEC SQL DECLARE stmt_2 STATEMENT;
2749 EXEC SQL DECLARE r9_cursor CURSOR FOR stmt_2;
2751 strcpy(qual, start);
2752 for (i = 0; i < q->argc; i++) {
2753 if (!strcmp(argv[i], "TRUE")) {
2754 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2755 (void) strcat(qual, buf);
2756 } else if (!strcmp(argv[i], "FALSE")) {
2757 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2758 (void) strcat(qual, buf);
2767 sprintf( stmt_2_str, "SELECT %s FROM RTBL R WHERE %s",
2770 EXEC SQL PREPARE stmt_2 FROM :stmt_2_str;
2771 EXEC SQL DESCRIBE stnt_2 INTO SQLDA;
2773 EXEC SQL OPEN r9_cursor;
2775 EXEC SQL FETCH r9_cursor INTO :name;
2776 if (sqlca.sqlcode != 0) break;
2777 (*action)(1, rargv, actarg);
2779 EXEC SQL CLOSE r9_cursor;
2780 if (ingres_errno) return(mr_errcode);
2781 if (sqlca.sqlcode == 100) return(MR_NO_MATCH);
2786 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2787 * the five flags associated with each serverhost. It will return the name of
2788 * each service and host that meets the quailifications. It does this by
2789 * building a where clause based on the arguments, then doing a retrieve.
2792 static char *shflags[6] = { "service", "enable", "override", "success",
2793 "inprogress", "hosterror" };
2795 int qualified_get_serverhost(q, argv, cl, action, actarg)
2802 EXEC SQL BEGIN DECLARE SECTION;
2803 char sname[33], mname[33], qual[256];
2805 char stmt_3_str[SQL_LONG_STR];
2806 EXEC SQL END DECLARE SECTION;
2807 char *rargv[2], buf[32];
2809 EXEC SQL DECLARE stmt_3 STATEMENT;
2810 EXEC SQL DECLARE s9_cursor CURSOR FOR stmt_3;
2812 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2814 for (i = 1; i < q->argc; i++) {
2815 if (!strcmp(argv[i], "TRUE")) {
2816 sprintf(buf, " and sh.%s != 0", shflags[i]);
2818 } else if (!strcmp(argv[i], "FALSE")) {
2819 sprintf(buf, " and sh.%s = 0", shflags[i]);
2826 sprintf( stmt_3_str,
2827 "SELECT S.service, M.name FROM SERVERHOSTS S, MACHINE M WHERE %s",
2829 EXEC SQL PREPARE stmt_3 FROM :stmt_3_str;
2830 EXEC SQL DESCRIBE stnt_3 INTO SQLDA;
2832 EXEC SQL OPEN s9_cursor;
2834 EXEC SQL FETCH s9_cursor INTO :sname, :mname;
2835 if (sqlca.sqlcode != 0) break;
2836 (*action)(2, rargv, actarg);
2838 EXEC SQL CLOSE s9_cursor;
2839 if (ingres_errno) return(mr_errcode);
2840 if (sqlca.sqlcode == 100) return(MR_NO_MATCH);
2845 /* register_user - change user's login name and allocate a pobox, group,
2846 * filesystem, and quota for them. The user's status must start out as 0,
2847 * and is left as 2. Arguments are: user's UID, new login name, and user's
2848 * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY,
2849 * MR_FS_STAFF, MR_FS_MISC).
2852 register_user(q, argv, cl)
2857 EXEC SQL BEGIN DECLARE SECTION;
2858 char *login, dir[65], *entity, *directory, machname[33];
2859 int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2860 int size, alloc, pid, m_id;
2861 EXEC SQL END DECLARE SECTION;
2862 char buffer[256], *aargv[3];
2865 entity = cl->entity;
2866 who = cl->client_id;
2868 uid = atoi(argv[0]);
2870 utype = atoi(argv[2]);
2872 ## range of u is users
2873 ## range of l is list
2874 ## range of sh is serverhosts
2875 ## range of n is nfsphys
2876 ## range of m is machine
2879 EXEC SQL DECLARE u_cursor CURSOR FOR
2882 WHERE U.uid = :uid AND (U.status = 0 OR U.status = 5 OR U.status = 6);
2883 EXEC SQL OPEN u_cursor;
2885 EXEC SQL FETCH u_cursor INTO :users_id;
2886 if (sqlca.sqlcode != 0) break;
2888 if (sqlca.sqlcode == 100) return(MR_NO_MATCH);
2889 if (sqlca.sqlerrd[2] > 1) return(MR_NOT_UNIQUE);
2891 /* check new login name */
2892 ## repeat retrieve (flag = any(u.#login where u.#login = @login and
2893 ## u.#users_id != users_id))
2894 if (ingres_errno) return(mr_errcode);
2895 if (flag) return(MR_IN_USE);
2896 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2897 if (ingres_errno) return(mr_errcode);
2898 if (flag) return(MR_IN_USE);
2899 ## repeat retrieve (flag = any(filesys.#label where filesys.#label = @login))
2900 if (ingres_errno) return(mr_errcode);
2901 if (flag) return(MR_IN_USE);
2902 com_err(whoami, 0, "new login name OK");
2904 /* choose place for pobox, put in mid */
2906 ## repeat retrieve (mid = sh.mach_id, machname = m.name)
2907 ## where sh.service = "POP" and m.mach_id = sh.mach_id and
2908 ## sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2909 if (ingres_errno) return(mr_errcode);
2910 if (sqlca.sqlcode == 100) return(MR_NO_POBOX);
2912 /* change login name, set pobox */
2913 sprintf(buffer, "u.users_id = %d", users_id);
2914 incremental_before("users", buffer, 0);
2915 ## repeat replace u (#login = @login, status = 2, modtime = "now",
2916 ## modby = @who, modwith = @entity, potype="POP",
2917 ## pop_id = @mid, pmodtime="now", pmodby=@who,
2918 ## pmodwith=@entity)
2919 ## where u.#users_id = @users_id
2920 if (ingres_errno) return(mr_errcode);
2921 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2922 return(MR_INTERNAL);
2923 set_pop_usage(mid, 1);
2924 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2926 incremental_after("users", buffer, 0);
2928 /* create group list */
2929 if (set_next_object_id("gid", "list"))
2931 if (set_next_object_id("list_id", "list"))
2934 EXEC SQL DECLARE v_cursor CURSOR FOR
2937 WHERE V.name = "list_id";
2938 EXEC SQL OPEN v_cursor;
2940 EXEC SQL FETCH v_cursor INTO :list_id;
2941 if (sqlca.sqlcode != 0) break;
2943 EXEC SQL CLOSE v_cursor;
2945 if (ingres_errno) return(mr_errcode);
2946 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2947 return(MR_INTERNAL);
2948 incremental_clear_before();
2949 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2950 ## public = 0, hidden = 0, maillist = 0, group = 1,
2951 ## #gid = values_tbl.value, desc = "User Group",
2952 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2953 ## modby = @who, modwith = @entity)
2954 ## where values_tbl.name = "gid"
2955 if (ingres_errno) return(mr_errcode);
2956 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2957 return(MR_INTERNAL);
2958 sprintf(buffer, "l.list_id = %d", list_id);
2959 incremental_after("list", buffer, 0);
2960 aargv[0] = (char *) list_id;
2962 aargv[2] = (char *) users_id;
2963 incremental_clear_before();
2964 ## repeat append imembers (#list_id = @list_id, member_type = "USER",
2965 ## member_id = @users_id, ref_count = 1, direct = 1)
2966 if (ingres_errno) return(mr_errcode);
2967 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
2968 return(MR_INTERNAL);
2970 incremental_after("members", 0, aargv);
2971 com_err(whoami, 0, "group list created");
2973 /* decide where to put filesystem */
2976 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2977 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2978 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2979 maxsize = size - alloc;
2982 directory = strsave(dir);
2987 if (ingres_errno) return(mr_errcode);
2989 return(MR_NO_FILESYS);
2991 /* create filesystem */
2992 if (set_next_object_id("filsys_id", "filesys"))
2994 incremental_clear_before();
2995 ## repeat append filesys (filsys_id = values_tbl.value, phys_id = @pid,
2996 ## label = @login, type = "NFS", mach_id = @m_id,
2997 ## name = @directory + "/" + @login,
2998 ## mount = "/mit/" + @login,
2999 ## access = "w", comments = "User Locker",
3000 ## owner = @users_id, owners = @list_id, createflg = 1,
3001 ## lockertype = "HOMEDIR", modtime = "now",
3002 ## modby = @who, modwith = @entity)
3003 ## where values_tbl.name = "filsys_id"
3004 if (ingres_errno) return(mr_errcode);
3005 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3006 return(MR_INTERNAL);
3007 incremental_after("filesys",
3008 "fs.filsys_id = values_tbl.value and values_tbl.name = \"filsys_id\"",
3010 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
3014 ## repeat retrieve (quota = values_tbl.value) where values_tbl.name = "def_quota"
3015 if (ingres_errno) return(mr_errcode);
3016 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3017 return(MR_NO_QUOTA);
3018 incremental_clear_before();
3019 ## repeat append #quota (entity_id = @users_id, filsys_id = values_tbl.value,
3021 ## #quota = @quota, phys_id = @pid, modtime = "now",
3022 ## modby = @who, modwith = @entity)
3023 ## where values_tbl.name = "filsys_id"
3024 if (ingres_errno) return(mr_errcode);
3025 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3026 return(MR_INTERNAL);
3027 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
3028 ## where nfsphys.nfsphys_id = filesys.#phys_id and
3029 ## filesys.filsys_id = values_tbl.value and values_tbl.name = "filsys_id"
3030 if (ingres_errno) return(mr_errcode);
3031 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3032 return(MR_INTERNAL);
3036 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);
3037 incremental_after("quota", buffer, aargv);
3038 com_err(whoami, 0, "quota of %d assigned", quota);
3039 if (ingres_errno) return(mr_errcode);
3041 cache_entry(login, "USER", users_id);
3043 EXEC SQL UPDATE tblstats
3044 SET updates = tblstats.updates + 1, modtime = "now"
3045 WHERE table_name = "users"
3047 EXEC SQL UPDATE tblstats
3048 SET appends = tblstats.appends + 1, modtime = "now"
3049 WHERE table_name = "list" OR table_name = "filesys"
3050 OR table_name = "quota";
3052 if (ingres_errno) return(mr_errcode);
3058 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
3062 ** delta (will be +/- 1)
3065 ** - incr/decr value field in serverhosts table for pop/mach_id
3069 static int set_pop_usage(id, count)
3073 EXEC SQL BEGIN DECLARE SECTION;
3076 EXEC SQL END DECLARE SECTION;
3078 EXEC SQL UPDATE serverhosts
3079 SET value1 = value1 + :n
3080 WHERE service = "POP" AND mach_id = :mach_id;
3082 if (ingres_errno) return(mr_errcode);
3088 /* Validation Routines */
3090 validate_row(q, argv, v)
3091 register struct query *q;
3093 register struct validate *v;
3095 EXEC SQL BEGIN DECLARE SECTION;
3101 EXEC SQL END DECLARE SECTION;
3103 /* build where clause */
3104 build_qual(v->qual, v->argc, argv, qual);
3106 /* setup ingres variables */
3111 if (log_flags & LOG_VALID)
3112 /* tell the logfile what we're doing */
3113 com_err(whoami, 0, "validating row: %s", qual);
3115 /* look for the record */
3116 ## range of rvar is tbl
3117 ## retrieve (rowcount = count(rvar.name where qual))
3118 if (ingres_errno) return(mr_errcode);
3119 if (rowcount == 0) return(MR_NO_MATCH);
3120 if (rowcount > 1) return(MR_NOT_UNIQUE);
3124 validate_fields(q, argv, vo, n)
3126 register char *argv[];
3127 register struct valobj *vo;
3130 register int status;
3135 if (log_flags & LOG_VALID)
3136 com_err(whoami, 0, "validating %s in %s: %s",
3137 vo->namefield, vo->table, argv[vo->index]);
3138 status = validate_name(argv, vo);
3142 if (log_flags & LOG_VALID)
3143 com_err(whoami, 0, "validating %s in %s: %s",
3144 vo->idfield, vo->table, argv[vo->index]);
3145 status = validate_id(argv, vo);
3149 if (log_flags & LOG_VALID)
3150 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
3151 status = validate_date(argv, vo);
3155 if (log_flags & LOG_VALID)
3156 com_err(whoami, 0, "validating %s type: %s",
3157 vo->table, argv[vo->index]);
3158 status = validate_type(argv, vo);
3162 if (log_flags & LOG_VALID)
3163 com_err(whoami, 0, "validating typed data (%s): %s",
3164 argv[vo->index - 1], argv[vo->index]);
3165 status = validate_typedata(q, argv, vo);
3169 if (log_flags & LOG_VALID)
3170 com_err(whoami, 0, "validating rename %s in %s",
3171 argv[vo->index], vo->table);
3172 status = validate_rename(argv, vo);
3176 if (log_flags & LOG_VALID)
3177 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
3178 status = validate_chars(argv[vo->index]);
3186 status = lock_table(vo);
3190 if (status != MR_EXISTS) return(status);
3194 if (ingres_errno) return(mr_errcode);
3199 /* validate_chars: verify that there are no illegal characters in
3200 * the string. Legal characters are printing chars other than
3201 * ", *, ?, \, [ and ].
3203 static int illegalchars[] = {
3204 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
3205 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
3206 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
3207 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
3208 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
3209 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
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, 0, 0, 0, 0, 1, /* p - ^? */
3212 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3213 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
3226 if (illegalchars[*s++])
3227 return(MR_BAD_CHAR);
3232 validate_id(argv, vo)
3234 register struct valobj *vo;
3236 EXEC SQL BEGIN DECLARE SECTION;
3242 EXEC SQL END DECLARE SECTION;
3247 name = argv[vo->index];
3249 namefield = vo->namefield;
3250 idfield = vo->idfield;
3252 if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
3253 !strcmp(tbl, "machine") ||
3254 !strcmp(tbl, "filesys") ||
3255 !strcmp(tbl, "list") ||
3256 !strcmp(tbl, "cluster") ||
3257 !strcmp(tbl, "string")) {
3258 if (!strcmp(tbl, "machine"))
3259 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3260 status = name_to_id(name, tbl, &id);
3262 *(int *)argv[vo->index] = id;
3264 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
3270 if (!strcmp(namefield, "uid")) {
3271 ## retrieve (id = tbl.idfield) where tbl.namefield = int4(name)
3272 if (ingres_errno) return(mr_errcode);
3274 ## retrieve (id = table.idfield) where table.namefield = name
3275 if (ingres_errno) return(mr_errcode);
3277 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3279 *(int *)argv[vo->index] = id;
3283 validate_name(argv, vo)
3285 register struct valobj *vo;
3287 EXEC SQL BEGIN DECLARE SECTION;
3292 EXEC SQL END DECLARE SECTION;
3295 name = argv[vo->index];
3297 namefield = vo->namefield;
3298 if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
3299 for (c = name; *c; c++)
3303 ## retrieve (rowcount = countu(tbl.namefield
3304 ## where tbl.namefield = name))
3305 if (ingres_errno) return(mr_errcode);
3306 return ((rowcount == 1) ? MR_EXISTS : vo->error);
3309 validate_date(argv, vo)
3313 EXEC SQL BEGIN DECLARE SECTION;
3317 EXEC SQL END DECLARE SECTION;
3319 idate = argv[vo->index];
3321 ## retrieve (dd = interval("years", date(idate) - date("today")))
3322 if (sqlca.sqlcode < 0 || dd > 5.0) return(MR_DATE);
3327 validate_rename(argv, vo)
3331 EXEC SQL BEGIN DECLARE SECTION;
3332 char *name, *tbl, *namefield, *idfield;
3334 EXEC SQL END DECLARE SECTION;
3338 c = name = argv[vo->index];
3340 if (illegalchars[*c++])
3341 return(MR_BAD_CHAR);
3343 /* minor kludge to upcasify machine names */
3344 if (!strcmp(tbl, "machine"))
3345 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3346 namefield = vo->namefield;
3347 idfield = vo->idfield;
3350 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3352 ## retrieve (id = any(tbl.namefield where tbl.namefield = name))
3353 if (ingres_errno) return(mr_errcode);
3359 status = name_to_id(name, tbl, &id);
3360 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3367 validate_type(argv, vo)
3369 register struct valobj *vo;
3371 EXEC SQL BEGIN DECLARE SECTION;
3375 EXEC SQL END DECLARE SECTION;
3378 typename = vo->table;
3379 c = value = argv[vo->index];
3381 if (illegalchars[*c++])
3382 return(MR_BAD_CHAR);
3384 /* uppercase type fields */
3385 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
3387 ## repeat retrieve (exist = any(alias.trans where alias.name = @typename and
3388 ## alias.type = "TYPE" and alias.trans = @value))
3389 if (ingres_errno) return(mr_errcode);
3390 return (exist ? MR_EXISTS : vo->error);
3393 /* validate member or type-specific data field */
3395 validate_typedata(q, argv, vo)
3396 register struct query *q;
3397 register char *argv[];
3398 register struct valobj *vo;
3400 EXEC SQL BEGIN DECLARE SECTION;
3403 char data_type[129];
3405 EXEC SQL END DECLARE SECTION;
3411 /* get named object */
3412 name = argv[vo->index];
3414 /* get field type string (known to be at index-1) */
3415 field_type = argv[vo->index-1];
3417 /* get corresponding data type associated with field type name */
3418 ## repeat retrieve (data_type = alias.trans)
3419 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
3420 if (ingres_errno) return(mr_errcode);
3421 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3424 /* now retrieve the record id corresponding to the named object */
3425 if (index(data_type, ' '))
3426 *index(data_type, ' ') = 0;
3427 if (!strcmp(data_type, "user")) {
3429 status = name_to_id(name, data_type, &id);
3430 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3432 if (status) return(status);
3433 } else if (!strcmp(data_type, "list")) {
3435 status = name_to_id(name, data_type, &id);
3436 if (status && status == MR_NOT_UNIQUE)
3438 if (status == MR_NO_MATCH) {
3439 /* if idfield is non-zero, then if argv[0] matches the string
3440 * that we're trying to resolve, we should get the value of
3441 * values_tbl.[idfield] for the id.
3443 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3444 set_next_object_id(q->validate->object_id, q->rtable);
3446 ## repeat retrieve (id = values_tbl.value) where values_tbl.#name = @name
3447 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3451 } else if (status) return(status);
3452 } else if (!strcmp(data_type, "machine")) {
3454 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3455 status = name_to_id(name, data_type, &id);
3456 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3458 if (status) return(status);
3459 } else if (!strcmp(data_type, "string")) {
3461 status = name_to_id(name, data_type, &id);
3462 if (status && status == MR_NOT_UNIQUE)
3464 if (status == MR_NO_MATCH) {
3465 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3466 ## retrieve (id = values_tbl.value) where values_tbl.#name = "strings_id"
3468 ## replace values_tbl.(value = id) where values_tbl.#name = "strings_id"
3469 ## append to strings (string_id = id, string = name)
3470 } else if (status) return(status);
3471 } else if (!strcmp(data_type, "none")) {
3477 /* now set value in argv */
3478 *(int *)argv[vo->index] = id;
3484 /* Lock the table named by the validation object */
3489 EXEC SQL BEGIN DECLARE SECTION;
3490 char *tbl, *idfield;
3492 EXEC SQL END DECLARE SECTION;
3495 idfield = vo->idfield;
3496 ## replace tbl (modtime = "now") where tbl.idfield = 0
3497 if (ingres_errno) return(mr_errcode);
3498 if (sqlca.sqlcode < 0 || sqlca.sqlerrd[2] != 1)
3505 /* Check the database at startup time. For now this just resets the
3506 * inprogress flags that the DCM uses.
3509 sanity_check_database()