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();
25 /* Specialized Access Routines */
27 /* access_user - verify that client name equals specified login name
29 * - since field validation routines are called first, a users_id is
30 * now in argv[0] instead of the login name.
33 access_user(q, argv, cl)
38 if (cl->users_id != *(int *)argv[0])
46 /* access_login - verify that client name equals specified login name
48 * argv[0...n] contain search info. q->
51 access_login(q, argv, cl)
59 build_qual(q->qual, q->argc, argv, qual);
60 ## retrieve (id = u.users_id) where qual
61 ## inquire_equel(rowcount = "rowcount")
62 if (rowcount != 1 || id != cl->users_id)
70 /* access_list - check access for most list operations
72 * Inputs: argv[0] - list_id
74 * argv[2] - member ID (only for queries "amtl" and "dmfl")
75 * argv[7] - group IID (only for query "ulis")
78 * - check that client is a member of the access control list
79 * - OR, if the query is add_member_to_list or delete_member_from_list
80 * and the list is public, allow access if client = member
83 access_list(q, argv, cl)
88 ## int list_id, acl_id, flags, rowcount, gid;
91 int client_id, status;
93 list_id = *(int *)argv[0];
94 ## repeat retrieve (acl_id = list.#acl_id, acl_type = list.#acl_type,
95 ## gid = list.#gid, flags = list.#public)
96 ## where list.#list_id = @list_id
97 ## inquire_equel(rowcount = "rowcount")
101 /* parse client structure */
102 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
105 /* if amtl or dmfl and list is public allow client to add or delete self */
106 if ((!strcmp("amtl", q->shortname) || !strcmp("dmfl", q->shortname)) &&
107 (flags && !strcmp("USER", argv[1]))) {
108 if (*(int *)argv[2] == client_id) return(SMS_SUCCESS);
109 /* if update_list, don't allow them to change the GID */
110 } else if (!strcmp("ulis", q->shortname)) {
111 if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
112 (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
116 /* check for client in access control list */
117 status = find_member(acl_type, acl_id, client_type, client_id, 0);
118 if (!status) return(SMS_PERM);
124 /* access_visible_list - allow access to list only if it is not hidden,
125 * or if the client is on the ACL
127 * Inputs: argv[0] - list_id
128 * cl - client identifier
131 access_visible_list(q, argv, cl)
136 ## int list_id, acl_id, flags, rowcount;
139 int client_id, status;
141 list_id = *(int *)argv[0];
142 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
143 ## acl_type = list.#acl_type) where list.#list_id = @list_id
144 ## inquire_equel(rowcount = "rowcount")
146 return(SMS_INTERNAL);
150 /* parse client structure */
151 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
154 /* check for client in access control list */
155 status = find_member(acl_type, acl_id, client_type, client_id, 0);
163 /* access_vis_list_by_name - allow access to list only if it is not hidden,
164 * or if the client is on the ACL
166 * Inputs: argv[0] - list name
167 * cl - client identifier
170 access_vis_list_by_name(q, argv, cl)
175 ## int acl_id, flags, rowcount;
176 ## char acl_type[9], *listname;
178 int client_id, status;
181 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
182 ## acl_type = list.#acl_type) where list.#name = @listname
183 ## inquire_equel(rowcount = "rowcount");
185 return(SMS_WILDCARD);
187 return(SMS_NO_MATCH);
191 /* parse client structure */
192 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
195 /* check for client in access control list */
196 status = find_member(acl_type, acl_id, client_type, client_id, 0);
204 /* access_member - allow user to access member of type "USER" and name matches
205 * username, or to access member of type "LIST" and list is one that user is
206 * on the acl of, or the list is visible.
209 access_member(q, argv, cl)
214 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
215 return(access_visible_list(q, &argv[1], cl));
217 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
218 if (cl->users_id == *(int *)argv[1])
226 /* access_qgli - special access routine for Qualified_get_lists. Allows
227 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
230 access_qgli(q, argv, cl)
235 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
241 /* access_service - allow access if user is on ACL of service. Don't
242 * allow access if a wildcard is used.
245 access_service(q, argv, cl)
250 ## int acl_id, rowcount;
251 ## char *name, acl_type[9];
252 int client_id, status;
256 ## repeat retrieve (acl_id = servers.#acl_id, acl_type = servers.#acl_type)
257 ## where servers.#name = uppercase(@name)
258 ## inquire_equel(rowcount = "rowcount")
262 /* parse client structure */
263 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
266 /* check for client in access control list */
267 status = find_member(acl_type, acl_id, client_type, client_id, 0);
268 if (!status) return(SMS_PERM);
275 /* access_filesys - verify that client is owner or on owners list of filesystem
279 access_filesys(q, argv, cl)
284 ## int rowcount, users_id, list_id;
286 int status, client_id;
290 ## repeat retrieve (users_id = filesys.owner, list_id = filesys.owners)
291 ## where filesys.label = @name
292 ## inquire_equel(rowcount = "rowcount")
296 if (users_id == cl->users_id)
298 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
300 status = find_member("LIST", list_id, client_type, client_id, 0);
310 /* Setup routine for add_user
312 * Inputs: argv[0] - login
317 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
318 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
321 setup_ausr(q, argv, cl)
323 register char *argv[];
326 ## int nuid, rowcount;
328 if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
329 if (set_next_object_id("uid", "users"))
330 return(SMS_INGRES_ERR);
331 ## repeat retrieve (nuid = values.value) where values.name = "uid"
332 ## inquire_equel(rowcount = "rowcount")
334 return(SMS_INTERNAL);
335 sprintf(argv[1], "%d", nuid);
338 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
339 sprintf(argv[0], "#%s", argv[1]);
346 /* setup_dusr - verify that the user is no longer being referenced
347 * and may safely be deleted.
350 int setup_dusr(q, argv)
356 id = *(int *)argv[0];
358 /* For now, only allow users to be deleted if their status is 0 */
359 ## repeat retrieve (flag = u.status) where u.users_id = @id
363 ## repeat delete nfsquota where nfsquota.users_id = @id
364 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
365 ## and members.member_type = "USER"))
368 ## repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
371 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
372 ## list.acl_type = "USER"))
375 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
376 ## servers.acl_type = "USER"))
379 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
380 ## hostaccess.acl_type = "USER"))
388 /* setup_spop: verify that there is already a valid POP machine_id in the
389 * pop_id field. Also take care of keeping track of the post office usage.
391 int setup_spop(q, argv)
395 ## int id, mid, flag;
398 id = *(int *)argv[0];
399 ## repeat retrieve (type = u.potype, mid = u.pop_id,
400 ## flag = any(machine.name where machine.mach_id = u.pop_id
401 ## and u.pop_id != 0 and u.users_id = @id))
402 ## where u.users_id = @id
405 if (strcmp(strtrim(type), "POP"))
406 set_pop_usage(mid, 1);
411 /* setup_dpob: Take care of keeping track of the post office usage.
413 int setup_dpob(q, argv)
420 user = *(int *)argv[0];
421 ## repeat retrieve (type = u.potype, id = u.pop_id)
422 ## where u.users_id = @user
424 if (!strcmp(strtrim(type), "POP"))
425 set_pop_usage(id, -1);
430 /* setup_dmac - verify that the machine is no longer being referenced
431 * and may safely be deleted.
434 int setup_dmac(q, argv)
440 id = *(int *)argv[0];
441 ## repeat retrieve (flag = any(users.login where users.potype = "POP"
442 ## and users.pop_id=@id))
445 ## repeat retrieve (flag = any(serverhosts.mach_id
446 ## where serverhosts.mach_id=@id))
449 ## repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
452 ## repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
455 ## repeat retrieve (flag = any(printcap.mach_id where printcap.mach_id=@id))
459 ## repeat delete mcmap where mcmap.mach_id = @id
464 /* setup_dclu - verify that the cluster is no longer being referenced
465 * and may safely be deleted.
468 int setup_dclu(q, argv)
474 id = *(int *)argv[0];
475 ## repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
478 ## repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
486 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
487 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
488 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
489 * a -1 there. Remember that this is also used for ulis, with the indexes
493 int setup_alis(q, argv)
501 if (!strcmp(q->shortname, "alis"))
503 else if (!strcmp(q->shortname, "ulis"))
506 if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
507 if (atoi(argv[idx - 1])) {
508 if (set_next_object_id("gid", "list"))
509 return(SMS_INGRES_ERR);
510 ## repeat retrieve (ngid = values.value) where values.name = "gid"
511 sprintf(argv[idx], "%d", ngid);
513 strcpy(argv[idx], "-1");
521 /* setup_dlist - verify that the list is no longer being referenced
522 * and may safely be deleted.
525 int setup_dlis(q, argv)
531 id = *(int *)argv[0];
532 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
533 ## and members.member_type = "LIST"))
536 ## repeat retrieve (flag = any(members.member_id where members.list_id=@id))
539 ## repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
542 ## repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
545 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
546 ## list.acl_type = "LIST" and list.list_id != @id))
549 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
550 ## servers.acl_type = "LIST"))
553 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
554 ## hostaccess.acl_type = "LIST"))
557 ## repeat retrieve (flag = any(zephyr.class
558 ## where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
559 ## zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
560 ## zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
561 ## zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
569 /* setup_dsin - verify that the service is no longer being referenced
570 * and may safely be deleted.
573 int setup_dsin(q, argv)
581 ## repeat retrieve (flag = any(serverhosts.service
582 ## where serverhosts.service=uppercase(@name)))
585 ## repeat retrieve (flag = servers.inprogress) where servers.#name = @name
593 /* setup_dshi - verify that the service-host is no longer being referenced
594 * and may safely be deleted.
597 int setup_dshi(q, argv)
605 id = *(int *)argv[1];
606 ## repeat retrieve (flag=serverhosts.inprogress)
607 ## where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
616 ** setup_add_filesys - verify existance of referenced file systems
628 ** * extract directory prefix from name
629 ** * verify mach_id/dir in nfsphys
630 ** * verify access in {r, w, R, W}
632 ** Side effect: sets variable var_phys_id to the ID of the physical
633 ** filesystem (nfsphys_id for NFS, 0 for RVD)
636 ** SMS_NFS - specified directory not exported
637 ** SMS_FILESYS_ACCESS - invalid filesys access
641 ##static int var_phys_id;
653 mach_id = *(int *)argv[2];
658 if (!strcmp(type, "NFS"))
659 return (check_nfs(mach_id, name, access));
665 /* Verify the arguments, depending on the FStype. Also, if this is an
666 * NFS filesystem, then update any quotas for that filesystem to reflect
675 char *type, *name, *access;
679 mach_id = *(int *)argv[3];
684 if (!strcmp(type, "NFS")) {
685 status = check_nfs(mach_id, name, access);
686 fid = *(int *)argv[0];
687 ## replace nfsquota (phys_id = var_phys_id) where nfsquota.filsys_id = fid
694 /* Find the NFS physical partition that the named directory is on.
695 * This is done by comparing the dir against the mount point of the
696 * partition. To make sure we get the correct match when there is
697 * more than one, we sort the query in reverse order by dir name.
700 ##check_nfs(mach_id, name, access)
711 caccess = (isupper(*access)) ? tolower(*access) : *access;
712 if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
715 ## range of np is nfsphys
716 ## repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
717 ## where np.#mach_id = @mach_id sort by #dir:d {
721 if (*cp1++ != *cp2) break;
725 status = SMS_SUCCESS;
734 /* setup_dfil: free any quota records and fsgroup info associated with
735 * a filesystem when it is deleted. Also adjust the allocation numbers.
738 setup_dfil(q, argv, cl)
745 id = *(int *)argv[0];
746 ## range of q is nfsquota
747 ## range of fs is filesys
748 ## range of n is nfsphys
749 ## repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
750 ## where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
752 ## repeat delete q where q.filsys_id = @id
753 ## repeat delete fsgroup where fsgroup.filsys_id = @id
754 ## repeat delete fsgroup where fsgroup.group_id = @id
759 /* setup_dnfp: check to see that the nfs physical partition does not have
760 * any filesystems assigned to it before allowing it to be deleted.
763 setup_dnfp(q, argv, cl)
770 id = *(int *)argv[0];
771 ## repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
778 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
779 * argv[0] = filsys_id
783 setup_dnfq(q, argv, cl)
788 ## int quota, fs, user;
790 fs = *(int *)argv[0];
791 user = *(int *)argv[1];
793 ## range of q is nfsquota
794 ## repeat retrieve (quota = q.#quota) where q.users_id = @user and
796 ## repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
797 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
803 /* FOLLOWUP ROUTINES */
805 /* generic set_modtime routine. This takes the table name from the query,
806 * and will update the modtime, modby, and modwho fields in the entry in
807 * the table whose name field matches argv[0].
810 set_modtime(q, argv, cl)
815 ## char *name, *entity, *table;
823 ## replace table (modtime = "now", modby = who, modwith = entity)
824 ## where table.#name = name
828 /* generic set_modtime_by_id routine. This takes the table name from
829 * the query, and the id name from the validate record,
830 * and will update the modtime, modby, and modwho fields in the entry in
831 * the table whose id matches argv[0].
834 set_modtime_by_id(q, argv, cl)
839 ## char *entity, *table, *id_name;
845 id_name = q->validate->object_id;
847 id = *(int *)argv[0];
848 ## replace table (modtime = "now", modby = who, modwith = entity)
849 ## where table.id_name = id
854 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
857 set_finger_modtime(q, argv, cl)
862 ## int users_id, who;
867 users_id = *(int *)argv[0];
869 ## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
870 ## where u.#users_id = @users_id
875 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
878 set_pobox_modtime(q, argv, cl)
883 ## int users_id, who;
888 users_id = *(int *)argv[0];
890 ## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
891 ## where users.#users_id = @users_id
896 /* Like set_modtime, but uppercases the name first.
899 set_uppercase_modtime(q, argv, cl)
904 ## char *name, *entity, *table;
912 ## replace table (modtime = "now", modby = who, modwith = entity)
913 ## where table.#name = uppercase(name)
918 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
919 * is necessary for add_machine_to_cluster becuase the table that query
920 * operates on is "mcm", not "machine".
923 set_mach_modtime_by_id(q, argv, cl)
934 id = *(int *)argv[0];
935 ## range of m is machine
936 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
937 ## where m.mach_id = @id
942 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
943 * is necessary for add_cluster_data and delete_cluster_data becuase the
944 * table that query operates on is "svc", not "cluster".
947 set_cluster_modtime_by_id(q, argv, cl)
958 id = *(int *)argv[0];
959 ## range of c is cluster
960 ## repeat replace c (modtime = "now", modby = @who, modwith = @entity)
961 ## where c.clu_id = @id
966 /* sets the modtime on the serverhost where the service name is in argv[0]
967 * and the mach_id is in argv[1].
970 set_serverhost_modtime(q, argv, cl)
975 ## char *entity, *serv;
982 id = *(int *)argv[1];
983 ## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
984 ## where sh.service = uppercase(@serv) and sh.mach_id = @id
989 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
990 * directory name is in argv[1].
993 set_nfsphys_modtime(q, argv, cl)
998 ## char *entity, *dir;
1001 entity = cl->entity;
1004 id = *(int *)argv[0];
1006 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1007 ## where np.#dir = @dir and np.mach_id = @id
1008 return(SMS_SUCCESS);
1012 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1016 set_filesys_modtime(q, argv, cl)
1021 ## char *label, *entity;
1024 entity = cl->entity;
1028 if (!strcmp(q->shortname, "ufil"))
1031 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1032 ## #phys_id = @var_phys_id) where fs.#label = @label
1033 return(SMS_SUCCESS);
1037 /* sets the modtime on a zephyr class, where argv[0] contains the class
1041 set_zephyr_modtime(q, argv, cl)
1046 ## char *class, *entity;
1049 entity = cl->entity;
1054 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1055 ## where z.#class = @class
1056 return(SMS_SUCCESS);
1060 /* fixes the modby field. This will be the second to last thing in the
1061 * argv, the argv length is determined from the query structure. It is
1062 * passed as a pointer to an integer. This will either turn it into a
1063 * username, or # + the users_id.
1065 followup_fix_modby(q, sq, v, action, actarg, cl)
1067 register struct save_queue *sq;
1069 register int (*action)();
1070 register int actarg;
1074 char **argv, *malloc();
1075 ## int id, rowcount;
1079 while (sq_get_data(sq, &argv)) {
1082 argv[i] = malloc(9);
1084 ## repeat retrieve (name = users.login) where users.users_id = @id
1085 ## inquire_equel(rowcount = "rowcount")
1086 if (rowcount != 1) {
1087 sprintf(argv[i], "#%d", id);
1089 (*action)(q->vcnt, argv, actarg);
1090 for (j = 0; j < q->vcnt; j++)
1095 return(SMS_SUCCESS);
1100 ** followup_ausr - add finger and pobox entries, set_user_modtime
1103 ** argv[0] - login (add_user)
1104 ** argv[3] - last name
1105 ** argv[4] - first name
1106 ** argv[5] - middle name
1110 followup_ausr(q, argv, cl)
1116 ## char *login, *entity;
1117 ## char fullname[129];
1121 entity = cl->entity;
1123 /* build fullname */
1124 if (strlen(argv[4]) && strlen(argv[5]))
1125 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1126 else if (strlen(argv[4]))
1127 sprintf(fullname, "%s %s", argv[4], argv[3]);
1129 sprintf(fullname, "%s", argv[3]);
1131 /* create finger entry, pobox & set modtime on user */
1132 ## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1133 ## #fullname=@fullname, mit_affil = u.mit_year,
1134 ## fmodtime="now", fmodby=@who, fmodwith=@entity,
1135 ## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1136 ## where u.#login = @login
1138 return(SMS_SUCCESS);
1142 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1143 * type in argv[1]. Then completes the upcall to the user.
1145 * argv[2] is of the form "123:234" where the first integer is the machine
1146 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1147 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1151 followup_gpob(q, sq, v, action, actarg, cl)
1152 register struct query *q;
1153 register struct save_queue *sq;
1154 register struct validate *v;
1155 register int (*action)();
1159 char **argv, *index();
1161 ## char box[129], *name;
1162 ## int mid, sid, rowcount;
1165 while (sq_get_data(sq, &argv)) {
1166 sms_trim_args(2, argv);
1168 p = index(argv[2], ':');
1170 mid = atoi(argv[2]);
1174 if (!strcmp(ptype, "POP")) {
1175 ## repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1176 ## inquire_equel(rowcount = "rowcount")
1178 return(SMS_MACHINE);
1179 } else if (!strcmp(ptype, "SMTP")) {
1180 ## repeat retrieve (box=strings.string) where strings.string_id=@sid
1181 ## inquire_equel(rowcount = "rowcount")
1184 } else /* ptype == "NONE" */ {
1188 if (!strcmp(q->shortname, "gpob")) {
1189 sid = atoi(argv[4]);
1191 argv[4] = malloc(9);
1193 ## repeat retrieve (name = users.login) where users.users_id = @sid
1194 ## inquire_equel(rowcount = "rowcount")
1196 sprintf(name, "#%d", sid);
1200 (*action)(q->vcnt, argv, actarg);
1202 /* free saved data */
1209 return (SMS_SUCCESS);
1213 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1214 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1215 * proper name based on the type, and repace that string in the argv.
1216 * Also fixes the modby field by called followup_fix_modby.
1219 followup_glin(q, sq, v, action, actarg, cl)
1220 register struct query *q;
1221 register struct save_queue *sq;
1222 register struct validate *v;
1223 register int (*action)();
1227 char **argv, *malloc(), *realloc(), *type;
1229 ## int id, rowcount;
1233 if (!strcmp(q->shortname, "gsin"))
1236 while (sq_get_data(sq, &argv)) {
1237 sms_trim_args(q->vcnt, argv);
1239 id = atoi(argv[i = q->vcnt - 2]);
1241 name = argv[i] = malloc(9);
1242 ## repeat retrieve (name = users.login) where users.users_id = @id
1243 ## inquire_equel(rowcount = "rowcount")
1245 sprintf(argv[i], "#%d", id);
1247 id = atoi(argv[idx]);
1248 type = argv[idx - 1];
1249 if ((name = malloc(33)) == NULL)
1252 if (!strcmp(type, "LIST")) {
1253 ## repeat retrieve (name = list.#name) where list.list_id = @id
1254 ## inquire_equel(rowcount = "rowcount")
1256 strcpy(name, "???");
1257 } else if (!strcmp(type, "USER")) {
1258 ## repeat retrieve (name = users.login) where users.users_id = @id
1259 ## inquire_equel(rowcount = "rowcount")
1261 strcpy(name, "???");
1262 } else if (!strcmp(type, "NONE")) {
1263 strcpy(name, "NONE");
1265 strcpy(name, "???");
1269 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1270 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1271 strcpy(argv[6], UNIQUE_GID);
1275 (*action)(q->vcnt, argv, actarg);
1277 /* free saved data */
1278 for (i = 0; i < q->vcnt; i++)
1284 return (SMS_SUCCESS);
1288 /** followup_amtl - followup for amtl and dmfl; when adding a list
1289 ** member to a maillist, make member list a maillist also
1290 ** unless list is a user-group.
1291 ** Then set_list_modtime_by_id.
1294 ** argv[0] - list_id
1295 ** argv[1] - member_type
1296 ** argv[2] - member_id
1300 followup_amtl(q, argv, cl)
1310 list_id = *(int *)argv[0];
1311 entity = cl->entity;
1314 ## range of l is list
1315 ## repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1316 ## where l.#list_id = @list_id
1318 /* if query is not amtl or if member_type is not LIST then return */
1319 if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4))
1320 return(SMS_SUCCESS);
1322 member_id = *(int *)argv[2];
1324 /* is parent list a mailing list? */
1325 ## repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1327 return(SMS_SUCCESS);
1329 /* list is not a user-group; add list to maillist table */
1330 ## repeat replace l (maillist = 1) where l.#list_id = @member_id
1331 return(SMS_SUCCESS);
1335 /* followup_anfq: Add allocation to nfsphys after creating quota.
1336 * argv[0] = filsys_id
1337 * argv[2] = ascii(quota)
1340 followup_anfq(q, argv, cl)
1345 ## int quota, user, fs, who;
1348 fs = *(int *)argv[0];
1349 user = *(int *)argv[1];
1350 quota = atoi(argv[2]);
1352 entity = cl->entity;
1354 ## repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1355 ## where nq.filsys_id = @fs and nq.users_id = @user
1356 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1357 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1358 return(SMS_SUCCESS);
1365 followup_gzcl(q, sq, v, action, actarg, cl)
1366 register struct query *q;
1367 register struct save_queue *sq;
1368 register struct validate *v;
1369 register int (*action)();
1374 ## int rowcount, id;
1378 while (sq_get_data(sq, &argv)) {
1379 sms_trim_args(q->vcnt, argv);
1381 id = atoi(argv[i = q->vcnt - 2]);
1383 name = argv[i] = malloc(9);
1384 ## repeat retrieve (name = users.login) where users.users_id = @id
1385 ## inquire_equel(rowcount = "rowcount")
1387 sprintf(argv[i], "#%d", id);
1389 for (i = 1; i < 8; i+=2) {
1390 id = atoi(argv[i+1]);
1392 if ((name = argv[i+1] = malloc(33)) == NULL)
1394 if (!strcmp(argv[i], "LIST")) {
1395 ## repeat retrieve (name = list.#name) where list.list_id = @id
1396 ## inquire_equel(rowcount = "rowcount")
1398 strcpy(name, "???");
1399 } else if (!strcmp(argv[i], "USER")) {
1400 ## repeat retrieve (name = users.login) where users.users_id = @id
1401 ## inquire_equel(rowcount = "rowcount")
1403 strcpy(name, "???");
1404 } else if (!strcmp(argv[i], "NONE")) {
1405 strcpy(name, "NONE");
1407 strcpy(name, "???");
1412 (*action)(q->vcnt, argv, actarg);
1414 /* free saved data */
1415 for (i = 0; i < q->vcnt; i++)
1420 return(SMS_SUCCESS);
1427 followup_gsha(q, sq, v, action, actarg, cl)
1428 register struct query *q;
1429 register struct save_queue *sq;
1430 register struct validate *v;
1431 register int (*action)();
1436 ## int rowcount, id;
1440 while (sq_get_data(sq, &argv)) {
1441 sms_trim_args(q->vcnt, argv);
1445 name = argv[4] = malloc(9);
1446 ## repeat retrieve (name = users.login) where users.users_id = @id
1447 ## inquire_equel(rowcount = "rowcount")
1449 sprintf(argv[4], "#%d", id);
1453 if ((name = argv[2] = malloc(33)) == NULL)
1455 if (!strcmp(argv[1], "LIST")) {
1456 ## repeat retrieve (name = list.#name) where list.list_id = @id
1457 ## inquire_equel(rowcount = "rowcount")
1459 strcpy(name, "???");
1460 } else if (!strcmp(argv[1], "USER")) {
1461 ## repeat retrieve (name = users.login) where users.users_id = @id
1462 ## inquire_equel(rowcount = "rowcount")
1464 strcpy(name, "???");
1465 } else if (!strcmp(argv[1], "NONE")) {
1466 strcpy(name, "NONE");
1468 strcpy(name, "???");
1472 (*action)(q->vcnt, argv, actarg);
1474 /* free saved data */
1475 for (i = 0; i < q->vcnt; i++)
1480 return(SMS_SUCCESS);
1485 /* Special query routines */
1487 /* set_pobox - this does all of the real work.
1488 * argv = user_id, type, box
1489 * if type is POP, then box should be a machine, and its ID should be put in
1490 * pop_id. If type is SMTP, then box should be a string and its ID should
1491 * be put in box_id. If type is NONE, then box doesn't matter.
1494 int set_pobox(q, argv, cl)
1499 ## int user, id, rowcount;
1500 ## char *box, potype[9];
1503 user = *(int *)argv[0];
1505 ## repeat retrieve (id = users.pop_id, potype = users.#potype)
1506 ## where users.users_id = @user
1507 if (!strcmp(strtrim(potype), "POP"))
1508 set_pop_usage(id, -1);
1510 if (!strcmp(argv[1], "POP")) {
1511 ## repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1512 ## inquire_equel(rowcount = "rowcount")
1514 return(SMS_MACHINE);
1515 ## repeat replace users (#potype = "POP", pop_id = @id)
1516 ## where users.users_id = @user
1517 set_pop_usage(id, 1);
1518 } else if (!strcmp(argv[1], "SMTP")) {
1519 ## range of s is strings
1520 ## repeat retrieve (id = s.string_id) where s.string = @box
1521 ## inquire_equel (rowcount = "rowcount")
1522 if (rowcount == 0) {
1523 ## range of v is values
1524 ## repeat retrieve (id = v.value) where v.name = "strings_id"
1526 ## repeat replace v (value = @id) where v.name = "strings_id"
1527 ## append to strings (string_id = id, string = box)
1529 ## repeat replace users (#potype = "SMTP", box_id = @id)
1530 ## where users.users_id = @user
1531 } else /* argv[1] == "NONE" */ {
1532 ## repeat replace users (#potype = "NONE") where users.users_id = @user
1535 set_pobox_modtime(q, argv, cl);
1536 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1537 ## where tblstats.#table = "users"
1538 return(SMS_SUCCESS);
1542 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1543 * each list. This is tricky: first build a queue of all requested
1544 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1547 get_list_info(q, aargv, cl, action, actarg)
1548 register struct query *q;
1551 register int (*action)();
1554 char *argv[13], *malloc(), *realloc();
1555 ## char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1556 ## char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1557 ## char modby[9], modwith[9];
1558 ## int id, rowcount, acl_id, hid, modby_id;
1560 struct save_queue *sq, *sq_create();
1562 returned = rowcount = 0;
1566 ## range of l is list
1567 ## repeat retrieve (id = l.list_id) where l.#name = @name {
1568 sq_save_data(sq, id);
1572 return(SMS_NO_MATCH);
1574 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1575 argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1576 argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1579 while (sq_get_data(sq, &id)) {
1583 ## repeat retrieve (listname = l.#name, active = text(l.#active),
1584 ## public = text(l.#public), hidden = text(l.#hidden),
1585 ## hid = l.#hidden, maillist = text(l.#maillist),
1586 ## group = text(l.#group), gid = text(l.#gid),
1587 ## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1588 ## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1589 ## modwith =l.#modwith)
1590 ## where l.list_id = @id
1592 if (atoi(gid) == -1)
1593 argv[6] = UNIQUE_GID;
1595 if (!strcmp(acl_type, "LIST")) {
1596 ## repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1597 ## inquire_equel(rowcount = "rowcount")
1599 strcpy(acl_name, "???");
1600 } else if (!strcmp(acl_type, "USER")) {
1601 ## repeat retrieve (acl_name = users.#login)
1602 ## where users.users_id = @acl_id
1603 ## inquire_equel(rowcount = "rowcount")
1605 strcpy(acl_name, "???");
1606 } else if (!strcmp(acl_type, "NONE")) {
1607 strcpy(acl_name, "NONE");
1609 strcpy(acl_name, "???");
1611 ## repeat retrieve (modby = users.login) where users.users_id = @modby_id
1612 ## inquire_equel(rowcount = "rowcount")
1614 sprintf(modby, "#%d", id);
1616 sms_trim_args(q->vcnt, argv);
1618 (*action)(q->vcnt, argv, actarg);
1622 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1623 ## where tblstats.#table = "list"
1625 return (SMS_SUCCESS);
1629 /* get_ace_use - given a type and a name, return a type and a name.
1630 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1631 * and argv[1] will contain the ID of the entity in question. The R*
1632 * types mean to recursively look at every containing list, not just
1633 * when the object in question is a direct member. On return, the
1634 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1637 int get_ace_use(q, argv, cl, action, actarg)
1646 ## int aid, listid, id;
1647 struct save_queue *sq, *sq_create();
1650 aid = *(int *)argv[1];
1651 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER")) {
1652 return(get_ace_internal(atype, aid, action, actarg));
1656 if (!strcmp(atype, "RLIST")) {
1657 sq_save_data(sq, aid);
1658 /* get all the list_id's of containing lists */
1659 ## range of m is members
1660 while (sq_get_data(sq, &id)) {
1661 ## repeat retrieve (listid = m.list_id)
1662 ## where m.member_type = "LIST" and m.member_id = @id {
1663 sq_save_unique_data(sq, listid);
1666 /* now process each one */
1667 while (sq_get_data(sq, &id)) {
1668 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1673 if (!strcmp(atype, "RUSER")) {
1674 ## range of m is members
1675 ## repeat retrieve (listid = m.list_id)
1676 ## where m.member_type = "USER" and m.member_id = @aid {
1677 sq_save_data(sq, listid);
1679 /* get all the list_id's of containing lists */
1680 while (sq_get_data(sq, &id)) {
1681 ## repeat retrieve (listid = m.list_id)
1682 ## where m.member_type = "LIST" and m.member_id = @id {
1683 sq_save_unique_data(sq, listid);
1686 /* now process each one */
1687 while (sq_get_data(sq, &id)) {
1688 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1691 if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1696 if (!found) return(SMS_NO_MATCH);
1697 return(SMS_SUCCESS);
1701 /* This looks up a single list or user for ace use. atype must be "USER"
1702 * or "LIST", and aid is the ID of the corresponding object. This is used
1703 * by get_ace_use above.
1706 ##get_ace_internal(atype, aid, action, actarg)
1717 if (!strcmp(atype, "LIST")) {
1718 rargv[0] = "FILESYS";
1719 ## repeat retrieve (name = filesys.label)
1720 ## where filesys.owners = @aid {
1721 (*action)(2, rargv, actarg);
1726 ## repeat retrieve (name = capacls.capability)
1727 ## where capacls.list_id = @aid {
1728 (*action)(2, rargv, actarg);
1731 } else if (!strcmp(atype, "USER")) {
1732 rargv[0] = "FILESYS";
1733 ## repeat retrieve (name = filesys.label)
1734 ## where filesys.owner = @aid {
1735 (*action)(2, rargv, actarg);
1741 ## repeat retrieve (name = list.#name)
1742 ## where list.acl_type = @atype and list.acl_id = @aid {
1743 (*action)(2, rargv, actarg);
1747 rargv[0] = "SERVICE";
1748 ## repeat retrieve (name = servers.#name)
1749 ## where servers.acl_type = @atype and servers.acl_id = @aid {
1750 (*action)(2, rargv, actarg);
1754 rargv[0] = "HOSTACCESS";
1755 ## repeat retrieve (name = machine.#name)
1756 ## where machine.mach_id = hostaccess.mach_id and
1757 ## hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1758 (*action)(2, rargv, actarg);
1761 rargv[0] = "ZEPHYR";
1762 ## repeat retrieve (name = zephyr.class)
1763 ## where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
1764 ## zephyr.sub_type = @atype and zephyr.sub_id = @aid or
1765 ## zephyr.iws_type = @atype and zephyr.iws_id = @aid or
1766 ## zephyr.iui_type = @atype and zephyr.iui_id = @aid {
1767 (*action)(2, rargv, actarg);
1771 if (!found) return(SMS_NO_MATCH);
1772 return(SMS_SUCCESS);
1776 /* get_lists_of_member - given a type and a name, return the name and flags
1777 * of all of the lists of the given member. The member_type is one of
1778 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1779 * and argv[1] will contain the ID of the entity in question. The R*
1780 * types mean to recursively look at every containing list, not just
1781 * when the object in question is a direct member.
1784 int get_lists_of_member(q, argv, cl, action, actarg)
1793 ## int aid, listid, id;
1794 struct save_queue *sq, *sq_create();
1797 aid = *(int *)argv[1];
1798 if (!strcmp(atype, "LIST") ||
1799 !strcmp(atype, "USER") ||
1800 !strcmp(atype, "STRING")) {
1801 return(glom_internal(atype, aid, action, actarg));
1805 if (!strcmp(atype, "RLIST")) {
1806 sq_save_data(sq, aid);
1807 /* get all the list_id's of containing lists */
1808 ## range of m is members
1809 while (sq_get_data(sq, &id)) {
1810 ## repeat retrieve (listid = m.list_id)
1811 ## where m.member_type = "LIST" and m.member_id = @id {
1812 sq_save_unique_data(sq, listid);
1815 /* now process each one */
1816 while (sq_get_data(sq, &id)) {
1817 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1822 if (!strcmp(atype, "RUSER")) {
1823 ## range of m is members
1824 ## repeat retrieve (listid = m.list_id)
1825 ## where m.member_type = "USER" and m.member_id = @aid {
1826 sq_save_data(sq, listid);
1828 /* get all the list_id's of containing lists */
1829 while (sq_get_data(sq, &id)) {
1830 ## repeat retrieve (listid = m.list_id)
1831 ## where m.member_type = "LIST" and m.member_id = @id {
1832 sq_save_unique_data(sq, listid);
1835 /* now process each one */
1836 while (sq_get_data(sq, &id)) {
1837 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1840 if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1844 if (!strcmp(atype, "RSTRING")) {
1845 ## range of m is members
1846 ## repeat retrieve (listid = m.list_id)
1847 ## where m.member_type = "STRING" and m.member_id = @aid {
1848 sq_save_data(sq, listid);
1850 /* get all the list_id's of containing lists */
1851 while (sq_get_data(sq, &id)) {
1852 ## repeat retrieve (listid = m.list_id)
1853 ## where m.member_type = "LIST" and m.member_id = @id {
1854 sq_save_unique_data(sq, listid);
1857 /* now process each one */
1858 while (sq_get_data(sq, &id)) {
1859 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1862 if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
1866 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1867 ## where tblstats.#table = "members"
1869 if (!found) return(SMS_NO_MATCH);
1870 return(SMS_SUCCESS);
1874 /* This looks up a single list, user, or string as a member. atype must be
1875 * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
1876 * This is used by get_lists_of_members above.
1879 ##glom_internal(atype, aid, action, actarg)
1887 ## char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
1893 rargv[4] = maillist;
1895 ## repeat retrieve (name = list.#name, active = text(list.#active),
1896 ## public = text(list.#public), hidden = text(list.#hidden),
1897 ## maillist = text(list.#maillist), group = text(list.#group))
1898 ## where list.list_id = m.list_id and
1899 ## m.member_type = @atype and m.member_id = @aid {
1900 (*action)(6, rargv, actarg);
1904 if (!found) return(SMS_NO_MATCH);
1905 return(SMS_SUCCESS);
1909 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1910 * the five flags associated with each list. It will return the name of
1911 * each list that meets the quailifications. It does this by building a
1912 * where clause based on the arguments, then doing a retrieve.
1915 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
1917 int qualified_get_lists(q, argv, cl, action, actarg)
1924 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
1925 "l", "name", lflags));
1929 /** get_members_of_list - optimized query for retrieval of list members
1932 ** argv[0] - list_id
1935 ** - retrieve USER members, then LIST members, then STRING members
1938 get_members_of_list(q, argv, cl, action, actarg)
1946 ## char member_name[129];
1949 list_id = *(int *)argv[0];
1951 targv[1] = member_name;
1953 ## range of m is members
1954 ## repeat retrieve (member_name = users.login)
1955 ## where m.#list_id = @list_id and m.member_type = "USER"
1956 ## and m.member_id = users.users_id
1957 ## sort by #member_name
1959 (*action)(2, targv, actarg);
1963 ## repeat retrieve (member_name = list.name)
1964 ## where m.#list_id = @list_id and m.member_type = "LIST"
1965 ## and m.member_id = list.#list_id
1966 ## sort by #member_name
1968 (*action)(2, targv, actarg);
1971 targv[0] = "STRING";
1972 ## repeat retrieve (member_name = strings.string)
1973 ## where m.#list_id = @list_id and m.member_type = "STRING"
1974 ## and m.member_id = strings.string_id
1975 ## sort by #member_name
1977 (*action)(2, targv, actarg);
1980 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1981 ## where tblstats.#table = "members"
1982 return(SMS_SUCCESS);
1986 /* count_members_of_list: this is a simple query, but it cannot be done
1987 * through the dispatch table.
1990 int count_members_of_list(q, argv, cl, action, actarg)
1997 ## int list, ct = 0;
1998 char *rargv[1], countbuf[5];
2000 list = *(int *)argv[0];
2001 rargv[0] = countbuf;
2002 ## repeat retrieve (ct = count(members.list_id where members.list_id = @list))
2003 sprintf(countbuf, "%d", ct);
2004 (*action)(1, rargv, actarg);
2005 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2006 ## where tblstats.#table = "members"
2007 return(SMS_SUCCESS);
2011 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2012 * the three flags associated with each service. It will return the name of
2013 * each service that meets the quailifications. It does this by building a
2014 * where clause based on the arguments, then doing a retrieve.
2017 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2019 int qualified_get_server(q, argv, cl, action, actarg)
2026 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2027 "s", "name", sflags));
2031 /* generic qualified get routine, used by qualified_get_lists,
2032 * qualified_get_server, and qualified_get_serverhost.
2034 * start - a simple where clause, must not be empty
2035 * range - the name of the range variable
2036 * field - the field to return
2037 * flags - an array of strings, names of the flag variables
2040 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2050 ## char name[33], qual[256], *rvar, *rtbl, *rfield;
2051 char *rargv[1], buf[32];
2054 strcpy(qual, start);
2055 for (i = 0; i < q->argc; i++) {
2056 if (!strcmp(argv[i], "TRUE")) {
2057 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2058 (void) strcat(qual, buf);
2059 } else if (!strcmp(argv[i], "FALSE")) {
2060 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2061 (void) strcat(qual, buf);
2069 ## range of rvar is rtbl
2070 ## retrieve (name = rvar.rfield) where qual {
2071 (*action)(1, rargv, actarg);
2073 ## inquire_equel(rowcount = "rowcount")
2074 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2075 ## where tblstats.#table = @rtbl
2077 return(SMS_NO_MATCH);
2078 return(SMS_SUCCESS);
2082 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2083 * the five flags associated with each serverhost. It will return the name of
2084 * each service and host that meets the quailifications. It does this by
2085 * building a where clause based on the arguments, then doing a retrieve.
2088 static char *shflags[6] = { "service", "enable", "override", "success",
2089 "inprogress", "hosterror" };
2091 int qualified_get_serverhost(q, argv, cl, action, actarg)
2098 ## char sname[33], mname[33], qual[256];
2099 char *rargv[2], buf[32];
2102 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2104 for (i = 1; i < q->argc; i++) {
2105 if (!strcmp(argv[i], "TRUE")) {
2106 sprintf(buf, " and sh.%s != 0", shflags[i]);
2108 } else if (!strcmp(argv[i], "FALSE")) {
2109 sprintf(buf, " and sh.%s = 0", shflags[i]);
2116 ## range of sh is serverhosts
2117 ## retrieve (sname = sh.service, mname = machine.name) where qual {
2118 (*action)(2, rargv, actarg);
2120 ## inquire_equel(rowcount = "rowcount")
2121 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2122 ## where tblstats.#table = "serverhosts"
2124 return(SMS_NO_MATCH);
2125 return(SMS_SUCCESS);
2129 /* register_user - change user's login name and allocate a pobox, group,
2130 * filesystem, and quota for them. The user's status must start out as 0,
2131 * and is left as 2. Arguments are: user's UID, new login name, and user's
2132 * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY,
2133 * SMS_FS_STAFF, SMS_FS_MISC).
2136 register_user(q, argv, cl)
2141 ## char *login, dir[65], *entity, *directory, machname[33];
2142 ## int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2143 ## int size, alloc, pid, m_id;
2146 entity = cl->entity;
2149 uid = atoi(argv[0]);
2151 utype = atoi(argv[2]);
2153 ## range of u is users
2154 ## range of l is list
2155 ## range of sh is serverhosts
2156 ## range of n is nfsphys
2157 ## range of m is machine
2160 ## repeat retrieve (users_id = u.#users_id)
2161 ## where u.#uid = @uid and u.status = 0
2162 ## inquire_equel(rowcount = "rowcount");
2164 return(SMS_NO_MATCH);
2166 return(SMS_NOT_UNIQUE);
2168 /* check new login name */
2169 ## repeat retrieve (flag = any(u.#login where u.#login = @login))
2172 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2175 ## repeat retrieve (flag = any(filesys.#label where filesys.#label = @login))
2178 com_err(whoami, 0, "new login name OK");
2180 /* choose place for pobox, put in mid */
2181 ## repeat retrieve (mid = sh.mach_id, machname = m.name)
2182 ## where sh.service = "POP" and m.mach_id = sh.mach_id and
2183 ## sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2184 ## inquire_equel(rowcount = "rowcount");
2186 return(SMS_NO_POBOX);
2188 /* change login name, set pobox */
2189 ## repeat replace u (#login = @login, status = 2, modtime = "now",
2190 ## modby = @who, modwith = @entity, potype="POP",
2191 ## pop_id = @mid, pmodtime="now", pmodby=@who,
2192 ## pmodwith=@entity)
2193 ## where u.#users_id = @users_id
2194 ## inquire_equel(rowcount = "rowcount");
2196 return(SMS_INTERNAL);
2197 set_pop_usage(mid, 1);
2198 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2201 /* create group list */
2202 if (set_next_object_id("gid", "list"))
2204 if (set_next_object_id("list_id", "list"))
2206 ## repeat retrieve (list_id = values.value) where values.name = "list_id"
2207 ## inquire_equel(rowcount = "rowcount");
2209 return(SMS_INTERNAL);
2210 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2211 ## public = 0, hidden = 0, maillist = 0, group = 1,
2212 ## #gid = values.value, desc = "User Group",
2213 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2214 ## modby = @who, modwith = @entity)
2215 ## where values.name = "gid"
2216 ## inquire_equel(rowcount = "rowcount");
2218 return(SMS_INTERNAL);
2219 ## repeat append members (#list_id = @list_id, member_type = "USER",
2220 ## member_id = @users_id)
2221 ## inquire_equel(rowcount = "rowcount");
2223 return(SMS_INTERNAL);
2224 com_err(whoami, 0, "group list created");
2226 /* decide where to put filesystem */
2229 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2230 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2231 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2232 maxsize = size - alloc;
2235 directory = strsave(dir);
2241 return(SMS_NO_FILESYS);
2243 /* create filesystem */
2244 if (set_next_object_id("filsys_id", "filesys"))
2246 ## repeat append filesys (filsys_id = values.value, phys_id = @pid,
2247 ## label = @login, type = "NFS", mach_id = @m_id,
2248 ## name = @directory + "/" + @login,
2249 ## mount = "/mit/" + @login,
2250 ## access = "w", comments = "User Locker",
2251 ## owner = @users_id, owners = @list_id, createflg = 1,
2252 ## lockertype = "HOMEDIR", modtime = "now",
2253 ## modby = @who, modwith = @entity)
2254 ## where values.name = "filsys_id"
2255 ## inquire_equel(rowcount = "rowcount");
2257 return(SMS_INTERNAL);
2258 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2262 ## repeat retrieve (quota = values.value) where values.name = "def_quota"
2263 ## inquire_equel(rowcount = "rowcount");
2265 return(SMS_NO_QUOTA);
2266 ## repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2267 ## #quota = @quota, phys_id = @pid, modtime = "now",
2268 ## modby = @who, modwith = @entity)
2269 ## where values.name = "filsys_id"
2270 ## inquire_equel(rowcount = "rowcount");
2272 return(SMS_INTERNAL);
2273 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2274 ## where nfsphys.nfsphys_id = filesys.#phys_id and
2275 ## filesys.filsys_id = values.value and values.name = "filsys_id"
2276 ## inquire_equel(rowcount = "rowcount");
2278 return(SMS_INTERNAL);
2279 com_err(whoami, 0, "quota of %d assigned", quota);
2281 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2282 ## where tblstats.table = "users"
2283 ## repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2284 ## where tblstats.table = "list" or tblstats.table = "filesys" or
2285 ## tblstats.table = "nfsquota"
2286 return(SMS_SUCCESS);
2291 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2295 ** delta (will be +/- 1)
2298 ** - incr/decr value field in serverhosts table for pop/mach_id
2302 static int set_pop_usage(id, count)
2306 ## int mach_id = id;
2309 ## range of sh is serverhosts
2310 ## repeat replace sh (value1 = sh.value1 + @n)
2311 ## where sh.service = "POP" and sh.#mach_id = @mach_id
2313 return(SMS_SUCCESS);
2318 /* Validation Routines */
2320 validate_row(q, argv, v)
2321 register struct query *q;
2323 register struct validate *v;
2331 /* build where clause */
2332 build_qual(v->qual, v->argc, argv, qual);
2334 /* setup ingres variables */
2339 if (log_flags & LOG_VALID)
2340 /* tell the logfile what we're doing */
2341 com_err(whoami, 0, "validating row: %s", qual);
2343 /* look for the record */
2344 ## range of rvar is table
2345 ## retrieve (rowcount = count(rvar.name where qual))
2346 if (rowcount == 0) return(SMS_NO_MATCH);
2347 if (rowcount > 1) return(SMS_NOT_UNIQUE);
2351 validate_fields(q, argv, vo, n)
2353 register char *argv[];
2354 register struct valobj *vo;
2357 register int status;
2362 if (log_flags & LOG_VALID)
2363 com_err(whoami, 0, "validating %s in %s: %s",
2364 vo->namefield, vo->table, argv[vo->index]);
2365 status = validate_name(argv, vo);
2369 if (log_flags & LOG_VALID)
2370 com_err(whoami, 0, "validating %s in %s: %s",
2371 vo->idfield, vo->table, argv[vo->index]);
2372 status = validate_id(argv, vo);
2376 if (log_flags & LOG_VALID)
2377 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2378 status = validate_date(argv, vo);
2382 if (log_flags & LOG_VALID)
2383 com_err(whoami, 0, "validating %s type: %s",
2384 vo->table, argv[vo->index]);
2385 status = validate_type(argv, vo);
2389 if (log_flags & LOG_VALID)
2390 com_err(whoami, 0, "validating typed data (%s): %s",
2391 argv[vo->index - 1], argv[vo->index]);
2392 status = validate_typedata(q, argv, vo);
2396 if (log_flags & LOG_VALID)
2397 com_err(whoami, 0, "validating rename %s in %s",
2398 argv[vo->index], vo->table);
2399 status = validate_rename(argv, vo);
2403 if (log_flags & LOG_VALID)
2404 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2405 status = validate_chars(argv[vo->index]);
2409 status = SMS_EXISTS;
2414 if (status != SMS_EXISTS) return(status);
2418 return(SMS_SUCCESS);
2422 /* validate_chars: verify that there are no illegal characters in
2423 * the string. Legal characters are printing chars other than
2424 * ", *, ?, \, [ and ].
2426 static int illegalchars[] = {
2427 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2428 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2429 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2430 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2431 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2434 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2435 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2436 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2437 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2438 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2439 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2440 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2441 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2442 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2449 if (illegalchars[*s++])
2450 return(SMS_BAD_CHAR);
2455 validate_id(argv, vo)
2457 register struct valobj *vo;
2467 name = argv[vo->index];
2469 /* minor kludge to upcasify machine names */
2470 if (!strcmp(table, "machine"))
2471 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2472 namefield = vo->namefield;
2473 idfield = vo->idfield;
2474 if (!strcmp(namefield, "uid")) {
2475 ## retrieve (id = table.idfield) where table.namefield = int4(name)
2476 ## inquire_equel (rowcount = "rowcount")
2478 ## retrieve (id = table.idfield) where table.namefield = name
2479 ## inquire_equel (rowcount = "rowcount")
2481 if (rowcount != 1) return(vo->error);
2482 *(int *)argv[vo->index] = id;
2486 validate_name(argv, vo)
2488 register struct valobj *vo;
2496 name = argv[vo->index];
2498 namefield = vo->namefield;
2499 if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2500 for (c = name; *c; c++)
2504 ## retrieve (rowcount = countu(table.namefield
2505 ## where table.namefield = name))
2506 return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2509 validate_date(argv, vo)
2517 idate = argv[vo->index];
2519 ## retrieve (dd = interval("years", date(idate) - date("today")))
2520 ## inquire_equel (errorno = "errorno")
2521 if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2526 validate_rename(argv, vo)
2530 ## char *name, *table, *namefield, *idfield;
2534 c = name = argv[vo->index];
2536 if (illegalchars[*c++])
2537 return(SMS_BAD_CHAR);
2539 /* minor kludge to upcasify machine names */
2540 if (!strcmp(table, "machine"))
2541 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2542 namefield = vo->namefield;
2543 idfield = vo->idfield;
2546 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2548 ## retrieve (id = any(table.namefield where table.namefield = name))
2554 ## retrieve (id = table.idfield) where table.namefield = name
2555 if (id == -1 || id == *(int *)argv[vo->index - 1])
2562 validate_type(argv, vo)
2564 register struct valobj *vo;
2571 typename = vo->table;
2572 c = value = argv[vo->index];
2574 if (illegalchars[*c++])
2575 return(SMS_BAD_CHAR);
2577 /* uppercase type fields */
2578 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2580 ## range of a is alias
2581 ## repeat retrieve (exists = any(a.trans where a.name = @typename and
2582 ## a.type = "TYPE" and
2583 ## a.trans = @value))
2584 return (exists ? SMS_EXISTS : vo->error);
2587 /* validate member or type-specific data field */
2589 validate_typedata(q, argv, vo)
2590 register struct query *q;
2591 register char *argv[];
2592 register struct valobj *vo;
2595 ## char *field_type;
2596 ## char data_type[129];
2602 /* get named object */
2603 name = argv[vo->index];
2605 /* get field type string (known to be at index-1) */
2606 field_type = argv[vo->index-1];
2608 /* get corresponding data type associated with field type name */
2609 ## repeat retrieve (data_type = alias.trans)
2610 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
2611 ## inquire_equel (rowcount = "rowcount")
2612 if (rowcount != 1) return(SMS_TYPE);
2614 /* now retrieve the record id corresponding to the named object */
2615 if (index(data_type, ' '))
2616 *index(data_type, ' ') = 0;
2617 if (!strcmp(data_type, "user")) {
2619 ## repeat retrieve (id = users.users_id) where users.login = @name
2620 ## inquire_equel (rowcount = "rowcount")
2621 if (rowcount != 1) return(SMS_USER);
2623 } else if (!strcmp(data_type, "list")) {
2625 ## repeat retrieve (id = list.list_id) where list.#name = @name
2626 ## inquire_equel (rowcount = "rowcount")
2627 if (rowcount != 1) {
2628 /* if idfield is non-zero, then if argv[0] matches the string
2629 * that we're trying to resolve, we should get the value of
2630 * values.[idfield] for the id.
2632 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2633 set_next_object_id(q->validate->object_id, q->rtable);
2635 ## repeat retrieve (id = values.value) where values.#name = @name
2636 ## inquire_equel(rowcount = "rowcount")
2637 if (rowcount != 1) return(SMS_LIST);
2641 } else if (!strcmp(data_type, "machine")) {
2643 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2644 ## repeat retrieve (id = machine.mach_id) where machine.#name = @name
2645 ## inquire_equel (rowcount = "rowcount")
2646 if (rowcount != 1) return(SMS_MACHINE);
2648 } else if (!strcmp(data_type, "string")) {
2650 ## range of s is strings
2651 ## repeat retrieve (id = s.string_id) where s.string = @name
2652 ## inquire_equel (rowcount = "rowcount")
2653 if (rowcount == 0) {
2654 if (q->type != APPEND) return(SMS_STRING);
2655 ## range of v is values
2656 ## retrieve (id = v.value) where v.#name = "strings_id"
2658 ## replace v (value = id) where v.#name = "strings_id"
2659 ## append to strings (string_id = id, string = name)
2661 } else if (!strcmp(data_type, "none")) {
2667 /* now set value in argv */
2668 *(int *)argv[vo->index] = id;
2670 return (SMS_EXISTS);
2674 /* This looks up a login name and returns the SMS internal ID. It is used
2675 * by authenticate to put the users_id in the client structure.
2678 int get_users_id(name)
2681 ## int id, rowcount;
2686 ## range of u is users
2687 ## repeat retrieve (id = u.#users_id) where u.#login = @login
2688 ## inquire_equel (rowcount = "rowcount")
2697 /* Check the database at startup time. For now this just resets the
2698 * inprogress flags that the DCM uses.
2701 sanity_check_database()