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 "sms_server.h"
22 extern char *whoami, *strsave();
23 extern int ingres_errno, sms_errcode;
26 /* Specialized Access Routines */
28 /* access_user - verify that client name equals specified login name
30 * - since field validation routines are called first, a users_id is
31 * now in argv[0] instead of the login name.
34 access_user(q, argv, cl)
39 if (cl->users_id != *(int *)argv[0])
47 /* access_login - verify that client name equals specified login name
49 * argv[0...n] contain search info. q->
52 access_login(q, argv, cl)
60 build_qual(q->qual, q->argc, argv, qual);
61 ## retrieve (id = u.users_id) where qual
62 ## inquire_equel(rowcount = "rowcount")
63 if (rowcount != 1 || id != cl->users_id)
71 /* access_list - check access for most list operations
73 * Inputs: argv[0] - list_id
75 * argv[2] - member ID (only for queries "amtl" and "dmfl")
76 * argv[7] - group IID (only for query "ulis")
79 * - check that client is a member of the access control list
80 * - OR, if the query is add_member_to_list or delete_member_from_list
81 * and the list is public, allow access if client = member
84 access_list(q, argv, cl)
89 ## int list_id, acl_id, flags, rowcount, gid;
92 int client_id, status;
94 list_id = *(int *)argv[0];
95 ## repeat retrieve (acl_id = list.#acl_id, acl_type = list.#acl_type,
96 ## gid = list.#gid, flags = list.#public)
97 ## where list.#list_id = @list_id
98 ## inquire_equel(rowcount = "rowcount")
100 return(SMS_INTERNAL);
102 /* parse client structure */
103 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
106 /* if amtl or dmfl and list is public allow client to add or delete self */
107 if (((!strcmp("amtl", q->shortname) && flags) ||
108 (!strcmp("dmfl", q->shortname))) &&
109 (!strcmp("USER", argv[1]))) {
110 if (*(int *)argv[2] == client_id) return(SMS_SUCCESS);
111 /* if update_list, don't allow them to change the GID */
112 } else if (!strcmp("ulis", q->shortname)) {
113 if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
114 (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
118 /* check for client in access control list */
119 status = find_member(acl_type, acl_id, client_type, client_id, 0);
120 if (!status) return(SMS_PERM);
126 /* access_visible_list - allow access to list only if it is not hidden,
127 * or if the client is on the ACL
129 * Inputs: argv[0] - list_id
130 * cl - client identifier
133 access_visible_list(q, argv, cl)
138 ## int list_id, acl_id, flags, rowcount;
141 int client_id, status;
143 list_id = *(int *)argv[0];
144 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
145 ## acl_type = list.#acl_type) where list.#list_id = @list_id
146 ## inquire_equel(rowcount = "rowcount")
148 return(SMS_INTERNAL);
152 /* parse client structure */
153 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
156 /* check for client in access control list */
157 status = find_member(acl_type, acl_id, client_type, client_id, 0);
165 /* access_vis_list_by_name - allow access to list only if it is not hidden,
166 * or if the client is on the ACL
168 * Inputs: argv[0] - list name
169 * cl - client identifier
172 access_vis_list_by_name(q, argv, cl)
177 ## int acl_id, flags, rowcount;
178 ## char acl_type[9], *listname;
180 int client_id, status;
183 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
184 ## acl_type = list.#acl_type) where list.#name = @listname
185 ## inquire_equel(rowcount = "rowcount");
187 return(SMS_WILDCARD);
189 return(SMS_NO_MATCH);
193 /* parse client structure */
194 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
197 /* check for client in access control list */
198 status = find_member(acl_type, acl_id, client_type, client_id, 0);
206 /* access_member - allow user to access member of type "USER" and name matches
207 * username, or to access member of type "LIST" and list is one that user is
208 * on the acl of, or the list is visible.
211 access_member(q, argv, cl)
216 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
217 return(access_visible_list(q, &argv[1], cl));
219 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
220 if (cl->users_id == *(int *)argv[1])
228 /* access_qgli - special access routine for Qualified_get_lists. Allows
229 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
232 access_qgli(q, argv, cl)
237 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
243 /* access_service - allow access if user is on ACL of service. Don't
244 * allow access if a wildcard is used.
247 access_service(q, argv, cl)
252 ## int acl_id, rowcount;
253 ## char *name, acl_type[9];
254 int client_id, status;
258 ## repeat retrieve (acl_id = servers.#acl_id, acl_type = servers.#acl_type)
259 ## where servers.#name = uppercase(@name)
260 ## inquire_equel(rowcount = "rowcount")
264 /* parse client structure */
265 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
268 /* check for client in access control list */
269 status = find_member(acl_type, acl_id, client_type, client_id, 0);
270 if (!status) return(SMS_PERM);
277 /* access_filesys - verify that client is owner or on owners list of filesystem
281 access_filesys(q, argv, cl)
286 ## int rowcount, users_id, list_id;
288 int status, client_id;
292 ## repeat retrieve (users_id = filesys.owner, list_id = filesys.owners)
293 ## where filesys.label = @name
294 ## inquire_equel(rowcount = "rowcount")
298 if (users_id == cl->users_id)
300 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
302 status = find_member("LIST", list_id, client_type, client_id, 0);
312 /* Setup routine for add_user
314 * Inputs: argv[0] - login
319 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
320 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
323 setup_ausr(q, argv, cl)
325 register char *argv[];
328 ## int nuid, rowcount;
330 if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
331 if (set_next_object_id("uid", "users"))
332 return(SMS_INGRES_ERR);
333 ## repeat retrieve (nuid = values.value) where values.name = "uid"
334 ## inquire_equel(rowcount = "rowcount")
336 return(SMS_INTERNAL);
337 sprintf(argv[1], "%d", nuid);
340 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
341 sprintf(argv[0], "#%s", argv[1]);
348 /* setup_dusr - verify that the user is no longer being referenced
349 * and may safely be deleted.
352 int setup_dusr(q, argv)
358 id = *(int *)argv[0];
360 /* For now, only allow users to be deleted if their status is 0 */
361 ## repeat retrieve (flag = u.status) where u.users_id = @id
365 ## repeat delete nfsquota where nfsquota.users_id = @id
366 ## repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
367 ## and imembers.member_type = "USER"))
370 ## repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
373 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
374 ## list.acl_type = "USER"))
377 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
378 ## servers.acl_type = "USER"))
381 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
382 ## hostaccess.acl_type = "USER"))
390 /* setup_spop: verify that there is already a valid POP machine_id in the
391 * pop_id field. Also take care of keeping track of the post office usage.
393 int setup_spop(q, argv)
397 ## int id, mid, flag;
400 id = *(int *)argv[0];
401 ## repeat retrieve (type = u.potype, mid = u.pop_id,
402 ## flag = any(machine.name where machine.mach_id = u.pop_id
403 ## and u.pop_id != 0 and u.users_id = @id))
404 ## where u.users_id = @id
407 if (strcmp(strtrim(type), "POP"))
408 set_pop_usage(mid, 1);
413 /* setup_dpob: Take care of keeping track of the post office usage.
415 int setup_dpob(q, argv)
422 user = *(int *)argv[0];
423 ## repeat retrieve (type = u.potype, id = u.pop_id)
424 ## where u.users_id = @user
426 if (!strcmp(strtrim(type), "POP"))
427 set_pop_usage(id, -1);
432 /* setup_dmac - verify that the machine is no longer being referenced
433 * and may safely be deleted.
436 int setup_dmac(q, argv)
442 id = *(int *)argv[0];
443 ## repeat retrieve (flag = any(users.login where users.potype = "POP"
444 ## and users.pop_id=@id))
447 ## repeat retrieve (flag = any(serverhosts.mach_id
448 ## where serverhosts.mach_id=@id))
451 ## repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
454 ## repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
457 ## repeat retrieve (flag = any(printcap.mach_id where printcap.mach_id=@id))
461 ## repeat delete mcmap where mcmap.mach_id = @id
466 /* setup_dclu - verify that the cluster is no longer being referenced
467 * and may safely be deleted.
470 int setup_dclu(q, argv)
476 id = *(int *)argv[0];
477 ## repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
480 ## repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
488 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
489 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
490 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
491 * a -1 there. Remember that this is also used for ulis, with the indexes
495 int setup_alis(q, argv)
503 if (!strcmp(q->shortname, "alis"))
505 else if (!strcmp(q->shortname, "ulis"))
508 if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
509 if (atoi(argv[idx - 1])) {
510 if (set_next_object_id("gid", "list"))
511 return(SMS_INGRES_ERR);
512 ## repeat retrieve (ngid = values.value) where values.name = "gid"
513 sprintf(argv[idx], "%d", ngid);
515 strcpy(argv[idx], "-1");
523 /* setup_dlist - verify that the list is no longer being referenced
524 * and may safely be deleted.
527 int setup_dlis(q, argv)
533 id = *(int *)argv[0];
534 ## repeat retrieve (flag = any(imembers.member_id where imembers.member_id=@id
535 ## and imembers.member_type = "LIST"))
538 ## repeat retrieve (flag = any(imembers.member_id where imembers.list_id=@id))
541 ## repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
544 ## repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
547 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
548 ## list.acl_type = "LIST" and list.list_id != @id))
551 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
552 ## servers.acl_type = "LIST"))
555 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
556 ## hostaccess.acl_type = "LIST"))
559 ## repeat retrieve (flag = any(zephyr.class
560 ## where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
561 ## zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
562 ## zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
563 ## zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
571 /* setup_dsin - verify that the service is no longer being referenced
572 * and may safely be deleted.
575 int setup_dsin(q, argv)
583 ## repeat retrieve (flag = any(serverhosts.service
584 ## where serverhosts.service=uppercase(@name)))
587 ## repeat retrieve (flag = servers.inprogress) where servers.#name = @name
595 /* setup_dshi - verify that the service-host is no longer being referenced
596 * and may safely be deleted.
599 int setup_dshi(q, argv)
607 id = *(int *)argv[1];
608 ## repeat retrieve (flag=serverhosts.inprogress)
609 ## where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
618 ** setup_add_filesys - verify existance of referenced file systems
630 ** * extract directory prefix from name
631 ** * verify mach_id/dir in nfsphys
632 ** * verify access in {r, w, R, W}
634 ** Side effect: sets variable var_phys_id to the ID of the physical
635 ** filesystem (nfsphys_id for NFS, 0 for RVD)
638 ** SMS_NFS - specified directory not exported
639 ** SMS_FILESYS_ACCESS - invalid filesys access
643 ##static int var_phys_id;
655 mach_id = *(int *)argv[2];
660 if (!strcmp(type, "NFS"))
661 return (check_nfs(mach_id, name, access));
667 /* Verify the arguments, depending on the FStype. Also, if this is an
668 * NFS filesystem, then update any quotas for that filesystem to reflect
677 char *type, *name, *access;
681 mach_id = *(int *)argv[3];
686 if (!strcmp(type, "NFS")) {
687 status = check_nfs(mach_id, name, access);
688 fid = *(int *)argv[0];
689 ## replace nfsquota (phys_id = var_phys_id) where nfsquota.filsys_id = fid
696 /* Find the NFS physical partition that the named directory is on.
697 * This is done by comparing the dir against the mount point of the
698 * partition. To make sure we get the correct match when there is
699 * more than one, we sort the query in reverse order by dir name.
702 ##check_nfs(mach_id, name, access)
713 caccess = (isupper(*access)) ? tolower(*access) : *access;
714 if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
717 ## range of np is nfsphys
718 ## repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
719 ## where np.#mach_id = @mach_id sort by #dir:d {
723 if (*cp1++ != *cp2) break;
727 status = SMS_SUCCESS;
736 /* setup_dfil: free any quota records and fsgroup info associated with
737 * a filesystem when it is deleted. Also adjust the allocation numbers.
740 setup_dfil(q, argv, cl)
747 id = *(int *)argv[0];
748 ## range of q is nfsquota
749 ## range of fs is filesys
750 ## range of n is nfsphys
751 ## repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
752 ## where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
754 ## repeat delete q where q.filsys_id = @id
755 ## repeat delete fsgroup where fsgroup.filsys_id = @id
756 ## repeat delete fsgroup where fsgroup.group_id = @id
761 /* setup_dnfp: check to see that the nfs physical partition does not have
762 * any filesystems assigned to it before allowing it to be deleted.
765 setup_dnfp(q, argv, cl)
772 id = *(int *)argv[0];
773 ## repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
780 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
781 * argv[0] = filsys_id
785 setup_dnfq(q, argv, cl)
790 ## int quota, fs, user;
792 fs = *(int *)argv[0];
793 user = *(int *)argv[1];
795 ## range of q is nfsquota
796 ## repeat retrieve (quota = q.#quota) where q.users_id = @user and
798 ## repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
799 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
804 /* setup_sshi: don't exclusive lock the machine table during
805 * set_server_host_internal.
808 setup_sshi(q, argv, cl)
813 ## set lockmode session where readlock = system
818 /* FOLLOWUP ROUTINES */
820 /* generic set_modtime routine. This takes the table name from the query,
821 * and will update the modtime, modby, and modwho fields in the entry in
822 * the table whose name field matches argv[0].
825 set_modtime(q, argv, cl)
830 ## char *name, *entity, *table;
838 ## replace table (modtime = "now", modby = who, modwith = entity)
839 ## where table.#name = name
843 /* generic set_modtime_by_id routine. This takes the table name from
844 * the query, and the id name from the validate record,
845 * and will update the modtime, modby, and modwho fields in the entry in
846 * the table whose id matches argv[0].
849 set_modtime_by_id(q, argv, cl)
854 ## char *entity, *table, *id_name;
860 id_name = q->validate->object_id;
862 id = *(int *)argv[0];
863 ## replace table (modtime = "now", modby = who, modwith = entity)
864 ## where table.id_name = id
869 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
872 set_finger_modtime(q, argv, cl)
877 ## int users_id, who;
882 users_id = *(int *)argv[0];
884 ## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
885 ## where u.#users_id = @users_id
890 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
893 set_pobox_modtime(q, argv, cl)
898 ## int users_id, who;
903 users_id = *(int *)argv[0];
905 ## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
906 ## where users.#users_id = @users_id
911 /* Like set_modtime, but uppercases the name first.
914 set_uppercase_modtime(q, argv, cl)
919 ## char *name, *entity, *table;
927 ## replace table (modtime = "now", modby = who, modwith = entity)
928 ## where table.#name = uppercase(name)
933 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
934 * is necessary for add_machine_to_cluster becuase the table that query
935 * operates on is "mcm", not "machine".
938 set_mach_modtime_by_id(q, argv, cl)
949 id = *(int *)argv[0];
950 ## range of m is machine
951 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
952 ## where m.mach_id = @id
957 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
958 * is necessary for add_cluster_data and delete_cluster_data becuase the
959 * table that query operates on is "svc", not "cluster".
962 set_cluster_modtime_by_id(q, argv, cl)
973 id = *(int *)argv[0];
974 ## range of c is cluster
975 ## repeat replace c (modtime = "now", modby = @who, modwith = @entity)
976 ## where c.clu_id = @id
981 /* sets the modtime on the serverhost where the service name is in argv[0]
982 * and the mach_id is in argv[1].
985 set_serverhost_modtime(q, argv, cl)
990 ## char *entity, *serv;
997 id = *(int *)argv[1];
998 ## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
999 ## where sh.service = uppercase(@serv) and sh.mach_id = @id
1000 return(SMS_SUCCESS);
1004 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1005 * directory name is in argv[1].
1008 set_nfsphys_modtime(q, argv, cl)
1013 ## char *entity, *dir;
1016 entity = cl->entity;
1019 id = *(int *)argv[0];
1021 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1022 ## where np.#dir = @dir and np.mach_id = @id
1023 return(SMS_SUCCESS);
1027 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1031 set_filesys_modtime(q, argv, cl)
1036 ## char *label, *entity;
1039 entity = cl->entity;
1043 if (!strcmp(q->shortname, "ufil"))
1046 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1047 ## #phys_id = @var_phys_id) where fs.#label = @label
1048 return(SMS_SUCCESS);
1052 /* sets the modtime on a zephyr class, where argv[0] contains the class
1056 set_zephyr_modtime(q, argv, cl)
1061 ## char *class, *entity;
1064 entity = cl->entity;
1069 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1070 ## where z.#class = @class
1071 return(SMS_SUCCESS);
1075 /* fixes the modby field. This will be the second to last thing in the
1076 * argv, the argv length is determined from the query structure. It is
1077 * passed as a pointer to an integer. This will either turn it into a
1078 * username, or # + the users_id.
1080 followup_fix_modby(q, sq, v, action, actarg, cl)
1082 register struct save_queue *sq;
1084 register int (*action)();
1085 register int actarg;
1089 char **argv, *malloc();
1090 ## int id, rowcount;
1094 while (sq_get_data(sq, &argv)) {
1097 argv[i] = malloc(9);
1099 ## repeat retrieve (name = users.login) where users.users_id = @id
1100 ## inquire_equel(rowcount = "rowcount")
1101 if (rowcount != 1) {
1102 sprintf(argv[i], "#%d", id);
1104 (*action)(q->vcnt, argv, actarg);
1105 for (j = 0; j < q->vcnt; j++)
1110 return(SMS_SUCCESS);
1115 ** followup_ausr - add finger and pobox entries, set_user_modtime
1118 ** argv[0] - login (add_user)
1119 ** argv[3] - last name
1120 ** argv[4] - first name
1121 ** argv[5] - middle name
1125 followup_ausr(q, argv, cl)
1131 ## char *login, *entity;
1132 ## char fullname[129];
1136 entity = cl->entity;
1138 /* build fullname */
1139 if (strlen(argv[4]) && strlen(argv[5]))
1140 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1141 else if (strlen(argv[4]))
1142 sprintf(fullname, "%s %s", argv[4], argv[3]);
1144 sprintf(fullname, "%s", argv[3]);
1146 /* create finger entry, pobox & set modtime on user */
1147 ## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1148 ## #fullname=@fullname, mit_affil = u.mit_year,
1149 ## fmodtime="now", fmodby=@who, fmodwith=@entity,
1150 ## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1151 ## where u.#login = @login
1153 return(SMS_SUCCESS);
1157 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1158 * type in argv[1]. Then completes the upcall to the user.
1160 * argv[2] is of the form "123:234" where the first integer is the machine
1161 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1162 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1166 followup_gpob(q, sq, v, action, actarg, cl)
1167 register struct query *q;
1168 register struct save_queue *sq;
1169 register struct validate *v;
1170 register int (*action)();
1174 char **argv, *index();
1176 ## char box[129], *name;
1177 ## int mid, sid, rowcount;
1180 while (sq_get_data(sq, &argv)) {
1181 sms_trim_args(2, argv);
1183 p = index(argv[2], ':');
1185 mid = atoi(argv[2]);
1189 if (!strcmp(ptype, "POP")) {
1190 ## repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1191 ## inquire_equel(rowcount = "rowcount")
1193 return(SMS_MACHINE);
1194 } else if (!strcmp(ptype, "SMTP")) {
1195 ## repeat retrieve (box=strings.string) where strings.string_id=@sid
1196 ## inquire_equel(rowcount = "rowcount")
1199 } else /* ptype == "NONE" */ {
1203 if (!strcmp(q->shortname, "gpob")) {
1204 sid = atoi(argv[4]);
1206 argv[4] = malloc(9);
1208 ## repeat retrieve (name = users.login) where users.users_id = @sid
1209 ## inquire_equel(rowcount = "rowcount")
1211 sprintf(name, "#%d", sid);
1215 (*action)(q->vcnt, argv, actarg);
1217 /* free saved data */
1224 return (SMS_SUCCESS);
1228 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1229 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1230 * proper name based on the type, and repace that string in the argv.
1231 * Also fixes the modby field by called followup_fix_modby.
1234 followup_glin(q, sq, v, action, actarg, cl)
1235 register struct query *q;
1236 register struct save_queue *sq;
1237 register struct validate *v;
1238 register int (*action)();
1242 char **argv, *malloc(), *realloc(), *type;
1244 ## int id, rowcount;
1248 if (!strcmp(q->shortname, "gsin"))
1251 while (sq_get_data(sq, &argv)) {
1252 sms_trim_args(q->vcnt, argv);
1254 id = atoi(argv[i = q->vcnt - 2]);
1256 name = argv[i] = malloc(9);
1257 ## repeat retrieve (name = users.login) where users.users_id = @id
1258 ## inquire_equel(rowcount = "rowcount")
1260 sprintf(argv[i], "#%d", id);
1262 id = atoi(argv[idx]);
1263 type = argv[idx - 1];
1264 if ((name = malloc(33)) == NULL)
1267 if (!strcmp(type, "LIST")) {
1268 ## repeat retrieve (name = list.#name) where list.list_id = @id
1269 ## inquire_equel(rowcount = "rowcount")
1271 strcpy(name, "???");
1272 } else if (!strcmp(type, "USER")) {
1273 ## repeat retrieve (name = users.login) where users.users_id = @id
1274 ## inquire_equel(rowcount = "rowcount")
1276 strcpy(name, "???");
1277 } else if (!strcmp(type, "KERBEROS")) {
1278 ## repeat retrieve (name = strings.string) where strings.string_id = @id
1279 ## inquire_equel(rowcount = "rowcount")
1281 strcpy(name, "???");
1282 } else if (!strcmp(type, "NONE")) {
1283 strcpy(name, "NONE");
1285 strcpy(name, "???");
1289 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1290 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1291 strcpy(argv[6], UNIQUE_GID);
1295 (*action)(q->vcnt, argv, actarg);
1297 /* free saved data */
1298 for (i = 0; i < q->vcnt; i++)
1304 return (SMS_SUCCESS);
1308 /** followup_amtl - followup for amtl and dmfl; when adding a list
1309 ** member to a maillist, make member list a maillist also
1310 ** unless list is a user-group.
1311 ** Then set_list_modtime_by_id.
1314 ** argv[0] - list_id
1315 ** argv[1] - member_type
1316 ** argv[2] - member_id
1320 followup_amtl(q, argv, cl)
1330 list_id = *(int *)argv[0];
1331 entity = cl->entity;
1334 ## range of l is list
1335 ## repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1336 ## where l.#list_id = @list_id
1338 /* if query is not amtl or if member_type is not LIST then return */
1339 if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4))
1340 return(SMS_SUCCESS);
1342 member_id = *(int *)argv[2];
1344 /* is parent list a mailing list? */
1345 ## repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1347 return(SMS_SUCCESS);
1349 /* list is not a user-group; add list to maillist table */
1350 ## repeat replace l (maillist = 1) where l.#list_id = @member_id
1351 return(SMS_SUCCESS);
1355 /* followup_anfq: Add allocation to nfsphys after creating quota.
1356 * argv[0] = filsys_id
1357 * argv[2] = ascii(quota)
1360 followup_anfq(q, argv, cl)
1365 ## int quota, user, fs, who;
1368 fs = *(int *)argv[0];
1369 user = *(int *)argv[1];
1370 quota = atoi(argv[2]);
1372 entity = cl->entity;
1374 ## repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1375 ## where nq.filsys_id = @fs and nq.users_id = @user
1376 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1377 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1378 return(SMS_SUCCESS);
1385 followup_gzcl(q, sq, v, action, actarg, cl)
1386 register struct query *q;
1387 register struct save_queue *sq;
1388 register struct validate *v;
1389 register int (*action)();
1394 ## int rowcount, id;
1398 while (sq_get_data(sq, &argv)) {
1399 sms_trim_args(q->vcnt, argv);
1401 id = atoi(argv[i = q->vcnt - 2]);
1403 name = argv[i] = malloc(9);
1404 ## repeat retrieve (name = users.login) where users.users_id = @id
1405 ## inquire_equel(rowcount = "rowcount")
1407 sprintf(argv[i], "#%d", id);
1409 for (i = 1; i < 8; i+=2) {
1410 id = atoi(argv[i+1]);
1412 if ((name = argv[i+1] = malloc(33)) == NULL)
1414 if (!strcmp(argv[i], "LIST")) {
1415 ## repeat retrieve (name = list.#name) where list.list_id = @id
1416 ## inquire_equel(rowcount = "rowcount")
1418 strcpy(name, "???");
1419 } else if (!strcmp(argv[i], "USER")) {
1420 ## repeat retrieve (name = users.login) where users.users_id = @id
1421 ## inquire_equel(rowcount = "rowcount")
1423 strcpy(name, "???");
1424 } else if (!strcmp(argv[i], "KERBEROS")) {
1425 ## repeat retrieve (name = strings.string) where strings.string_id = @id
1426 ## inquire_equel(rowcount = "rowcount")
1428 strcpy(name, "???");
1429 } else if (!strcmp(argv[i], "NONE")) {
1430 strcpy(name, "NONE");
1432 strcpy(name, "???");
1437 (*action)(q->vcnt, argv, actarg);
1439 /* free saved data */
1440 for (i = 0; i < q->vcnt; i++)
1445 return(SMS_SUCCESS);
1452 followup_gsha(q, sq, v, action, actarg, cl)
1453 register struct query *q;
1454 register struct save_queue *sq;
1455 register struct validate *v;
1456 register int (*action)();
1461 ## int rowcount, id;
1465 while (sq_get_data(sq, &argv)) {
1466 sms_trim_args(q->vcnt, argv);
1470 name = argv[4] = malloc(9);
1471 ## repeat retrieve (name = users.login) where users.users_id = @id
1472 ## inquire_equel(rowcount = "rowcount")
1474 sprintf(argv[4], "#%d", id);
1478 if ((name = argv[2] = malloc(33)) == NULL)
1480 if (!strcmp(argv[1], "LIST")) {
1481 ## repeat retrieve (name = list.#name) where list.list_id = @id
1482 ## inquire_equel(rowcount = "rowcount")
1484 strcpy(name, "???");
1485 } else if (!strcmp(argv[1], "USER")) {
1486 ## repeat retrieve (name = users.login) where users.users_id = @id
1487 ## inquire_equel(rowcount = "rowcount")
1489 strcpy(name, "???");
1490 } else if (!strcmp(argv[1], "KERBEROS")) {
1491 ## repeat retrieve (name = strings.string) where strings.string_id = @id
1492 ## inquire_equel(rowcount = "rowcount")
1494 strcpy(name, "???");
1495 } else if (!strcmp(argv[1], "NONE")) {
1496 strcpy(name, "NONE");
1498 strcpy(name, "???");
1502 (*action)(q->vcnt, argv, actarg);
1504 /* free saved data */
1505 for (i = 0; i < q->vcnt; i++)
1510 return(SMS_SUCCESS);
1515 /* Special query routines */
1517 /* set_pobox - this does all of the real work.
1518 * argv = user_id, type, box
1519 * if type is POP, then box should be a machine, and its ID should be put in
1520 * pop_id. If type is SMTP, then box should be a string and its ID should
1521 * be put in box_id. If type is NONE, then box doesn't matter.
1524 int set_pobox(q, argv, cl)
1529 ## int user, id, rowcount;
1530 ## char *box, potype[9];
1533 user = *(int *)argv[0];
1535 ## repeat retrieve (id = users.pop_id, potype = users.#potype)
1536 ## where users.users_id = @user
1537 if (!strcmp(strtrim(potype), "POP"))
1538 set_pop_usage(id, -1);
1540 if (!strcmp(argv[1], "POP")) {
1541 ## repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1542 ## inquire_equel(rowcount = "rowcount")
1544 return(SMS_MACHINE);
1545 ## repeat replace users (#potype = "POP", pop_id = @id)
1546 ## where users.users_id = @user
1547 set_pop_usage(id, 1);
1548 } else if (!strcmp(argv[1], "SMTP")) {
1549 ## range of s is strings
1550 ## repeat retrieve (id = s.string_id) where s.string = @box
1551 ## inquire_equel (rowcount = "rowcount")
1552 if (rowcount == 0) {
1553 ## range of v is values
1554 ## repeat retrieve (id = v.value) where v.name = "strings_id"
1556 ## repeat replace v (value = @id) where v.name = "strings_id"
1557 ## append to strings (string_id = id, string = box)
1559 ## repeat replace users (#potype = "SMTP", box_id = @id)
1560 ## where users.users_id = @user
1561 } else /* argv[1] == "NONE" */ {
1562 ## repeat replace users (#potype = "NONE") where users.users_id = @user
1565 set_pobox_modtime(q, argv, cl);
1566 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1567 ## where tblstats.#table = "users"
1568 return(SMS_SUCCESS);
1572 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1573 * each list. This is tricky: first build a queue of all requested
1574 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1577 get_list_info(q, aargv, cl, action, actarg)
1578 register struct query *q;
1581 register int (*action)();
1584 char *argv[13], *malloc(), *realloc();
1585 ## char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1586 ## char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1587 ## char modby[9], modwith[9];
1588 ## int id, rowcount, acl_id, hid, modby_id;
1590 struct save_queue *sq, *sq_create();
1592 returned = rowcount = 0;
1596 ## range of l is list
1597 ## repeat retrieve (id = l.list_id) where l.#name = @name {
1598 sq_save_data(sq, id);
1602 return(SMS_NO_MATCH);
1604 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1605 argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1606 argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1609 while (sq_get_data(sq, &id)) {
1613 ## repeat retrieve (listname = l.#name, active = text(l.#active),
1614 ## public = text(l.#public), hidden = text(l.#hidden),
1615 ## hid = l.#hidden, maillist = text(l.#maillist),
1616 ## group = text(l.#group), gid = text(l.#gid),
1617 ## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1618 ## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1619 ## modwith =l.#modwith)
1620 ## where l.list_id = @id
1622 if (atoi(gid) == -1)
1623 argv[6] = UNIQUE_GID;
1625 if (!strcmp(acl_type, "LIST")) {
1626 ## repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1627 ## inquire_equel(rowcount = "rowcount")
1629 strcpy(acl_name, "???");
1630 } else if (!strcmp(acl_type, "USER")) {
1631 ## repeat retrieve (acl_name = users.#login)
1632 ## where users.users_id = @acl_id
1633 ## inquire_equel(rowcount = "rowcount")
1635 strcpy(acl_name, "???");
1636 } else if (!strcmp(acl_type, "KERBEROS")) {
1637 ## repeat retrieve (acl_name = strings.string)
1638 ## where strings.string_id = @acl_id
1639 ## inquire_equel(rowcount = "rowcount")
1641 strcpy(acl_name, "???");
1642 } else if (!strcmp(acl_type, "NONE")) {
1643 strcpy(acl_name, "NONE");
1645 strcpy(acl_name, "???");
1647 ## repeat retrieve (modby = users.login) where users.users_id = @modby_id
1648 ## inquire_equel(rowcount = "rowcount")
1650 sprintf(modby, "#%d", id);
1652 sms_trim_args(q->vcnt, argv);
1654 (*action)(q->vcnt, argv, actarg);
1658 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1659 ## where tblstats.#table = "list"
1661 return (SMS_SUCCESS);
1665 /* Add_member_to_list: do list flattening as we go! MAXLISTDEPTH is
1666 * how many different ancestors a member is allowed to have.
1669 #define MAXLISTDEPTH 100
1671 int add_member_to_list(q, argv, cl)
1676 ## int id, lid, mid, exists, error;
1677 ## char *mtype, dtype[9];
1678 int ancestors[MAXLISTDEPTH], acount, a;
1679 int descendants[MAXLISTDEPTH], dcount, d;
1680 char *dtypes[MAXLISTDEPTH];
1682 ## range of m is imembers
1683 lid = *(int *)argv[0];
1685 mid = *(int *)argv[2];
1686 ## repeat retrieve (exists = any(m.list_id where m.list_id=@lid and
1687 ## m.member_id = @mid and m.member_type = @mtype
1688 ## and m.direct = 1))
1693 ## repeat retrieve (id = m.list_id)
1694 ## where m.member_id = @lid and m.member_type = "LIST" {
1695 ancestors[acount++] = id;
1696 if (acount >= MAXLISTDEPTH) {
1700 if (acount >= MAXLISTDEPTH) {
1701 return(SMS_INTERNAL);
1703 descendants[0] = mid;
1707 if (!strcmp(mtype, "LIST")) {
1708 ## repeat retrieve (id = m.member_id, dtype = m.member_type)
1709 ## where m.list_id = @mid {
1712 dtypes[dcount] = "LIST";
1715 dtypes[dcount] = "USER";
1718 dtypes[dcount] = "STRING";
1721 dtypes[dcount] = "KERBEROS";
1727 descendants[dcount++] = id;
1728 if (dcount >= MAXLISTDEPTH) {
1734 return(SMS_INTERNAL);
1736 for (a = 0; a < acount; a++) {
1738 for (d = 0; d < dcount; d++) {
1739 mid = descendants[d];
1741 if (mid == lid && !strcmp(mtype, "LIST")) {
1742 return(SMS_LISTLOOP);
1744 ## repeat retrieve (exists = any(m.ref_count where m.list_id = @lid
1745 ## and m.member_id = @mid
1746 ## and m.member_type = @mtype))
1748 if (a == 0 && d == 0)
1749 ## replace m (ref_count = m.ref_count+1, direct = 1)
1750 ## where m.list_id = lid and m.member_id = mid and
1751 ## m.member_type = mtype
1753 ## replace m (ref_count = m.ref_count+1)
1754 ## where m.list_id = lid and m.member_id = mid and
1755 ## m.member_type = mtype
1757 if (a == 0 && d == 0)
1758 ## append imembers (list_id=lid, member_id = mid, direct = 1,
1759 ## member_type=mtype, ref_count = 1)
1761 ## append imembers (list_id=lid, member_id = mid,
1762 ## member_type=mtype, ref_count = 1)
1766 return(SMS_SUCCESS);
1770 /* Delete_member_from_list: do list flattening as we go!
1773 int delete_member_from_list(q, argv, cl)
1778 ## int id, lid, mid, cnt, exists, error;
1779 ## char *mtype, dtype[9];
1780 int ancestors[MAXLISTDEPTH], acount, a;
1781 int descendants[MAXLISTDEPTH], dcount, d;
1782 char *dtypes[MAXLISTDEPTH];
1784 ## range of m is imembers
1785 lid = *(int *)argv[0];
1787 mid = *(int *)argv[2];
1788 ## repeat retrieve (exists = any(m.list_id where m.list_id=@lid and
1789 ## m.member_id = @mid and m.member_type = @mtype
1790 ## and m.direct = 1))
1792 return(SMS_NO_MATCH);
1795 ## repeat retrieve (id = m.list_id)
1796 ## where m.member_id = @lid and m.member_type = "LIST" {
1797 ancestors[acount++] = id;
1798 if (acount >= MAXLISTDEPTH)
1801 if (acount >= MAXLISTDEPTH)
1802 return(SMS_INTERNAL);
1803 descendants[0] = mid;
1807 if (!strcmp(mtype, "LIST")) {
1808 ## repeat retrieve (id = m.member_id, dtype = m.member_type)
1809 ## where m.list_id = @mid {
1812 dtypes[dcount] = "LIST";
1815 dtypes[dcount] = "USER";
1818 dtypes[dcount] = "STRING";
1821 dtypes[dcount] = "KERBEROS";
1827 descendants[dcount++] = id;
1828 if (dcount >= MAXLISTDEPTH)
1832 return(SMS_INTERNAL);
1834 for (a = 0; a < acount; a++) {
1836 for (d = 0; d < dcount; d++) {
1837 mid = descendants[d];
1839 if (mid == lid && !strcmp(mtype, "LIST")) {
1840 return(SMS_LISTLOOP);
1842 ## repeat retrieve (cnt = m.ref_count)
1843 ## where m.list_id = @lid and m.member_id = @mid
1844 ## and m.member_type = @mtype
1846 ## delete m where m.list_id = lid and m.member_id = mid and
1847 ## m.member_type = mtype
1848 } else if (a == 0 && d == 0) {
1849 ## replace m (ref_count = m.ref_count-1, direct = 0)
1850 ## where m.list_id = lid and m.member_id = mid and
1851 ## m.member_type = mtype
1853 ## replace m (ref_count = m.ref_count-1)
1854 ## where m.list_id = lid and m.member_idn = mid and
1855 ## m.member_type = mtype
1859 return(SMS_SUCCESS);
1863 /* get_ace_use - given a type and a name, return a type and a name.
1864 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1865 * and argv[1] will contain the ID of the entity in question. The R*
1866 * types mean to recursively look at every containing list, not just
1867 * when the object in question is a direct member. On return, the
1868 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1871 int get_ace_use(q, argv, cl, action, actarg)
1880 ## int aid, listid, id;
1881 struct save_queue *sq, *sq_create();
1883 ## range of m is imembers
1885 aid = *(int *)argv[1];
1886 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
1887 !strcmp(atype, "KERBEROS")) {
1888 return(get_ace_internal(atype, aid, action, actarg));
1892 if (!strcmp(atype, "RLIST")) {
1893 sq_save_data(sq, aid);
1894 /* get all the list_id's of containing lists */
1895 ## range of m is imembers
1896 ## repeat retrieve (listid = m.list_id)
1897 ## where m.member_type = "LIST" and m.member_id = @id {
1898 sq_save_unique_data(sq, listid);
1900 /* now process each one */
1901 while (sq_get_data(sq, &id)) {
1902 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1907 if (!strcmp(atype, "RUSER")) {
1908 ## repeat retrieve (listid = m.list_id)
1909 ## where m.member_type = "USER" and m.member_id = @aid {
1910 sq_save_data(sq, listid);
1912 /* now process each one */
1913 while (sq_get_data(sq, &id)) {
1914 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1917 if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1921 if (!strcmp(atype, "RKERBERO")) {
1922 ## repeat retrieve (listid = m.list_id)
1923 ## where m.member_type = "KERBEROS" and m.member_id = @aid {
1924 sq_save_data(sq, listid);
1926 /* now process each one */
1927 while (sq_get_data(sq, &id)) {
1928 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1931 if (get_ace_internal("KERBEROS", aid, action, actarg) == SMS_SUCCESS)
1936 if (!found) return(SMS_NO_MATCH);
1937 return(SMS_SUCCESS);
1941 /* This looks up a single list or user for ace use. atype must be "USER"
1942 * or "LIST", and aid is the ID of the corresponding object. This is used
1943 * by get_ace_use above.
1946 ##get_ace_internal(atype, aid, action, actarg)
1957 if (!strcmp(atype, "LIST")) {
1958 rargv[0] = "FILESYS";
1959 ## repeat retrieve (name = filesys.label)
1960 ## where filesys.owners = @aid {
1961 (*action)(2, rargv, actarg);
1966 ## repeat retrieve (name = capacls.capability)
1967 ## where capacls.list_id = @aid {
1968 (*action)(2, rargv, actarg);
1971 } else if (!strcmp(atype, "USER")) {
1972 rargv[0] = "FILESYS";
1973 ## repeat retrieve (name = filesys.label)
1974 ## where filesys.owner = @aid {
1975 (*action)(2, rargv, actarg);
1981 ## repeat retrieve (name = list.#name)
1982 ## where list.acl_type = @atype and list.acl_id = @aid {
1983 (*action)(2, rargv, actarg);
1987 rargv[0] = "SERVICE";
1988 ## repeat retrieve (name = servers.#name)
1989 ## where servers.acl_type = @atype and servers.acl_id = @aid {
1990 (*action)(2, rargv, actarg);
1994 rargv[0] = "HOSTACCESS";
1995 ## repeat retrieve (name = machine.#name)
1996 ## where machine.mach_id = hostaccess.mach_id and
1997 ## hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1998 (*action)(2, rargv, actarg);
2001 rargv[0] = "ZEPHYR";
2002 ## repeat retrieve (name = zephyr.class)
2003 ## where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
2004 ## zephyr.sub_type = @atype and zephyr.sub_id = @aid or
2005 ## zephyr.iws_type = @atype and zephyr.iws_id = @aid or
2006 ## zephyr.iui_type = @atype and zephyr.iui_id = @aid {
2007 (*action)(2, rargv, actarg);
2011 if (!found) return(SMS_NO_MATCH);
2012 return(SMS_SUCCESS);
2016 /* get_lists_of_member - given a type and a name, return the name and flags
2017 * of all of the lists of the given member. The member_type is one of
2018 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2019 * and argv[1] will contain the ID of the entity in question. The R*
2020 * types mean to recursively look at every containing list, not just
2021 * when the object in question is a direct member.
2024 int get_lists_of_member(q, argv, cl, action, actarg)
2031 int found = 0, direct = 1;
2034 ## int aid, listid, id;
2035 ## char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
2038 aid = *(int *)argv[1];
2039 if (!strcmp(atype, "RLIST")) {
2043 if (!strcmp(atype, "RUSER")) {
2047 if (!strcmp(atype, "RSTRING")) {
2051 if (!strcmp(atype, "RKERBEROS")) {
2060 rargv[4] = maillist;
2063 ## repeat retrieve (name = list.#name, active = text(list.#active),
2064 ## public = text(list.#public), hidden = text(list.#hidden),
2065 ## maillist = text(list.#maillist), group = text(list.#group))
2066 ## where list.list_id = m.list_id and m.direct = 1 and
2067 ## m.member_type = @atype and m.member_id = @aid {
2068 (*action)(6, rargv, actarg);
2072 ## repeat retrieve (name = list.#name, active = text(list.#active),
2073 ## public = text(list.#public), hidden = text(list.#hidden),
2074 ## maillist = text(list.#maillist), group = text(list.#group))
2075 ## where list.list_id = m.list_id and
2076 ## m.member_type = @atype and m.member_id = @aid {
2077 (*action)(6, rargv, actarg);
2082 if (!found) return(SMS_NO_MATCH);
2083 return(SMS_SUCCESS);
2087 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2088 * the five flags associated with each list. It will return the name of
2089 * each list that meets the quailifications. It does this by building a
2090 * where clause based on the arguments, then doing a retrieve.
2093 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
2095 int qualified_get_lists(q, argv, cl, action, actarg)
2102 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2103 "l", "name", lflags));
2107 /** get_members_of_list - optimized query for retrieval of list members
2110 ** argv[0] - list_id
2113 ** - retrieve USER members, then LIST members, then STRING members
2116 get_members_of_list(q, argv, cl, action, actarg)
2124 ## char member_name[129];
2127 list_id = *(int *)argv[0];
2129 targv[1] = member_name;
2131 ## range of m is imembers
2132 ## repeat retrieve (member_name = users.login)
2133 ## where m.#list_id = @list_id and m.member_type = "USER"
2134 ## and m.member_id = users.users_id and m.direct = 1
2135 ## sort by #member_name
2137 (*action)(2, targv, actarg);
2141 ## repeat retrieve (member_name = list.name)
2142 ## where m.#list_id = @list_id and m.member_type = "LIST"
2143 ## and m.member_id = list.#list_id and m.direct = 1
2144 ## sort by #member_name
2146 (*action)(2, targv, actarg);
2149 targv[0] = "STRING";
2150 ## repeat retrieve (member_name = strings.string)
2151 ## where m.#list_id = @list_id and m.member_type = "STRING"
2152 ## and m.member_id = strings.string_id and m.direct = 1
2153 ## sort by #member_name
2155 (*action)(2, targv, actarg);
2158 targv[0] = "KERBEROS";
2159 ## repeat retrieve (member_name = strings.string)
2160 ## where m.#list_id = @list_id and m.member_type = "KERBEROS"
2161 ## and m.member_id = strings.string_id and m.direct = 1
2162 ## sort by #member_name
2164 (*action)(2, targv, actarg);
2167 return(SMS_SUCCESS);
2171 /* count_members_of_list: this is a simple query, but it cannot be done
2172 * through the dispatch table.
2175 int count_members_of_list(q, argv, cl, action, actarg)
2182 ## int list, ct = 0;
2183 char *rargv[1], countbuf[5];
2185 list = *(int *)argv[0];
2186 rargv[0] = countbuf;
2187 ## repeat retrieve (ct = count(imembers.list_id
2188 ## where imembers.list_id = @list and
2189 ## imembers.direct = 1))
2190 sprintf(countbuf, "%d", ct);
2191 (*action)(1, rargv, actarg);
2192 return(SMS_SUCCESS);
2196 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2197 * the three flags associated with each service. It will return the name of
2198 * each service that meets the quailifications. It does this by building a
2199 * where clause based on the arguments, then doing a retrieve.
2202 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2204 int qualified_get_server(q, argv, cl, action, actarg)
2211 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2212 "s", "name", sflags));
2216 /* generic qualified get routine, used by qualified_get_lists,
2217 * qualified_get_server, and qualified_get_serverhost.
2219 * start - a simple where clause, must not be empty
2220 * range - the name of the range variable
2221 * field - the field to return
2222 * flags - an array of strings, names of the flag variables
2225 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2235 ## char name[33], qual[256], *rvar, *rtbl, *rfield;
2236 char *rargv[1], buf[32];
2239 strcpy(qual, start);
2240 for (i = 0; i < q->argc; i++) {
2241 if (!strcmp(argv[i], "TRUE")) {
2242 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2243 (void) strcat(qual, buf);
2244 } else if (!strcmp(argv[i], "FALSE")) {
2245 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2246 (void) strcat(qual, buf);
2254 ## range of rvar is rtbl
2255 ## retrieve (name = rvar.rfield) where qual {
2256 (*action)(1, rargv, actarg);
2258 ## inquire_equel(rowcount = "rowcount")
2259 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2260 ## where tblstats.#table = @rtbl
2262 return(SMS_NO_MATCH);
2263 return(SMS_SUCCESS);
2267 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2268 * the five flags associated with each serverhost. It will return the name of
2269 * each service and host that meets the quailifications. It does this by
2270 * building a where clause based on the arguments, then doing a retrieve.
2273 static char *shflags[6] = { "service", "enable", "override", "success",
2274 "inprogress", "hosterror" };
2276 int qualified_get_serverhost(q, argv, cl, action, actarg)
2283 ## char sname[33], mname[33], qual[256];
2284 char *rargv[2], buf[32];
2287 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2289 for (i = 1; i < q->argc; i++) {
2290 if (!strcmp(argv[i], "TRUE")) {
2291 sprintf(buf, " and sh.%s != 0", shflags[i]);
2293 } else if (!strcmp(argv[i], "FALSE")) {
2294 sprintf(buf, " and sh.%s = 0", shflags[i]);
2301 ## range of sh is serverhosts
2302 ## retrieve (sname = sh.service, mname = machine.name) where qual {
2303 (*action)(2, rargv, actarg);
2305 ## inquire_equel(rowcount = "rowcount")
2306 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2307 ## where tblstats.#table = "serverhosts"
2309 return(SMS_NO_MATCH);
2310 return(SMS_SUCCESS);
2314 /* register_user - change user's login name and allocate a pobox, group,
2315 * filesystem, and quota for them. The user's status must start out as 0,
2316 * and is left as 2. Arguments are: user's UID, new login name, and user's
2317 * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY,
2318 * SMS_FS_STAFF, SMS_FS_MISC).
2321 register_user(q, argv, cl)
2326 ## char *login, dir[65], *entity, *directory, machname[33];
2327 ## int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2328 ## int size, alloc, pid, m_id;
2331 entity = cl->entity;
2334 uid = atoi(argv[0]);
2336 utype = atoi(argv[2]);
2338 ## range of u is users
2339 ## range of l is list
2340 ## range of sh is serverhosts
2341 ## range of n is nfsphys
2342 ## range of m is machine
2345 ## repeat retrieve (users_id = u.#users_id)
2346 ## where u.#uid = @uid and u.status = 0
2347 ## inquire_equel(rowcount = "rowcount");
2349 return(SMS_NO_MATCH);
2351 return(SMS_NOT_UNIQUE);
2353 /* check new login name */
2354 ## repeat retrieve (flag = any(u.#login where u.#login = @login))
2355 if (ingres_errno) return(sms_errcode);
2356 if (flag) return(SMS_IN_USE);
2357 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2358 if (ingres_errno) return(sms_errcode);
2359 if (flag) return(SMS_IN_USE);
2360 ## repeat retrieve (flag = any(filesys.#label where filesys.#label = @login))
2361 if (ingres_errno) return(sms_errcode);
2362 if (flag) return(SMS_IN_USE);
2363 com_err(whoami, 0, "new login name OK");
2365 /* choose place for pobox, put in mid */
2366 ## repeat retrieve (mid = sh.mach_id, machname = m.name)
2367 ## where sh.service = "POP" and m.mach_id = sh.mach_id and
2368 ## sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2369 ## inquire_equel(rowcount = "rowcount");
2371 return(SMS_NO_POBOX);
2373 /* change login name, set pobox */
2374 ## repeat replace u (#login = @login, status = 2, modtime = "now",
2375 ## modby = @who, modwith = @entity, potype="POP",
2376 ## pop_id = @mid, pmodtime="now", pmodby=@who,
2377 ## pmodwith=@entity)
2378 ## where u.#users_id = @users_id
2379 ## inquire_equel(rowcount = "rowcount");
2381 return(SMS_INTERNAL);
2382 set_pop_usage(mid, 1);
2383 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2386 /* create group list */
2387 if (set_next_object_id("gid", "list"))
2389 if (set_next_object_id("list_id", "list"))
2391 ## repeat retrieve (list_id = values.value) where values.name = "list_id"
2392 ## inquire_equel(rowcount = "rowcount");
2394 return(SMS_INTERNAL);
2395 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2396 ## public = 0, hidden = 0, maillist = 0, group = 1,
2397 ## #gid = values.value, desc = "User Group",
2398 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2399 ## modby = @who, modwith = @entity)
2400 ## where values.name = "gid"
2401 ## inquire_equel(rowcount = "rowcount");
2403 return(SMS_INTERNAL);
2404 ## repeat append imembers (#list_id = @list_id, member_type = "USER",
2405 ## member_id = @users_id, ref_count = 1, direct = 1)
2406 ## inquire_equel(rowcount = "rowcount");
2408 return(SMS_INTERNAL);
2409 com_err(whoami, 0, "group list created");
2411 /* decide where to put filesystem */
2414 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2415 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2416 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2417 maxsize = size - alloc;
2420 directory = strsave(dir);
2426 return(SMS_NO_FILESYS);
2428 /* create filesystem */
2429 if (set_next_object_id("filsys_id", "filesys"))
2431 ## repeat append filesys (filsys_id = values.value, phys_id = @pid,
2432 ## label = @login, type = "NFS", mach_id = @m_id,
2433 ## name = @directory + "/" + @login,
2434 ## mount = "/mit/" + @login,
2435 ## access = "w", comments = "User Locker",
2436 ## owner = @users_id, owners = @list_id, createflg = 1,
2437 ## lockertype = "HOMEDIR", modtime = "now",
2438 ## modby = @who, modwith = @entity)
2439 ## where values.name = "filsys_id"
2440 ## inquire_equel(rowcount = "rowcount");
2442 return(SMS_INTERNAL);
2443 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2447 ## repeat retrieve (quota = values.value) where values.name = "def_quota"
2448 ## inquire_equel(rowcount = "rowcount");
2450 return(SMS_NO_QUOTA);
2451 ## repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2452 ## #quota = @quota, phys_id = @pid, modtime = "now",
2453 ## modby = @who, modwith = @entity)
2454 ## where values.name = "filsys_id"
2455 ## inquire_equel(rowcount = "rowcount");
2457 return(SMS_INTERNAL);
2458 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2459 ## where nfsphys.nfsphys_id = filesys.#phys_id and
2460 ## filesys.filsys_id = values.value and values.name = "filsys_id"
2461 ## inquire_equel(rowcount = "rowcount");
2463 return(SMS_INTERNAL);
2464 com_err(whoami, 0, "quota of %d assigned", quota);
2466 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2467 ## where tblstats.table = "users"
2468 ## repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2469 ## where tblstats.table = "list" or tblstats.table = "filesys" or
2470 ## tblstats.table = "nfsquota"
2471 return(SMS_SUCCESS);
2476 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2480 ** delta (will be +/- 1)
2483 ** - incr/decr value field in serverhosts table for pop/mach_id
2487 static int set_pop_usage(id, count)
2491 ## int mach_id = id;
2494 ## range of sh is serverhosts
2495 ## repeat replace sh (value1 = sh.value1 + @n)
2496 ## where sh.service = "POP" and sh.#mach_id = @mach_id
2498 return(SMS_SUCCESS);
2503 /* Validation Routines */
2505 validate_row(q, argv, v)
2506 register struct query *q;
2508 register struct validate *v;
2516 /* build where clause */
2517 build_qual(v->qual, v->argc, argv, qual);
2519 /* setup ingres variables */
2524 if (log_flags & LOG_VALID)
2525 /* tell the logfile what we're doing */
2526 com_err(whoami, 0, "validating row: %s", qual);
2528 /* look for the record */
2529 ## range of rvar is table
2530 ## retrieve (rowcount = count(rvar.name where qual))
2531 if (ingres_errno) return(sms_errcode);
2532 if (rowcount == 0) return(SMS_NO_MATCH);
2533 if (rowcount > 1) return(SMS_NOT_UNIQUE);
2537 validate_fields(q, argv, vo, n)
2539 register char *argv[];
2540 register struct valobj *vo;
2543 register int status;
2548 if (log_flags & LOG_VALID)
2549 com_err(whoami, 0, "validating %s in %s: %s",
2550 vo->namefield, vo->table, argv[vo->index]);
2551 status = validate_name(argv, vo);
2555 if (log_flags & LOG_VALID)
2556 com_err(whoami, 0, "validating %s in %s: %s",
2557 vo->idfield, vo->table, argv[vo->index]);
2558 status = validate_id(argv, vo);
2562 if (log_flags & LOG_VALID)
2563 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2564 status = validate_date(argv, vo);
2568 if (log_flags & LOG_VALID)
2569 com_err(whoami, 0, "validating %s type: %s",
2570 vo->table, argv[vo->index]);
2571 status = validate_type(argv, vo);
2575 if (log_flags & LOG_VALID)
2576 com_err(whoami, 0, "validating typed data (%s): %s",
2577 argv[vo->index - 1], argv[vo->index]);
2578 status = validate_typedata(q, argv, vo);
2582 if (log_flags & LOG_VALID)
2583 com_err(whoami, 0, "validating rename %s in %s",
2584 argv[vo->index], vo->table);
2585 status = validate_rename(argv, vo);
2589 if (log_flags & LOG_VALID)
2590 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2591 status = validate_chars(argv[vo->index]);
2595 status = SMS_EXISTS;
2599 status = lock_table(vo);
2603 if (status != SMS_EXISTS) return(status);
2607 return(SMS_SUCCESS);
2611 /* validate_chars: verify that there are no illegal characters in
2612 * the string. Legal characters are printing chars other than
2613 * ", *, ?, \, [ and ].
2615 static int illegalchars[] = {
2616 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2617 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2618 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2619 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2620 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2621 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2622 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2623 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2624 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2625 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2626 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2627 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2628 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2629 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2630 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2631 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2638 if (illegalchars[*s++])
2639 return(SMS_BAD_CHAR);
2644 validate_id(argv, vo)
2646 register struct valobj *vo;
2656 name = argv[vo->index];
2658 /* minor kludge to upcasify machine names */
2659 if (!strcmp(table, "machine"))
2660 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2661 namefield = vo->namefield;
2662 idfield = vo->idfield;
2663 if (!strcmp(namefield, "uid")) {
2664 ## retrieve (id = table.idfield) where table.namefield = int4(name)
2665 if (ingres_errno) return(sms_errcode);
2666 ## inquire_equel (rowcount = "rowcount")
2668 ## retrieve (id = table.idfield) where table.namefield = name
2669 if (ingres_errno) return(sms_errcode);
2670 ## inquire_equel (rowcount = "rowcount")
2672 if (rowcount != 1) return(vo->error);
2673 *(int *)argv[vo->index] = id;
2677 validate_name(argv, vo)
2679 register struct valobj *vo;
2687 name = argv[vo->index];
2689 namefield = vo->namefield;
2690 if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2691 for (c = name; *c; c++)
2695 ## retrieve (rowcount = countu(table.namefield
2696 ## where table.namefield = name))
2697 if (ingres_errno) return(sms_errcode);
2698 return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2701 validate_date(argv, vo)
2709 idate = argv[vo->index];
2711 ## retrieve (dd = interval("years", date(idate) - date("today")))
2712 ## inquire_equel (errorno = "errorno")
2713 if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2718 validate_rename(argv, vo)
2722 ## char *name, *table, *namefield, *idfield;
2726 c = name = argv[vo->index];
2728 if (illegalchars[*c++])
2729 return(SMS_BAD_CHAR);
2731 /* minor kludge to upcasify machine names */
2732 if (!strcmp(table, "machine"))
2733 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2734 namefield = vo->namefield;
2735 idfield = vo->idfield;
2738 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2740 ## retrieve (id = any(table.namefield where table.namefield = name))
2741 if (ingres_errno) return(sms_errcode);
2747 ## retrieve (id = table.idfield) where table.namefield = name
2748 if (ingres_errno) return(sms_errcode);
2749 if (id == -1 || id == *(int *)argv[vo->index - 1])
2756 validate_type(argv, vo)
2758 register struct valobj *vo;
2765 typename = vo->table;
2766 c = value = argv[vo->index];
2768 if (illegalchars[*c++])
2769 return(SMS_BAD_CHAR);
2771 /* uppercase type fields */
2772 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2774 ## range of a is alias
2775 ## repeat retrieve (exists = any(a.trans where a.name = @typename and
2776 ## a.type = "TYPE" and
2777 ## a.trans = @value))
2778 if (ingres_errno) return(sms_errcode);
2779 return (exists ? SMS_EXISTS : vo->error);
2782 /* validate member or type-specific data field */
2784 validate_typedata(q, argv, vo)
2785 register struct query *q;
2786 register char *argv[];
2787 register struct valobj *vo;
2790 ## char *field_type;
2791 ## char data_type[129];
2797 /* get named object */
2798 name = argv[vo->index];
2800 /* get field type string (known to be at index-1) */
2801 field_type = argv[vo->index-1];
2803 /* get corresponding data type associated with field type name */
2804 ## repeat retrieve (data_type = alias.trans)
2805 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
2806 if (ingres_errno) return(sms_errcode);
2807 ## inquire_equel (rowcount = "rowcount")
2808 if (rowcount != 1) return(SMS_TYPE);
2810 /* now retrieve the record id corresponding to the named object */
2811 if (index(data_type, ' '))
2812 *index(data_type, ' ') = 0;
2813 if (!strcmp(data_type, "user")) {
2815 ## repeat retrieve (id = users.users_id) where users.login = @name
2816 ## inquire_equel (rowcount = "rowcount")
2817 if (rowcount != 1) return(SMS_USER);
2819 } else if (!strcmp(data_type, "list")) {
2821 ## repeat retrieve (id = list.list_id) where list.#name = @name
2822 ## inquire_equel (rowcount = "rowcount")
2823 if (rowcount != 1) {
2824 /* if idfield is non-zero, then if argv[0] matches the string
2825 * that we're trying to resolve, we should get the value of
2826 * values.[idfield] for the id.
2828 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2829 set_next_object_id(q->validate->object_id, q->rtable);
2831 ## repeat retrieve (id = values.value) where values.#name = @name
2832 ## inquire_equel(rowcount = "rowcount")
2833 if (rowcount != 1) return(SMS_LIST);
2837 } else if (!strcmp(data_type, "machine")) {
2839 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2840 ## repeat retrieve (id = machine.mach_id) where machine.#name = @name
2841 ## inquire_equel (rowcount = "rowcount")
2842 if (rowcount != 1) return(SMS_MACHINE);
2844 } else if (!strcmp(data_type, "string")) {
2846 ## range of s is strings
2847 ## repeat retrieve (id = s.string_id) where s.string = @name
2848 ## inquire_equel (rowcount = "rowcount")
2849 if (rowcount == 0) {
2850 if (q->type != APPEND) return(SMS_STRING);
2851 ## range of v is values
2852 ## retrieve (id = v.value) where v.#name = "strings_id"
2854 ## replace v (value = id) where v.#name = "strings_id"
2855 ## append to strings (string_id = id, string = name)
2857 } else if (!strcmp(data_type, "none")) {
2863 /* now set value in argv */
2864 *(int *)argv[vo->index] = id;
2866 return (SMS_EXISTS);
2870 /* Lock the table named by the validation object */
2875 ## char *table, *idfield;
2879 idfield = vo->idfield;
2880 ## replace table (modtime = "now") where table.idfield = 0
2881 if (ingres_errno) return(sms_errcode);
2882 ## inquire_equel (rowcount = "rowcount")
2890 /* This looks up a login name and returns the SMS internal ID. It is used
2891 * by authenticate to put the users_id in the client structure.
2894 int get_users_id(name)
2897 ## int id, rowcount;
2902 ## range of u is users
2903 ## repeat retrieve (id = u.#users_id) where u.#login = @login
2904 ## inquire_equel (rowcount = "rowcount")
2913 /* Check the database at startup time. For now this just resets the
2914 * inprogress flags that the DCM uses.
2917 sanity_check_database()