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) || !strcmp("dmfl", q->shortname)) &&
108 (flags && !strcmp("USER", argv[1]))) {
109 if (*(int *)argv[2] == client_id) return(SMS_SUCCESS);
110 /* if update_list, don't allow them to change the GID */
111 } else if (!strcmp("ulis", q->shortname)) {
112 if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
113 (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
117 /* check for client in access control list */
118 status = find_member(acl_type, acl_id, client_type, client_id, 0);
119 if (!status) return(SMS_PERM);
125 /* access_visible_list - allow access to list only if it is not hidden,
126 * or if the client is on the ACL
128 * Inputs: argv[0] - list_id
129 * cl - client identifier
132 access_visible_list(q, argv, cl)
137 ## int list_id, acl_id, flags, rowcount;
140 int client_id, status;
142 list_id = *(int *)argv[0];
143 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
144 ## acl_type = list.#acl_type) where list.#list_id = @list_id
145 ## inquire_equel(rowcount = "rowcount")
147 return(SMS_INTERNAL);
151 /* parse client structure */
152 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
155 /* check for client in access control list */
156 status = find_member(acl_type, acl_id, client_type, client_id, 0);
164 /* access_vis_list_by_name - allow access to list only if it is not hidden,
165 * or if the client is on the ACL
167 * Inputs: argv[0] - list name
168 * cl - client identifier
171 access_vis_list_by_name(q, argv, cl)
176 ## int acl_id, flags, rowcount;
177 ## char acl_type[9], *listname;
179 int client_id, status;
182 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
183 ## acl_type = list.#acl_type) where list.#name = @listname
184 ## inquire_equel(rowcount = "rowcount");
186 return(SMS_WILDCARD);
188 return(SMS_NO_MATCH);
192 /* parse client structure */
193 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
196 /* check for client in access control list */
197 status = find_member(acl_type, acl_id, client_type, client_id, 0);
205 /* access_member - allow user to access member of type "USER" and name matches
206 * username, or to access member of type "LIST" and list is one that user is
207 * on the acl of, or the list is visible.
210 access_member(q, argv, cl)
215 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
216 return(access_visible_list(q, &argv[1], cl));
218 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
219 if (cl->users_id == *(int *)argv[1])
227 /* access_qgli - special access routine for Qualified_get_lists. Allows
228 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
231 access_qgli(q, argv, cl)
236 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
242 /* access_service - allow access if user is on ACL of service. Don't
243 * allow access if a wildcard is used.
246 access_service(q, argv, cl)
251 ## int acl_id, rowcount;
252 ## char *name, acl_type[9];
253 int client_id, status;
257 ## repeat retrieve (acl_id = servers.#acl_id, acl_type = servers.#acl_type)
258 ## where servers.#name = uppercase(@name)
259 ## inquire_equel(rowcount = "rowcount")
263 /* parse client structure */
264 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
267 /* check for client in access control list */
268 status = find_member(acl_type, acl_id, client_type, client_id, 0);
269 if (!status) return(SMS_PERM);
276 /* access_filesys - verify that client is owner or on owners list of filesystem
280 access_filesys(q, argv, cl)
285 ## int rowcount, users_id, list_id;
287 int status, client_id;
291 ## repeat retrieve (users_id = filesys.owner, list_id = filesys.owners)
292 ## where filesys.label = @name
293 ## inquire_equel(rowcount = "rowcount")
297 if (users_id == cl->users_id)
299 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
301 status = find_member("LIST", list_id, client_type, client_id, 0);
311 /* Setup routine for add_user
313 * Inputs: argv[0] - login
318 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
319 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
322 setup_ausr(q, argv, cl)
324 register char *argv[];
327 ## int nuid, rowcount;
329 if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
330 if (set_next_object_id("uid", "users"))
331 return(SMS_INGRES_ERR);
332 ## repeat retrieve (nuid = values.value) where values.name = "uid"
333 ## inquire_equel(rowcount = "rowcount")
335 return(SMS_INTERNAL);
336 sprintf(argv[1], "%d", nuid);
339 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
340 sprintf(argv[0], "#%s", argv[1]);
347 /* setup_dusr - verify that the user is no longer being referenced
348 * and may safely be deleted.
351 int setup_dusr(q, argv)
357 id = *(int *)argv[0];
359 /* For now, only allow users to be deleted if their status is 0 */
360 ## repeat retrieve (flag = u.status) where u.users_id = @id
364 ## repeat delete nfsquota where nfsquota.users_id = @id
365 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
366 ## and members.member_type = "USER"))
369 ## repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
372 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
373 ## list.acl_type = "USER"))
376 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
377 ## servers.acl_type = "USER"))
380 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
381 ## hostaccess.acl_type = "USER"))
389 /* setup_spop: verify that there is already a valid POP machine_id in the
390 * pop_id field. Also take care of keeping track of the post office usage.
392 int setup_spop(q, argv)
396 ## int id, mid, flag;
399 id = *(int *)argv[0];
400 ## repeat retrieve (type = u.potype, mid = u.pop_id,
401 ## flag = any(machine.name where machine.mach_id = u.pop_id
402 ## and u.pop_id != 0 and u.users_id = @id))
403 ## where u.users_id = @id
406 if (strcmp(strtrim(type), "POP"))
407 set_pop_usage(mid, 1);
412 /* setup_dpob: Take care of keeping track of the post office usage.
414 int setup_dpob(q, argv)
421 user = *(int *)argv[0];
422 ## repeat retrieve (type = u.potype, id = u.pop_id)
423 ## where u.users_id = @user
425 if (!strcmp(strtrim(type), "POP"))
426 set_pop_usage(id, -1);
431 /* setup_dmac - verify that the machine is no longer being referenced
432 * and may safely be deleted.
435 int setup_dmac(q, argv)
441 id = *(int *)argv[0];
442 ## repeat retrieve (flag = any(users.login where users.potype = "POP"
443 ## and users.pop_id=@id))
446 ## repeat retrieve (flag = any(serverhosts.mach_id
447 ## where serverhosts.mach_id=@id))
450 ## repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
453 ## repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
456 ## repeat retrieve (flag = any(printcap.mach_id where printcap.mach_id=@id))
460 ## repeat delete mcmap where mcmap.mach_id = @id
465 /* setup_dclu - verify that the cluster is no longer being referenced
466 * and may safely be deleted.
469 int setup_dclu(q, argv)
475 id = *(int *)argv[0];
476 ## repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
479 ## repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
487 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
488 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
489 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
490 * a -1 there. Remember that this is also used for ulis, with the indexes
494 int setup_alis(q, argv)
502 if (!strcmp(q->shortname, "alis"))
504 else if (!strcmp(q->shortname, "ulis"))
507 if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
508 if (atoi(argv[idx - 1])) {
509 if (set_next_object_id("gid", "list"))
510 return(SMS_INGRES_ERR);
511 ## repeat retrieve (ngid = values.value) where values.name = "gid"
512 sprintf(argv[idx], "%d", ngid);
514 strcpy(argv[idx], "-1");
522 /* setup_dlist - verify that the list is no longer being referenced
523 * and may safely be deleted.
526 int setup_dlis(q, argv)
532 id = *(int *)argv[0];
533 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
534 ## and members.member_type = "LIST"))
537 ## repeat retrieve (flag = any(members.member_id where members.list_id=@id))
540 ## repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
543 ## repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
546 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
547 ## list.acl_type = "LIST" and list.list_id != @id))
550 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
551 ## servers.acl_type = "LIST"))
554 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
555 ## hostaccess.acl_type = "LIST"))
558 ## repeat retrieve (flag = any(zephyr.class
559 ## where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
560 ## zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
561 ## zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
562 ## zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
570 /* setup_dsin - verify that the service is no longer being referenced
571 * and may safely be deleted.
574 int setup_dsin(q, argv)
582 ## repeat retrieve (flag = any(serverhosts.service
583 ## where serverhosts.service=uppercase(@name)))
586 ## repeat retrieve (flag = servers.inprogress) where servers.#name = @name
594 /* setup_dshi - verify that the service-host is no longer being referenced
595 * and may safely be deleted.
598 int setup_dshi(q, argv)
606 id = *(int *)argv[1];
607 ## repeat retrieve (flag=serverhosts.inprogress)
608 ## where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
617 ** setup_add_filesys - verify existance of referenced file systems
629 ** * extract directory prefix from name
630 ** * verify mach_id/dir in nfsphys
631 ** * verify access in {r, w, R, W}
633 ** Side effect: sets variable var_phys_id to the ID of the physical
634 ** filesystem (nfsphys_id for NFS, 0 for RVD)
637 ** SMS_NFS - specified directory not exported
638 ** SMS_FILESYS_ACCESS - invalid filesys access
642 ##static int var_phys_id;
654 mach_id = *(int *)argv[2];
659 if (!strcmp(type, "NFS"))
660 return (check_nfs(mach_id, name, access));
666 /* Verify the arguments, depending on the FStype. Also, if this is an
667 * NFS filesystem, then update any quotas for that filesystem to reflect
676 char *type, *name, *access;
680 mach_id = *(int *)argv[3];
685 if (!strcmp(type, "NFS")) {
686 status = check_nfs(mach_id, name, access);
687 fid = *(int *)argv[0];
688 ## replace nfsquota (phys_id = var_phys_id) where nfsquota.filsys_id = fid
695 /* Find the NFS physical partition that the named directory is on.
696 * This is done by comparing the dir against the mount point of the
697 * partition. To make sure we get the correct match when there is
698 * more than one, we sort the query in reverse order by dir name.
701 ##check_nfs(mach_id, name, access)
712 caccess = (isupper(*access)) ? tolower(*access) : *access;
713 if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
716 ## range of np is nfsphys
717 ## repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
718 ## where np.#mach_id = @mach_id sort by #dir:d {
722 if (*cp1++ != *cp2) break;
726 status = SMS_SUCCESS;
735 /* setup_dfil: free any quota records and fsgroup info associated with
736 * a filesystem when it is deleted. Also adjust the allocation numbers.
739 setup_dfil(q, argv, cl)
746 id = *(int *)argv[0];
747 ## range of q is nfsquota
748 ## range of fs is filesys
749 ## range of n is nfsphys
750 ## repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
751 ## where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
753 ## repeat delete q where q.filsys_id = @id
754 ## repeat delete fsgroup where fsgroup.filsys_id = @id
755 ## repeat delete fsgroup where fsgroup.group_id = @id
760 /* setup_dnfp: check to see that the nfs physical partition does not have
761 * any filesystems assigned to it before allowing it to be deleted.
764 setup_dnfp(q, argv, cl)
771 id = *(int *)argv[0];
772 ## repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
779 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
780 * argv[0] = filsys_id
784 setup_dnfq(q, argv, cl)
789 ## int quota, fs, user;
791 fs = *(int *)argv[0];
792 user = *(int *)argv[1];
794 ## range of q is nfsquota
795 ## repeat retrieve (quota = q.#quota) where q.users_id = @user and
797 ## repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
798 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
804 /* FOLLOWUP ROUTINES */
806 /* generic set_modtime routine. This takes the table name from the query,
807 * and will update the modtime, modby, and modwho fields in the entry in
808 * the table whose name field matches argv[0].
811 set_modtime(q, argv, cl)
816 ## char *name, *entity, *table;
824 ## replace table (modtime = "now", modby = who, modwith = entity)
825 ## where table.#name = name
829 /* generic set_modtime_by_id routine. This takes the table name from
830 * the query, and the id name from the validate record,
831 * and will update the modtime, modby, and modwho fields in the entry in
832 * the table whose id matches argv[0].
835 set_modtime_by_id(q, argv, cl)
840 ## char *entity, *table, *id_name;
846 id_name = q->validate->object_id;
848 id = *(int *)argv[0];
849 ## replace table (modtime = "now", modby = who, modwith = entity)
850 ## where table.id_name = id
855 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
858 set_finger_modtime(q, argv, cl)
863 ## int users_id, who;
868 users_id = *(int *)argv[0];
870 ## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
871 ## where u.#users_id = @users_id
876 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
879 set_pobox_modtime(q, argv, cl)
884 ## int users_id, who;
889 users_id = *(int *)argv[0];
891 ## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
892 ## where users.#users_id = @users_id
897 /* Like set_modtime, but uppercases the name first.
900 set_uppercase_modtime(q, argv, cl)
905 ## char *name, *entity, *table;
913 ## replace table (modtime = "now", modby = who, modwith = entity)
914 ## where table.#name = uppercase(name)
919 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
920 * is necessary for add_machine_to_cluster becuase the table that query
921 * operates on is "mcm", not "machine".
924 set_mach_modtime_by_id(q, argv, cl)
935 id = *(int *)argv[0];
936 ## range of m is machine
937 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
938 ## where m.mach_id = @id
943 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
944 * is necessary for add_cluster_data and delete_cluster_data becuase the
945 * table that query operates on is "svc", not "cluster".
948 set_cluster_modtime_by_id(q, argv, cl)
959 id = *(int *)argv[0];
960 ## range of c is cluster
961 ## repeat replace c (modtime = "now", modby = @who, modwith = @entity)
962 ## where c.clu_id = @id
967 /* sets the modtime on the serverhost where the service name is in argv[0]
968 * and the mach_id is in argv[1].
971 set_serverhost_modtime(q, argv, cl)
976 ## char *entity, *serv;
983 id = *(int *)argv[1];
984 ## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
985 ## where sh.service = uppercase(@serv) and sh.mach_id = @id
990 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
991 * directory name is in argv[1].
994 set_nfsphys_modtime(q, argv, cl)
999 ## char *entity, *dir;
1002 entity = cl->entity;
1005 id = *(int *)argv[0];
1007 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1008 ## where np.#dir = @dir and np.mach_id = @id
1009 return(SMS_SUCCESS);
1013 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1017 set_filesys_modtime(q, argv, cl)
1022 ## char *label, *entity;
1025 entity = cl->entity;
1029 if (!strcmp(q->shortname, "ufil"))
1032 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1033 ## #phys_id = @var_phys_id) where fs.#label = @label
1034 return(SMS_SUCCESS);
1038 /* sets the modtime on a zephyr class, where argv[0] contains the class
1042 set_zephyr_modtime(q, argv, cl)
1047 ## char *class, *entity;
1050 entity = cl->entity;
1055 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1056 ## where z.#class = @class
1057 return(SMS_SUCCESS);
1061 /* fixes the modby field. This will be the second to last thing in the
1062 * argv, the argv length is determined from the query structure. It is
1063 * passed as a pointer to an integer. This will either turn it into a
1064 * username, or # + the users_id.
1066 followup_fix_modby(q, sq, v, action, actarg, cl)
1068 register struct save_queue *sq;
1070 register int (*action)();
1071 register int actarg;
1075 char **argv, *malloc();
1076 ## int id, rowcount;
1080 while (sq_get_data(sq, &argv)) {
1083 argv[i] = malloc(9);
1085 ## repeat retrieve (name = users.login) where users.users_id = @id
1086 ## inquire_equel(rowcount = "rowcount")
1087 if (rowcount != 1) {
1088 sprintf(argv[i], "#%d", id);
1090 (*action)(q->vcnt, argv, actarg);
1091 for (j = 0; j < q->vcnt; j++)
1096 return(SMS_SUCCESS);
1101 ** followup_ausr - add finger and pobox entries, set_user_modtime
1104 ** argv[0] - login (add_user)
1105 ** argv[3] - last name
1106 ** argv[4] - first name
1107 ** argv[5] - middle name
1111 followup_ausr(q, argv, cl)
1117 ## char *login, *entity;
1118 ## char fullname[129];
1122 entity = cl->entity;
1124 /* build fullname */
1125 if (strlen(argv[4]) && strlen(argv[5]))
1126 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1127 else if (strlen(argv[4]))
1128 sprintf(fullname, "%s %s", argv[4], argv[3]);
1130 sprintf(fullname, "%s", argv[3]);
1132 /* create finger entry, pobox & set modtime on user */
1133 ## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1134 ## #fullname=@fullname, mit_affil = u.mit_year,
1135 ## fmodtime="now", fmodby=@who, fmodwith=@entity,
1136 ## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1137 ## where u.#login = @login
1139 return(SMS_SUCCESS);
1143 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1144 * type in argv[1]. Then completes the upcall to the user.
1146 * argv[2] is of the form "123:234" where the first integer is the machine
1147 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1148 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1152 followup_gpob(q, sq, v, action, actarg, cl)
1153 register struct query *q;
1154 register struct save_queue *sq;
1155 register struct validate *v;
1156 register int (*action)();
1160 char **argv, *index();
1162 ## char box[129], *name;
1163 ## int mid, sid, rowcount;
1166 while (sq_get_data(sq, &argv)) {
1167 sms_trim_args(2, argv);
1169 p = index(argv[2], ':');
1171 mid = atoi(argv[2]);
1175 if (!strcmp(ptype, "POP")) {
1176 ## repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1177 ## inquire_equel(rowcount = "rowcount")
1179 return(SMS_MACHINE);
1180 } else if (!strcmp(ptype, "SMTP")) {
1181 ## repeat retrieve (box=strings.string) where strings.string_id=@sid
1182 ## inquire_equel(rowcount = "rowcount")
1185 } else /* ptype == "NONE" */ {
1189 if (!strcmp(q->shortname, "gpob")) {
1190 sid = atoi(argv[4]);
1192 argv[4] = malloc(9);
1194 ## repeat retrieve (name = users.login) where users.users_id = @sid
1195 ## inquire_equel(rowcount = "rowcount")
1197 sprintf(name, "#%d", sid);
1201 (*action)(q->vcnt, argv, actarg);
1203 /* free saved data */
1210 return (SMS_SUCCESS);
1214 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1215 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1216 * proper name based on the type, and repace that string in the argv.
1217 * Also fixes the modby field by called followup_fix_modby.
1220 followup_glin(q, sq, v, action, actarg, cl)
1221 register struct query *q;
1222 register struct save_queue *sq;
1223 register struct validate *v;
1224 register int (*action)();
1228 char **argv, *malloc(), *realloc(), *type;
1230 ## int id, rowcount;
1234 if (!strcmp(q->shortname, "gsin"))
1237 while (sq_get_data(sq, &argv)) {
1238 sms_trim_args(q->vcnt, argv);
1240 id = atoi(argv[i = q->vcnt - 2]);
1242 name = argv[i] = malloc(9);
1243 ## repeat retrieve (name = users.login) where users.users_id = @id
1244 ## inquire_equel(rowcount = "rowcount")
1246 sprintf(argv[i], "#%d", id);
1248 id = atoi(argv[idx]);
1249 type = argv[idx - 1];
1250 if ((name = malloc(33)) == NULL)
1253 if (!strcmp(type, "LIST")) {
1254 ## repeat retrieve (name = list.#name) where list.list_id = @id
1255 ## inquire_equel(rowcount = "rowcount")
1257 strcpy(name, "???");
1258 } else if (!strcmp(type, "USER")) {
1259 ## repeat retrieve (name = users.login) where users.users_id = @id
1260 ## inquire_equel(rowcount = "rowcount")
1262 strcpy(name, "???");
1263 } else if (!strcmp(type, "KERBEROS")) {
1264 ## repeat retrieve (name = strings.string) where strings.string_id = @id
1265 ## inquire_equel(rowcount = "rowcount")
1267 strcpy(name, "???");
1268 } else if (!strcmp(type, "NONE")) {
1269 strcpy(name, "NONE");
1271 strcpy(name, "???");
1275 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1276 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1277 strcpy(argv[6], UNIQUE_GID);
1281 (*action)(q->vcnt, argv, actarg);
1283 /* free saved data */
1284 for (i = 0; i < q->vcnt; i++)
1290 return (SMS_SUCCESS);
1294 /** followup_amtl - followup for amtl and dmfl; when adding a list
1295 ** member to a maillist, make member list a maillist also
1296 ** unless list is a user-group.
1297 ** Then set_list_modtime_by_id.
1300 ** argv[0] - list_id
1301 ** argv[1] - member_type
1302 ** argv[2] - member_id
1306 followup_amtl(q, argv, cl)
1316 list_id = *(int *)argv[0];
1317 entity = cl->entity;
1320 ## range of l is list
1321 ## repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1322 ## where l.#list_id = @list_id
1324 /* if query is not amtl or if member_type is not LIST then return */
1325 if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4))
1326 return(SMS_SUCCESS);
1328 member_id = *(int *)argv[2];
1330 /* is parent list a mailing list? */
1331 ## repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1333 return(SMS_SUCCESS);
1335 /* list is not a user-group; add list to maillist table */
1336 ## repeat replace l (maillist = 1) where l.#list_id = @member_id
1337 return(SMS_SUCCESS);
1341 /* followup_anfq: Add allocation to nfsphys after creating quota.
1342 * argv[0] = filsys_id
1343 * argv[2] = ascii(quota)
1346 followup_anfq(q, argv, cl)
1351 ## int quota, user, fs, who;
1354 fs = *(int *)argv[0];
1355 user = *(int *)argv[1];
1356 quota = atoi(argv[2]);
1358 entity = cl->entity;
1360 ## repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1361 ## where nq.filsys_id = @fs and nq.users_id = @user
1362 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1363 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1364 return(SMS_SUCCESS);
1371 followup_gzcl(q, sq, v, action, actarg, cl)
1372 register struct query *q;
1373 register struct save_queue *sq;
1374 register struct validate *v;
1375 register int (*action)();
1380 ## int rowcount, id;
1384 while (sq_get_data(sq, &argv)) {
1385 sms_trim_args(q->vcnt, argv);
1387 id = atoi(argv[i = q->vcnt - 2]);
1389 name = argv[i] = malloc(9);
1390 ## repeat retrieve (name = users.login) where users.users_id = @id
1391 ## inquire_equel(rowcount = "rowcount")
1393 sprintf(argv[i], "#%d", id);
1395 for (i = 1; i < 8; i+=2) {
1396 id = atoi(argv[i+1]);
1398 if ((name = argv[i+1] = malloc(33)) == NULL)
1400 if (!strcmp(argv[i], "LIST")) {
1401 ## repeat retrieve (name = list.#name) where list.list_id = @id
1402 ## inquire_equel(rowcount = "rowcount")
1404 strcpy(name, "???");
1405 } else if (!strcmp(argv[i], "USER")) {
1406 ## repeat retrieve (name = users.login) where users.users_id = @id
1407 ## inquire_equel(rowcount = "rowcount")
1409 strcpy(name, "???");
1410 } else if (!strcmp(argv[i], "KERBEROS")) {
1411 ## repeat retrieve (name = strings.string) where strings.string_id = @id
1412 ## inquire_equel(rowcount = "rowcount")
1414 strcpy(name, "???");
1415 } else if (!strcmp(argv[i], "NONE")) {
1416 strcpy(name, "NONE");
1418 strcpy(name, "???");
1423 (*action)(q->vcnt, argv, actarg);
1425 /* free saved data */
1426 for (i = 0; i < q->vcnt; i++)
1431 return(SMS_SUCCESS);
1438 followup_gsha(q, sq, v, action, actarg, cl)
1439 register struct query *q;
1440 register struct save_queue *sq;
1441 register struct validate *v;
1442 register int (*action)();
1447 ## int rowcount, id;
1451 while (sq_get_data(sq, &argv)) {
1452 sms_trim_args(q->vcnt, argv);
1456 name = argv[4] = malloc(9);
1457 ## repeat retrieve (name = users.login) where users.users_id = @id
1458 ## inquire_equel(rowcount = "rowcount")
1460 sprintf(argv[4], "#%d", id);
1464 if ((name = argv[2] = malloc(33)) == NULL)
1466 if (!strcmp(argv[1], "LIST")) {
1467 ## repeat retrieve (name = list.#name) where list.list_id = @id
1468 ## inquire_equel(rowcount = "rowcount")
1470 strcpy(name, "???");
1471 } else if (!strcmp(argv[1], "USER")) {
1472 ## repeat retrieve (name = users.login) where users.users_id = @id
1473 ## inquire_equel(rowcount = "rowcount")
1475 strcpy(name, "???");
1476 } else if (!strcmp(argv[1], "KERBEROS")) {
1477 ## repeat retrieve (name = strings.string) where strings.string_id = @id
1478 ## inquire_equel(rowcount = "rowcount")
1480 strcpy(name, "???");
1481 } else if (!strcmp(argv[1], "NONE")) {
1482 strcpy(name, "NONE");
1484 strcpy(name, "???");
1488 (*action)(q->vcnt, argv, actarg);
1490 /* free saved data */
1491 for (i = 0; i < q->vcnt; i++)
1496 return(SMS_SUCCESS);
1501 /* Special query routines */
1503 /* set_pobox - this does all of the real work.
1504 * argv = user_id, type, box
1505 * if type is POP, then box should be a machine, and its ID should be put in
1506 * pop_id. If type is SMTP, then box should be a string and its ID should
1507 * be put in box_id. If type is NONE, then box doesn't matter.
1510 int set_pobox(q, argv, cl)
1515 ## int user, id, rowcount;
1516 ## char *box, potype[9];
1519 user = *(int *)argv[0];
1521 ## repeat retrieve (id = users.pop_id, potype = users.#potype)
1522 ## where users.users_id = @user
1523 if (!strcmp(strtrim(potype), "POP"))
1524 set_pop_usage(id, -1);
1526 if (!strcmp(argv[1], "POP")) {
1527 ## repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1528 ## inquire_equel(rowcount = "rowcount")
1530 return(SMS_MACHINE);
1531 ## repeat replace users (#potype = "POP", pop_id = @id)
1532 ## where users.users_id = @user
1533 set_pop_usage(id, 1);
1534 } else if (!strcmp(argv[1], "SMTP")) {
1535 ## range of s is strings
1536 ## repeat retrieve (id = s.string_id) where s.string = @box
1537 ## inquire_equel (rowcount = "rowcount")
1538 if (rowcount == 0) {
1539 ## range of v is values
1540 ## repeat retrieve (id = v.value) where v.name = "strings_id"
1542 ## repeat replace v (value = @id) where v.name = "strings_id"
1543 ## append to strings (string_id = id, string = box)
1545 ## repeat replace users (#potype = "SMTP", box_id = @id)
1546 ## where users.users_id = @user
1547 } else /* argv[1] == "NONE" */ {
1548 ## repeat replace users (#potype = "NONE") where users.users_id = @user
1551 set_pobox_modtime(q, argv, cl);
1552 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1553 ## where tblstats.#table = "users"
1554 return(SMS_SUCCESS);
1558 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1559 * each list. This is tricky: first build a queue of all requested
1560 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1563 get_list_info(q, aargv, cl, action, actarg)
1564 register struct query *q;
1567 register int (*action)();
1570 char *argv[13], *malloc(), *realloc();
1571 ## char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1572 ## char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1573 ## char modby[9], modwith[9];
1574 ## int id, rowcount, acl_id, hid, modby_id;
1576 struct save_queue *sq, *sq_create();
1578 returned = rowcount = 0;
1582 ## range of l is list
1583 ## repeat retrieve (id = l.list_id) where l.#name = @name {
1584 sq_save_data(sq, id);
1588 return(SMS_NO_MATCH);
1590 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1591 argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1592 argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1595 while (sq_get_data(sq, &id)) {
1599 ## repeat retrieve (listname = l.#name, active = text(l.#active),
1600 ## public = text(l.#public), hidden = text(l.#hidden),
1601 ## hid = l.#hidden, maillist = text(l.#maillist),
1602 ## group = text(l.#group), gid = text(l.#gid),
1603 ## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1604 ## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1605 ## modwith =l.#modwith)
1606 ## where l.list_id = @id
1608 if (atoi(gid) == -1)
1609 argv[6] = UNIQUE_GID;
1611 if (!strcmp(acl_type, "LIST")) {
1612 ## repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1613 ## inquire_equel(rowcount = "rowcount")
1615 strcpy(acl_name, "???");
1616 } else if (!strcmp(acl_type, "USER")) {
1617 ## repeat retrieve (acl_name = users.#login)
1618 ## where users.users_id = @acl_id
1619 ## inquire_equel(rowcount = "rowcount")
1621 strcpy(acl_name, "???");
1622 } else if (!strcmp(acl_type, "KERBEROS")) {
1623 ## repeat retrieve (acl_name = strings.string)
1624 ## where strings.string_id = @acl_id
1625 ## inquire_equel(rowcount = "rowcount")
1627 strcpy(acl_name, "???");
1628 } else if (!strcmp(acl_type, "NONE")) {
1629 strcpy(acl_name, "NONE");
1631 strcpy(acl_name, "???");
1633 ## repeat retrieve (modby = users.login) where users.users_id = @modby_id
1634 ## inquire_equel(rowcount = "rowcount")
1636 sprintf(modby, "#%d", id);
1638 sms_trim_args(q->vcnt, argv);
1640 (*action)(q->vcnt, argv, actarg);
1644 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1645 ## where tblstats.#table = "list"
1647 return (SMS_SUCCESS);
1651 /* get_ace_use - given a type and a name, return a type and a name.
1652 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1653 * and argv[1] will contain the ID of the entity in question. The R*
1654 * types mean to recursively look at every containing list, not just
1655 * when the object in question is a direct member. On return, the
1656 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1659 int get_ace_use(q, argv, cl, action, actarg)
1668 ## int aid, listid, id;
1669 struct save_queue *sq, *sq_create();
1672 aid = *(int *)argv[1];
1673 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
1674 !strcmp(atype, "KERBEROS")) {
1675 return(get_ace_internal(atype, aid, action, actarg));
1679 if (!strcmp(atype, "RLIST")) {
1680 sq_save_data(sq, aid);
1681 /* get all the list_id's of containing lists */
1682 ## range of m is members
1683 while (sq_get_data(sq, &id)) {
1684 ## repeat retrieve (listid = m.list_id)
1685 ## where m.member_type = "LIST" and m.member_id = @id {
1686 sq_save_unique_data(sq, listid);
1689 /* now process each one */
1690 while (sq_get_data(sq, &id)) {
1691 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1696 if (!strcmp(atype, "RUSER")) {
1697 ## range of m is members
1698 ## repeat retrieve (listid = m.list_id)
1699 ## where m.member_type = "USER" and m.member_id = @aid {
1700 sq_save_data(sq, listid);
1702 /* get all the list_id's of containing lists */
1703 while (sq_get_data(sq, &id)) {
1704 ## repeat retrieve (listid = m.list_id)
1705 ## where m.member_type = "LIST" and m.member_id = @id {
1706 sq_save_unique_data(sq, listid);
1709 /* now process each one */
1710 while (sq_get_data(sq, &id)) {
1711 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1714 if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1718 if (!strcmp(atype, "RKERBERO")) {
1719 ## range of m is members
1720 ## repeat retrieve (listid = m.list_id)
1721 ## where m.member_type = "KERBEROS" and m.member_id = @aid {
1722 sq_save_data(sq, listid);
1724 /* get all the list_id's of containing lists */
1725 while (sq_get_data(sq, &id)) {
1726 ## repeat retrieve (listid = m.list_id)
1727 ## where m.member_type = "LIST" and m.member_id = @id {
1728 sq_save_unique_data(sq, listid);
1731 /* now process each one */
1732 while (sq_get_data(sq, &id)) {
1733 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1736 if (get_ace_internal("KERBEROS", aid, action, actarg) == SMS_SUCCESS)
1741 if (!found) return(SMS_NO_MATCH);
1742 return(SMS_SUCCESS);
1746 /* This looks up a single list or user for ace use. atype must be "USER"
1747 * or "LIST", and aid is the ID of the corresponding object. This is used
1748 * by get_ace_use above.
1751 ##get_ace_internal(atype, aid, action, actarg)
1762 if (!strcmp(atype, "LIST")) {
1763 rargv[0] = "FILESYS";
1764 ## repeat retrieve (name = filesys.label)
1765 ## where filesys.owners = @aid {
1766 (*action)(2, rargv, actarg);
1771 ## repeat retrieve (name = capacls.capability)
1772 ## where capacls.list_id = @aid {
1773 (*action)(2, rargv, actarg);
1776 } else if (!strcmp(atype, "USER")) {
1777 rargv[0] = "FILESYS";
1778 ## repeat retrieve (name = filesys.label)
1779 ## where filesys.owner = @aid {
1780 (*action)(2, rargv, actarg);
1786 ## repeat retrieve (name = list.#name)
1787 ## where list.acl_type = @atype and list.acl_id = @aid {
1788 (*action)(2, rargv, actarg);
1792 rargv[0] = "SERVICE";
1793 ## repeat retrieve (name = servers.#name)
1794 ## where servers.acl_type = @atype and servers.acl_id = @aid {
1795 (*action)(2, rargv, actarg);
1799 rargv[0] = "HOSTACCESS";
1800 ## repeat retrieve (name = machine.#name)
1801 ## where machine.mach_id = hostaccess.mach_id and
1802 ## hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1803 (*action)(2, rargv, actarg);
1806 rargv[0] = "ZEPHYR";
1807 ## repeat retrieve (name = zephyr.class)
1808 ## where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
1809 ## zephyr.sub_type = @atype and zephyr.sub_id = @aid or
1810 ## zephyr.iws_type = @atype and zephyr.iws_id = @aid or
1811 ## zephyr.iui_type = @atype and zephyr.iui_id = @aid {
1812 (*action)(2, rargv, actarg);
1816 if (!found) return(SMS_NO_MATCH);
1817 return(SMS_SUCCESS);
1821 /* get_lists_of_member - given a type and a name, return the name and flags
1822 * of all of the lists of the given member. The member_type is one of
1823 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1824 * and argv[1] will contain the ID of the entity in question. The R*
1825 * types mean to recursively look at every containing list, not just
1826 * when the object in question is a direct member.
1829 int get_lists_of_member(q, argv, cl, action, actarg)
1838 ## int aid, listid, id;
1839 struct save_queue *sq, *sq_create();
1842 aid = *(int *)argv[1];
1843 if (!strcmp(atype, "LIST") ||
1844 !strcmp(atype, "USER") ||
1845 !strcmp(atype, "STRING") ||
1846 !strcmp(atype, "KERBEROS")) {
1847 return(glom_internal(atype, aid, action, actarg));
1851 if (!strcmp(atype, "RLIST")) {
1852 sq_save_data(sq, aid);
1853 /* get all the list_id's of containing lists */
1854 ## range of m is members
1855 while (sq_get_data(sq, &id)) {
1856 ## repeat retrieve (listid = m.list_id)
1857 ## where m.member_type = "LIST" and m.member_id = @id {
1858 sq_save_unique_data(sq, listid);
1861 /* now process each one */
1862 while (sq_get_data(sq, &id)) {
1863 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1868 if (!strcmp(atype, "RUSER")) {
1869 ## range of m is members
1870 ## repeat retrieve (listid = m.list_id)
1871 ## where m.member_type = "USER" and m.member_id = @aid {
1872 sq_save_data(sq, listid);
1874 /* get all the list_id's of containing lists */
1875 while (sq_get_data(sq, &id)) {
1876 ## repeat retrieve (listid = m.list_id)
1877 ## where m.member_type = "LIST" and m.member_id = @id {
1878 sq_save_unique_data(sq, listid);
1881 /* now process each one */
1882 while (sq_get_data(sq, &id)) {
1883 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1886 if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1890 if (!strcmp(atype, "RSTRING")) {
1891 ## range of m is members
1892 ## repeat retrieve (listid = m.list_id)
1893 ## where m.member_type = "STRING" and m.member_id = @aid {
1894 sq_save_data(sq, listid);
1896 /* get all the list_id's of containing lists */
1897 while (sq_get_data(sq, &id)) {
1898 ## repeat retrieve (listid = m.list_id)
1899 ## where m.member_type = "LIST" and m.member_id = @id {
1900 sq_save_unique_data(sq, listid);
1903 /* now process each one */
1904 while (sq_get_data(sq, &id)) {
1905 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1908 if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
1912 if (!strcmp(atype, "RKERBERO")) {
1913 ## range of m is members
1914 ## repeat retrieve (listid = m.list_id)
1915 ## where m.member_type = "KERBEROS" and m.member_id = @aid {
1916 sq_save_data(sq, listid);
1918 /* get all the list_id's of containing lists */
1919 while (sq_get_data(sq, &id)) {
1920 ## repeat retrieve (listid = m.list_id)
1921 ## where m.member_type = "LIST" and m.member_id = @id {
1922 sq_save_unique_data(sq, listid);
1925 /* now process each one */
1926 while (sq_get_data(sq, &id)) {
1927 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1930 if (glom_internal("KERBEROS", aid, action, actarg) == SMS_SUCCESS)
1934 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1935 ## where tblstats.#table = "members"
1937 if (!found) return(SMS_NO_MATCH);
1938 return(SMS_SUCCESS);
1942 /* This looks up a single list, user, or string as a member. atype must be
1943 * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
1944 * This is used by get_lists_of_members above.
1947 ##glom_internal(atype, aid, action, actarg)
1955 ## char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
1961 rargv[4] = maillist;
1963 ## repeat retrieve (name = list.#name, active = text(list.#active),
1964 ## public = text(list.#public), hidden = text(list.#hidden),
1965 ## maillist = text(list.#maillist), group = text(list.#group))
1966 ## where list.list_id = m.list_id and
1967 ## m.member_type = @atype and m.member_id = @aid {
1968 (*action)(6, rargv, actarg);
1972 if (!found) return(SMS_NO_MATCH);
1973 return(SMS_SUCCESS);
1977 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1978 * the five flags associated with each list. It will return the name of
1979 * each list that meets the quailifications. It does this by building a
1980 * where clause based on the arguments, then doing a retrieve.
1983 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
1985 int qualified_get_lists(q, argv, cl, action, actarg)
1992 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
1993 "l", "name", lflags));
1997 /** get_members_of_list - optimized query for retrieval of list members
2000 ** argv[0] - list_id
2003 ** - retrieve USER members, then LIST members, then STRING members
2006 get_members_of_list(q, argv, cl, action, actarg)
2014 ## char member_name[129];
2017 list_id = *(int *)argv[0];
2019 targv[1] = member_name;
2021 ## range of m is members
2022 ## repeat retrieve (member_name = users.login)
2023 ## where m.#list_id = @list_id and m.member_type = "USER"
2024 ## and m.member_id = users.users_id
2025 ## sort by #member_name
2027 (*action)(2, targv, actarg);
2031 ## repeat retrieve (member_name = list.name)
2032 ## where m.#list_id = @list_id and m.member_type = "LIST"
2033 ## and m.member_id = list.#list_id
2034 ## sort by #member_name
2036 (*action)(2, targv, actarg);
2039 targv[0] = "STRING";
2040 ## repeat retrieve (member_name = strings.string)
2041 ## where m.#list_id = @list_id and m.member_type = "STRING"
2042 ## and m.member_id = strings.string_id
2043 ## sort by #member_name
2045 (*action)(2, targv, actarg);
2048 targv[0] = "KERBEROS";
2049 ## repeat retrieve (member_name = strings.string)
2050 ## where m.#list_id = @list_id and m.member_type = "KERBEROS"
2051 ## and m.member_id = strings.string_id
2052 ## sort by #member_name
2054 (*action)(2, targv, actarg);
2057 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2058 ## where tblstats.#table = "members"
2059 return(SMS_SUCCESS);
2063 /* count_members_of_list: this is a simple query, but it cannot be done
2064 * through the dispatch table.
2067 int count_members_of_list(q, argv, cl, action, actarg)
2074 ## int list, ct = 0;
2075 char *rargv[1], countbuf[5];
2077 list = *(int *)argv[0];
2078 rargv[0] = countbuf;
2079 ## repeat retrieve (ct = count(members.list_id where members.list_id = @list))
2080 sprintf(countbuf, "%d", ct);
2081 (*action)(1, rargv, actarg);
2082 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2083 ## where tblstats.#table = "members"
2084 return(SMS_SUCCESS);
2088 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2089 * the three flags associated with each service. It will return the name of
2090 * each service that meets the quailifications. It does this by building a
2091 * where clause based on the arguments, then doing a retrieve.
2094 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2096 int qualified_get_server(q, argv, cl, action, actarg)
2103 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2104 "s", "name", sflags));
2108 /* generic qualified get routine, used by qualified_get_lists,
2109 * qualified_get_server, and qualified_get_serverhost.
2111 * start - a simple where clause, must not be empty
2112 * range - the name of the range variable
2113 * field - the field to return
2114 * flags - an array of strings, names of the flag variables
2117 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2127 ## char name[33], qual[256], *rvar, *rtbl, *rfield;
2128 char *rargv[1], buf[32];
2131 strcpy(qual, start);
2132 for (i = 0; i < q->argc; i++) {
2133 if (!strcmp(argv[i], "TRUE")) {
2134 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2135 (void) strcat(qual, buf);
2136 } else if (!strcmp(argv[i], "FALSE")) {
2137 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2138 (void) strcat(qual, buf);
2146 ## range of rvar is rtbl
2147 ## retrieve (name = rvar.rfield) where qual {
2148 (*action)(1, rargv, actarg);
2150 ## inquire_equel(rowcount = "rowcount")
2151 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2152 ## where tblstats.#table = @rtbl
2154 return(SMS_NO_MATCH);
2155 return(SMS_SUCCESS);
2159 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2160 * the five flags associated with each serverhost. It will return the name of
2161 * each service and host that meets the quailifications. It does this by
2162 * building a where clause based on the arguments, then doing a retrieve.
2165 static char *shflags[6] = { "service", "enable", "override", "success",
2166 "inprogress", "hosterror" };
2168 int qualified_get_serverhost(q, argv, cl, action, actarg)
2175 ## char sname[33], mname[33], qual[256];
2176 char *rargv[2], buf[32];
2179 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2181 for (i = 1; i < q->argc; i++) {
2182 if (!strcmp(argv[i], "TRUE")) {
2183 sprintf(buf, " and sh.%s != 0", shflags[i]);
2185 } else if (!strcmp(argv[i], "FALSE")) {
2186 sprintf(buf, " and sh.%s = 0", shflags[i]);
2193 ## range of sh is serverhosts
2194 ## retrieve (sname = sh.service, mname = machine.name) where qual {
2195 (*action)(2, rargv, actarg);
2197 ## inquire_equel(rowcount = "rowcount")
2198 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2199 ## where tblstats.#table = "serverhosts"
2201 return(SMS_NO_MATCH);
2202 return(SMS_SUCCESS);
2206 /* register_user - change user's login name and allocate a pobox, group,
2207 * filesystem, and quota for them. The user's status must start out as 0,
2208 * and is left as 2. Arguments are: user's UID, new login name, and user's
2209 * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY,
2210 * SMS_FS_STAFF, SMS_FS_MISC).
2213 register_user(q, argv, cl)
2218 ## char *login, dir[65], *entity, *directory, machname[33];
2219 ## int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2220 ## int size, alloc, pid, m_id;
2223 entity = cl->entity;
2226 uid = atoi(argv[0]);
2228 utype = atoi(argv[2]);
2230 ## range of u is users
2231 ## range of l is list
2232 ## range of sh is serverhosts
2233 ## range of n is nfsphys
2234 ## range of m is machine
2237 ## repeat retrieve (users_id = u.#users_id)
2238 ## where u.#uid = @uid and u.status = 0
2239 ## inquire_equel(rowcount = "rowcount");
2241 return(SMS_NO_MATCH);
2243 return(SMS_NOT_UNIQUE);
2245 /* check new login name */
2246 ## repeat retrieve (flag = any(u.#login where u.#login = @login))
2247 if (ingres_errno) return(sms_errcode);
2248 if (flag) return(SMS_IN_USE);
2249 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2250 if (ingres_errno) return(sms_errcode);
2251 if (flag) return(SMS_IN_USE);
2252 ## repeat retrieve (flag = any(filesys.#label where filesys.#label = @login))
2253 if (ingres_errno) return(sms_errcode);
2254 if (flag) return(SMS_IN_USE);
2255 com_err(whoami, 0, "new login name OK");
2257 /* choose place for pobox, put in mid */
2258 ## repeat retrieve (mid = sh.mach_id, machname = m.name)
2259 ## where sh.service = "POP" and m.mach_id = sh.mach_id and
2260 ## sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2261 ## inquire_equel(rowcount = "rowcount");
2263 return(SMS_NO_POBOX);
2265 /* change login name, set pobox */
2266 ## repeat replace u (#login = @login, status = 2, modtime = "now",
2267 ## modby = @who, modwith = @entity, potype="POP",
2268 ## pop_id = @mid, pmodtime="now", pmodby=@who,
2269 ## pmodwith=@entity)
2270 ## where u.#users_id = @users_id
2271 ## inquire_equel(rowcount = "rowcount");
2273 return(SMS_INTERNAL);
2274 set_pop_usage(mid, 1);
2275 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2278 /* create group list */
2279 if (set_next_object_id("gid", "list"))
2281 if (set_next_object_id("list_id", "list"))
2283 ## repeat retrieve (list_id = values.value) where values.name = "list_id"
2284 ## inquire_equel(rowcount = "rowcount");
2286 return(SMS_INTERNAL);
2287 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2288 ## public = 0, hidden = 0, maillist = 0, group = 1,
2289 ## #gid = values.value, desc = "User Group",
2290 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2291 ## modby = @who, modwith = @entity)
2292 ## where values.name = "gid"
2293 ## inquire_equel(rowcount = "rowcount");
2295 return(SMS_INTERNAL);
2296 ## repeat append members (#list_id = @list_id, member_type = "USER",
2297 ## member_id = @users_id)
2298 ## inquire_equel(rowcount = "rowcount");
2300 return(SMS_INTERNAL);
2301 com_err(whoami, 0, "group list created");
2303 /* decide where to put filesystem */
2306 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2307 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2308 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2309 maxsize = size - alloc;
2312 directory = strsave(dir);
2318 return(SMS_NO_FILESYS);
2320 /* create filesystem */
2321 if (set_next_object_id("filsys_id", "filesys"))
2323 ## repeat append filesys (filsys_id = values.value, phys_id = @pid,
2324 ## label = @login, type = "NFS", mach_id = @m_id,
2325 ## name = @directory + "/" + @login,
2326 ## mount = "/mit/" + @login,
2327 ## access = "w", comments = "User Locker",
2328 ## owner = @users_id, owners = @list_id, createflg = 1,
2329 ## lockertype = "HOMEDIR", modtime = "now",
2330 ## modby = @who, modwith = @entity)
2331 ## where values.name = "filsys_id"
2332 ## inquire_equel(rowcount = "rowcount");
2334 return(SMS_INTERNAL);
2335 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2339 ## repeat retrieve (quota = values.value) where values.name = "def_quota"
2340 ## inquire_equel(rowcount = "rowcount");
2342 return(SMS_NO_QUOTA);
2343 ## repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2344 ## #quota = @quota, phys_id = @pid, modtime = "now",
2345 ## modby = @who, modwith = @entity)
2346 ## where values.name = "filsys_id"
2347 ## inquire_equel(rowcount = "rowcount");
2349 return(SMS_INTERNAL);
2350 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2351 ## where nfsphys.nfsphys_id = filesys.#phys_id and
2352 ## filesys.filsys_id = values.value and values.name = "filsys_id"
2353 ## inquire_equel(rowcount = "rowcount");
2355 return(SMS_INTERNAL);
2356 com_err(whoami, 0, "quota of %d assigned", quota);
2358 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2359 ## where tblstats.table = "users"
2360 ## repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2361 ## where tblstats.table = "list" or tblstats.table = "filesys" or
2362 ## tblstats.table = "nfsquota"
2363 return(SMS_SUCCESS);
2368 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2372 ** delta (will be +/- 1)
2375 ** - incr/decr value field in serverhosts table for pop/mach_id
2379 static int set_pop_usage(id, count)
2383 ## int mach_id = id;
2386 ## range of sh is serverhosts
2387 ## repeat replace sh (value1 = sh.value1 + @n)
2388 ## where sh.service = "POP" and sh.#mach_id = @mach_id
2390 return(SMS_SUCCESS);
2395 /* Validation Routines */
2397 validate_row(q, argv, v)
2398 register struct query *q;
2400 register struct validate *v;
2408 /* build where clause */
2409 build_qual(v->qual, v->argc, argv, qual);
2411 /* setup ingres variables */
2416 if (log_flags & LOG_VALID)
2417 /* tell the logfile what we're doing */
2418 com_err(whoami, 0, "validating row: %s", qual);
2420 /* look for the record */
2421 ## range of rvar is table
2422 ## retrieve (rowcount = count(rvar.name where qual))
2423 if (ingres_errno) return(sms_errcode);
2424 if (rowcount == 0) return(SMS_NO_MATCH);
2425 if (rowcount > 1) return(SMS_NOT_UNIQUE);
2429 validate_fields(q, argv, vo, n)
2431 register char *argv[];
2432 register struct valobj *vo;
2435 register int status;
2440 if (log_flags & LOG_VALID)
2441 com_err(whoami, 0, "validating %s in %s: %s",
2442 vo->namefield, vo->table, argv[vo->index]);
2443 status = validate_name(argv, vo);
2447 if (log_flags & LOG_VALID)
2448 com_err(whoami, 0, "validating %s in %s: %s",
2449 vo->idfield, vo->table, argv[vo->index]);
2450 status = validate_id(argv, vo);
2454 if (log_flags & LOG_VALID)
2455 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2456 status = validate_date(argv, vo);
2460 if (log_flags & LOG_VALID)
2461 com_err(whoami, 0, "validating %s type: %s",
2462 vo->table, argv[vo->index]);
2463 status = validate_type(argv, vo);
2467 if (log_flags & LOG_VALID)
2468 com_err(whoami, 0, "validating typed data (%s): %s",
2469 argv[vo->index - 1], argv[vo->index]);
2470 status = validate_typedata(q, argv, vo);
2474 if (log_flags & LOG_VALID)
2475 com_err(whoami, 0, "validating rename %s in %s",
2476 argv[vo->index], vo->table);
2477 status = validate_rename(argv, vo);
2481 if (log_flags & LOG_VALID)
2482 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2483 status = validate_chars(argv[vo->index]);
2487 status = SMS_EXISTS;
2491 status = lock_table(vo);
2495 if (status != SMS_EXISTS) return(status);
2499 return(SMS_SUCCESS);
2503 /* validate_chars: verify that there are no illegal characters in
2504 * the string. Legal characters are printing chars other than
2505 * ", *, ?, \, [ and ].
2507 static int illegalchars[] = {
2508 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2509 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2510 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2513 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2514 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2515 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2516 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2517 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2518 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2519 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2520 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2521 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2522 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2523 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2530 if (illegalchars[*s++])
2531 return(SMS_BAD_CHAR);
2536 validate_id(argv, vo)
2538 register struct valobj *vo;
2548 name = argv[vo->index];
2550 /* minor kludge to upcasify machine names */
2551 if (!strcmp(table, "machine"))
2552 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2553 namefield = vo->namefield;
2554 idfield = vo->idfield;
2555 if (!strcmp(namefield, "uid")) {
2556 ## retrieve (id = table.idfield) where table.namefield = int4(name)
2557 if (ingres_errno) return(sms_errcode);
2558 ## inquire_equel (rowcount = "rowcount")
2560 ## retrieve (id = table.idfield) where table.namefield = name
2561 if (ingres_errno) return(sms_errcode);
2562 ## inquire_equel (rowcount = "rowcount")
2564 if (rowcount != 1) return(vo->error);
2565 *(int *)argv[vo->index] = id;
2569 validate_name(argv, vo)
2571 register struct valobj *vo;
2579 name = argv[vo->index];
2581 namefield = vo->namefield;
2582 if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2583 for (c = name; *c; c++)
2587 ## retrieve (rowcount = countu(table.namefield
2588 ## where table.namefield = name))
2589 if (ingres_errno) return(sms_errcode);
2590 return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2593 validate_date(argv, vo)
2601 idate = argv[vo->index];
2603 ## retrieve (dd = interval("years", date(idate) - date("today")))
2604 ## inquire_equel (errorno = "errorno")
2605 if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2610 validate_rename(argv, vo)
2614 ## char *name, *table, *namefield, *idfield;
2618 c = name = argv[vo->index];
2620 if (illegalchars[*c++])
2621 return(SMS_BAD_CHAR);
2623 /* minor kludge to upcasify machine names */
2624 if (!strcmp(table, "machine"))
2625 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2626 namefield = vo->namefield;
2627 idfield = vo->idfield;
2630 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2632 ## retrieve (id = any(table.namefield where table.namefield = name))
2633 if (ingres_errno) return(sms_errcode);
2639 ## retrieve (id = table.idfield) where table.namefield = name
2640 if (ingres_errno) return(sms_errcode);
2641 if (id == -1 || id == *(int *)argv[vo->index - 1])
2648 validate_type(argv, vo)
2650 register struct valobj *vo;
2657 typename = vo->table;
2658 c = value = argv[vo->index];
2660 if (illegalchars[*c++])
2661 return(SMS_BAD_CHAR);
2663 /* uppercase type fields */
2664 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2666 ## range of a is alias
2667 ## repeat retrieve (exists = any(a.trans where a.name = @typename and
2668 ## a.type = "TYPE" and
2669 ## a.trans = @value))
2670 if (ingres_errno) return(sms_errcode);
2671 return (exists ? SMS_EXISTS : vo->error);
2674 /* validate member or type-specific data field */
2676 validate_typedata(q, argv, vo)
2677 register struct query *q;
2678 register char *argv[];
2679 register struct valobj *vo;
2682 ## char *field_type;
2683 ## char data_type[129];
2689 /* get named object */
2690 name = argv[vo->index];
2692 /* get field type string (known to be at index-1) */
2693 field_type = argv[vo->index-1];
2695 /* get corresponding data type associated with field type name */
2696 ## repeat retrieve (data_type = alias.trans)
2697 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
2698 if (ingres_errno) return(sms_errcode);
2699 ## inquire_equel (rowcount = "rowcount")
2700 if (rowcount != 1) return(SMS_TYPE);
2702 /* now retrieve the record id corresponding to the named object */
2703 if (index(data_type, ' '))
2704 *index(data_type, ' ') = 0;
2705 if (!strcmp(data_type, "user")) {
2707 ## repeat retrieve (id = users.users_id) where users.login = @name
2708 ## inquire_equel (rowcount = "rowcount")
2709 if (rowcount != 1) return(SMS_USER);
2711 } else if (!strcmp(data_type, "list")) {
2713 ## repeat retrieve (id = list.list_id) where list.#name = @name
2714 ## inquire_equel (rowcount = "rowcount")
2715 if (rowcount != 1) {
2716 /* if idfield is non-zero, then if argv[0] matches the string
2717 * that we're trying to resolve, we should get the value of
2718 * values.[idfield] for the id.
2720 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2721 set_next_object_id(q->validate->object_id, q->rtable);
2723 ## repeat retrieve (id = values.value) where values.#name = @name
2724 ## inquire_equel(rowcount = "rowcount")
2725 if (rowcount != 1) return(SMS_LIST);
2729 } else if (!strcmp(data_type, "machine")) {
2731 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2732 ## repeat retrieve (id = machine.mach_id) where machine.#name = @name
2733 ## inquire_equel (rowcount = "rowcount")
2734 if (rowcount != 1) return(SMS_MACHINE);
2736 } else if (!strcmp(data_type, "string")) {
2738 ## range of s is strings
2739 ## repeat retrieve (id = s.string_id) where s.string = @name
2740 ## inquire_equel (rowcount = "rowcount")
2741 if (rowcount == 0) {
2742 if (q->type != APPEND) return(SMS_STRING);
2743 ## range of v is values
2744 ## retrieve (id = v.value) where v.#name = "strings_id"
2746 ## replace v (value = id) where v.#name = "strings_id"
2747 ## append to strings (string_id = id, string = name)
2749 } else if (!strcmp(data_type, "none")) {
2755 /* now set value in argv */
2756 *(int *)argv[vo->index] = id;
2758 return (SMS_EXISTS);
2762 /* Lock the table named by the validation object */
2767 ## char *table, *idfield;
2771 idfield = vo->idfield;
2772 ## replace table (modtime = "now") where table.idfield = 0
2773 if (ingres_errno) return(sms_errcode);
2774 ## inquire_equel (rowcount = "rowcount")
2782 /* This looks up a login name and returns the SMS internal ID. It is used
2783 * by authenticate to put the users_id in the client structure.
2786 int get_users_id(name)
2789 ## int id, rowcount;
2794 ## range of u is users
2795 ## repeat retrieve (id = u.#users_id) where u.#login = @login
2796 ## inquire_equel (rowcount = "rowcount")
2805 /* Check the database at startup time. For now this just resets the
2806 * inprogress flags that the DCM uses.
2809 sanity_check_database()