6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
11 static char *rcsid_qsupport_qc = "$Header$";
15 #include "sms_server.h"
19 extern char *whoami, *strsave();
22 /* Specialized Access Routines */
24 /* access_user - verify that client name equals specified login name
26 * - since field validation routines are called first, a users_id is
27 * now in argv[0] instead of the login name.
30 access_user(q, argv, cl)
35 if (cl->users_id != *(int *)argv[0])
43 /* access_login - verify that client name equals specified login name
45 * argv[0...n] contain search info. q->
48 access_login(q, argv, cl)
56 build_qual(q->qual, q->argc, argv, qual);
57 ## retrieve (id = u.users_id) where qual
58 ## inquire_equel(rowcount = "rowcount")
59 if (rowcount != 1 || id != cl->users_id)
67 /* access_list - check access for most list operations
69 * Inputs: argv[0] - list_id
71 * argv[2] - member ID (only for queries "amtl" and "dmfl")
74 * - check that client is a member of the access control list
75 * - OR, if the query is add_member_to_list or delete_member_from_list
76 * and the list is public, allow access if client = member
79 access_list(q, argv, cl)
84 ## int list_id, acl_id, flags, rowcount;
87 int client_id, status;
89 list_id = *(int *)argv[0];
90 ## repeat retrieve (acl_id = list.#acl_id, acl_type = list.#acl_type,
91 ## flags = list.#public)
92 ## where list.#list_id = @list_id
93 ## inquire_equel(rowcount = "rowcount")
97 /* parse client structure */
98 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
101 /* if amtl or dmfl and list is public allow client to add or delete self */
102 if ((!strcmp("amtl", q->shortname) || !strcmp("dmfl", q->shortname)) &&
103 (flags && !strcmp("USER", argv[1]))) {
104 if (*(int *)argv[2] == client_id) return(SMS_SUCCESS);
107 /* check for client in access control list */
108 status = find_member(acl_type, acl_id, client_type, client_id, 0);
109 if (!status) return(SMS_PERM);
115 /* access_visible_list - allow access to list only if it is not hidden,
116 * or if the client is on the ACL
118 * Inputs: argv[0] - list_id
119 * cl - client identifier
122 access_visible_list(q, argv, cl)
127 ## int list_id, acl_id, flags, rowcount;
130 int client_id, status;
132 list_id = *(int *)argv[0];
133 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
134 ## acl_type = list.#acl_type) where list.#list_id = @list_id
135 ## inquire_equel(rowcount = "rowcount")
137 return(SMS_INTERNAL);
141 /* parse client structure */
142 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
145 /* check for client in access control list */
146 status = find_member(acl_type, acl_id, client_type, client_id, 0);
154 /* access_vis_list_by_name - allow access to list only if it is not hidden,
155 * or if the client is on the ACL
157 * Inputs: argv[0] - list name
158 * cl - client identifier
161 access_vis_list_by_name(q, argv, cl)
166 ## int acl_id, flags, rowcount;
167 ## char acl_type[9], *listname;
169 int client_id, status;
172 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
173 ## acl_type = list.#acl_type) where list.#name = @listname
174 ## inquire_equel(rowcount = "rowcount");
176 return(SMS_WILDCARD);
178 return(SMS_NO_MATCH);
182 /* parse client structure */
183 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
186 /* check for client in access control list */
187 status = find_member(acl_type, acl_id, client_type, client_id, 0);
195 /* access_member - allow user to access member of type "USER" and name matches
196 * username, or to access member of type "LIST" and list is one that user is
197 * on the acl of, or the list is visible.
200 access_member(q, argv, cl)
205 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
206 return(access_visible_list(q, &argv[1], cl));
208 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
209 if (!strcmp(cl->kname.name, argv[1]))
217 /* access_qgli - special access routine for Qualified_get_lists. Allows
218 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
221 access_qgli(q, argv, cl)
226 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
232 /* access_service - allow access if user is on ACL of service. Don't
233 * allow access if a wildcard is used.
236 access_service(q, argv, cl)
241 ## int acl_id, rowcount;
242 ## char *name, acl_type[9];
243 int client_id, status;
247 ## repeat retrieve (acl_id = servers.#acl_id, acl_type = servers.#acl_type)
248 ## where servers.#name = uppercase(@name)
249 ## inquire_equel(rowcount = "rowcount")
253 /* parse client structure */
254 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
257 /* check for client in access control list */
258 status = find_member(acl_type, acl_id, client_type, client_id, 0);
259 if (!status) return(SMS_PERM);
266 /* access_filesys - verify that client is owner or on owners list of filesystem
270 access_filesys(q, argv, cl)
275 ## int rowcount, users_id, list_id;
277 int status, client_id;
281 ## repeat retrieve (users_id = filesys.owner, list_id = filesys.owners)
282 ## where filesys.label = @name
283 ## inquire_equel(rowcount = "rowcount")
287 if (users_id == cl->users_id)
289 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
291 status = find_member("LIST", list_id, client_type, client_id, 0);
301 /* Setup routine for add_user
303 * Inputs: argv[0] - login
308 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
309 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
312 setup_ausr(q, argv, cl)
314 register char *argv[];
317 ## int nuid, rowcount;
319 if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
320 if (set_next_object_id("uid", "users"))
321 return(SMS_INGRES_ERR);
322 ## repeat retrieve (nuid = values.value) where values.name = "uid"
323 ## inquire_equel(rowcount = "rowcount")
325 return(SMS_INTERNAL);
326 sprintf(argv[1], "%d", nuid);
329 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
330 sprintf(argv[0], "#%s", argv[1]);
337 /* setup_dusr - verify that the user is no longer being referenced
338 * and may safely be deleted.
341 int setup_dusr(q, argv)
347 id = *(int *)argv[0];
348 ## repeat delete nfsquota where nfsquota.users_id = @id
349 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
350 ## and members.member_type = "USER"))
353 ## repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
356 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
357 ## list.acl_type = "USER"))
360 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
361 ## servers.acl_type = "USER"))
364 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
365 ## hostaccess.acl_type = "USER"))
373 /* setup_spop: verify that there is already a valid POP machine_id in the
374 * pop_id field. Also take care of keeping track of the post office usage.
376 int setup_spop(q, argv)
383 id = *(int *)argv[0];
384 ## repeat retrieve (type = u.potype, flag = any(machine.name
385 ## where machine.mach_id = u.pop_id
387 ## and u.users_id = @id))
388 ## where u.users_id = @id
391 if (strcmp(type, "POP"))
392 set_pop_usage(id, 1);
397 /* setup_dpob: Take care of keeping track of the post office usage.
399 int setup_dpob(q, argv)
406 user = *(int *)argv[0];
407 ## repeat retrieve (type = u.potype, id = u.pop_id)
408 ## where u.users_id = @user
410 if (strcmp(type, "POP"))
411 set_pop_usage(id, -1);
416 /* setup_dmac - verify that the machine is no longer being referenced
417 * and may safely be deleted.
420 int setup_dmac(q, argv)
426 id = *(int *)argv[0];
427 ## repeat retrieve (flag = any(users.login where users.potype = "POP"
428 ## and users.pop_id=@id))
431 ## repeat retrieve (flag = any(serverhosts.mach_id
432 ## where serverhosts.mach_id=@id))
435 ## repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
438 ## repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
442 ## repeat delete mcmap where mcmap.mach_id = @id
447 /* setup_dclu - verify that the cluster is no longer being referenced
448 * and may safely be deleted.
451 int setup_dclu(q, argv)
457 id = *(int *)argv[0];
458 ## repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
461 ## repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
469 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
470 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
471 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
472 * a -1 there. Remember that this is also used for ulis, with the indexes
476 int setup_alis(q, argv)
484 if (!strcmp(q->shortname, "alis"))
486 else if (!strcmp(q->shortname, "ulis"))
489 if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
490 if (atoi(argv[idx - 1])) {
491 if (set_next_object_id("gid", "list"))
492 return(SMS_INGRES_ERR);
493 ## repeat retrieve (ngid = values.value) where values.name = "gid"
494 sprintf(argv[idx], "%d", ngid);
496 strcpy(argv[idx], "-1");
504 /* setup_dlist - verify that the list is no longer being referenced
505 * and may safely be deleted.
508 int setup_dlis(q, argv)
514 id = *(int *)argv[0];
515 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
516 ## and members.member_type = "LIST"))
519 ## repeat retrieve (flag = any(members.member_id where members.list_id=@id))
522 ## repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
525 ## repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
528 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
529 ## list.acl_type = "LIST" and list.list_id != @id))
532 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
533 ## servers.acl_type = "LIST"))
536 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
537 ## hostaccess.acl_type = "LIST"))
540 ## repeat retrieve (flag = any(zephyr.class
541 ## where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
542 ## zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
543 ## zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
544 ## zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
552 /* setup_dsin - verify that the service is no longer being referenced
553 * and may safely be deleted.
556 int setup_dsin(q, argv)
564 ## repeat retrieve (flag = any(serverhosts.service
565 ## where serverhosts.service=uppercase(@name)))
568 ## repeat retrieve (flag = servers.inprogress) where servers.#name = @name
576 /* setup_dshi - verify that the service-host is no longer being referenced
577 * and may safely be deleted.
580 int setup_dshi(q, argv)
588 id = *(int *)argv[1];
589 ## repeat retrieve (flag=serverhosts.inprogress)
590 ## where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
599 ** setup_add_filesys - verify existance of referenced file systems
611 ** * extract directory prefix from name
612 ** * verify mach_id/dir in nfsphys
613 ** * verify access in {r, w, R, W}
615 ** Side effect: sets variable var_phys_id to the ID of the physical
616 ** filesystem (nfsphys_id for NFS, 0 for RVD)
619 ** SMS_NFS - specified directory not exported
620 ** SMS_FILESYS_ACCESS - invalid filesys access
624 ##static int var_phys_id;
636 mach_id = *(int *)argv[2];
641 if (!strcmp(type, "NFS"))
642 return (check_nfs(mach_id, name, access));
658 mach_id = *(int *)argv[3];
663 if (!strcmp(type, "NFS"))
664 return (check_nfs(mach_id, name, access));
670 /* Find the NFS physical partition that the named directory is on.
671 * This is done by comparing the dir against the mount point of the
672 * partition. To make sure we get the correct match when there is
673 * more than one, we sort the query in reverse order by dir name.
676 ##check_nfs(mach_id, name, access)
687 caccess = (isupper(*access)) ? tolower(*access) : *access;
688 if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
691 ## range of np is nfsphys
692 ## repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
693 ## where np.#mach_id = @mach_id sort by #dir:d {
697 if (*cp1++ != *cp2) break;
701 status = SMS_SUCCESS;
710 /* setup_dfil: free any quota records associated with a filesystem
711 * when it is deleted.
714 setup_dfil(q, argv, cl)
721 id = *(int *)argv[0];
722 ## range of q is nfsquota
723 ## range of fs is filesys
724 ## range of n is nfsphys
725 ## repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
726 ## where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
728 ## repeat delete q where q.filsys_id = @id
733 /* setup_dnfp: check to see that the nfs physical partition does not have
734 * any filesystems assigned to it before allowing it to be deleted.
737 setup_dnfp(q, argv, cl)
744 id = *(int *)argv[0];
745 ## repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
752 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
753 * argv[0] = filsys_id
757 setup_dnfq(q, argv, cl)
762 ## int quota, fs, user;
764 fs = *(int *)argv[0];
765 user = *(int *)argv[1];
767 ## range of q is nfsquota
768 ## repeat retrieve (quota = q.#quota) where q.users_id = @user and
770 ## repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
771 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
777 /* FOLLOWUP ROUTINES */
779 /* generic set_modtime routine. This takes the table name from the query,
780 * and will update the modtime, modby, and modwho fields in the entry in
781 * the table whose name field matches argv[0].
784 set_modtime(q, argv, cl)
789 ## char *name, *entity, *table;
797 ## replace table (modtime = "now", modby = who, modwith = entity)
798 ## where table.#name = name
802 /* generic set_modtime_by_id routine. This takes the table name from
803 * the query, and the id name from the validate record,
804 * and will update the modtime, modby, and modwho fields in the entry in
805 * the table whose id matches argv[0].
808 set_modtime_by_id(q, argv, cl)
813 ## char *entity, *table, *id_name;
819 id_name = q->validate->object_id;
821 id = *(int *)argv[0];
822 ## replace table (modtime = "now", modby = who, modwith = entity)
823 ## where table.id_name = id
828 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
831 set_finger_modtime(q, argv, cl)
836 ## int users_id, who;
841 users_id = *(int *)argv[0];
843 ## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
844 ## where u.#users_id = @users_id
849 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
852 set_pobox_modtime(q, argv, cl)
857 ## int users_id, who;
862 users_id = *(int *)argv[0];
864 ## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
865 ## where users.#users_id = @users_id
870 /* Sets the modtime on a machine record. The machine name is in argv[0].
871 * This routine is different from the generic set_modtime in that the
872 * name is uppercased first.
875 set_mach_modtime(q, argv, cl)
880 ## char *host, *entity;
887 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
888 ## where m.name = uppercase(@host)
893 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
894 * is necessary for add_machine_to_cluster becuase the table that query
895 * operates on is "mcm", not "machine".
898 set_mach_modtime_by_id(q, argv, cl)
909 id = *(int *)argv[0];
910 ## range of m is machine
911 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
912 ## where m.mach_id = @id
917 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
918 * is necessary for add_cluster_data and delete_cluster_data becuase the
919 * table that query operates on is "svc", not "cluster".
922 set_cluster_modtime_by_id(q, argv, cl)
933 id = *(int *)argv[0];
934 ## range of c is cluster
935 ## repeat replace c (modtime = "now", modby = @who, modwith = @entity)
936 ## where c.clu_id = @id
941 /* sets the modtime on the serverhost where the service name is in argv[0]
942 * and the mach_id is in argv[1].
945 set_serverhost_modtime(q, argv, cl)
950 ## char *entity, *serv;
957 id = *(int *)argv[1];
958 ## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
959 ## where sh.service = uppercase(@serv) and sh.mach_id = @id
964 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
965 * directory name is in argv[1].
968 set_nfsphys_modtime(q, argv, cl)
973 ## char *entity, *dir;
979 id = *(int *)argv[0];
981 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
982 ## where np.#dir = @dir and np.mach_id = @id
987 /* sets the modtime on a filesystem, where argv[0] contains the filesys
991 set_filesys_modtime(q, argv, cl)
996 ## char *label, *entity;
1003 if (!strcmp(q->shortname, "ufil"))
1006 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1007 ## #phys_id = @var_phys_id) where fs.#label = @label
1008 return(SMS_SUCCESS);
1012 /* sets the modtime on a zephyr class, where argv[0] contains the class
1016 set_zephyr_modtime(q, argv, cl)
1021 ## char *class, *entity;
1024 entity = cl->entity;
1029 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1030 ## where z.#class = @class
1031 return(SMS_SUCCESS);
1035 /* fixes the modby field. This will be the second to last thing in the
1036 * argv, the argv length is determined from the query structure. It is
1037 * passed as a pointer to an integer. This will either turn it into a
1038 * username, or # + the users_id.
1040 followup_fix_modby(q, sq, v, action, actarg, cl)
1042 register struct save_queue *sq;
1044 register int (*action)();
1045 register int actarg;
1049 char **argv, *malloc();
1050 ## int id, rowcount;
1054 while (sq_get_data(sq, &argv)) {
1057 argv[i] = malloc(9);
1059 ## repeat retrieve (name = users.login) where users.users_id = @id
1060 ## inquire_equel(rowcount = "rowcount")
1061 if (rowcount != 1) {
1062 sprintf(argv[i], "#%d", id);
1064 (*action)(q->vcnt, argv, actarg);
1065 for (j = 0; j < q->vcnt; j++)
1070 return(SMS_SUCCESS);
1075 ** followup_ausr - add finger and pobox entries, set_user_modtime
1078 ** argv[0] - login (add_user)
1079 ** argv[3] - last name
1080 ** argv[4] - first name
1081 ** argv[5] - middle name
1085 followup_ausr(q, argv, cl)
1091 ## char *login, *entity;
1092 ## char fullname[129];
1096 entity = cl->entity;
1098 /* build fullname */
1099 if (strlen(argv[4]) && strlen(argv[5]))
1100 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1101 else if (strlen(argv[4]))
1102 sprintf(fullname, "%s %s", argv[4], argv[3]);
1104 sprintf(fullname, "%s", argv[3]);
1106 /* create finger entry, pobox & set modtime on user */
1107 ## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1108 ## #fullname=@fullname, mit_affil = u.mit_year,
1109 ## fmodtime="now", fmodby=@who, fmodwith=@entity,
1110 ## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1111 ## where u.#login = @login
1113 return(SMS_SUCCESS);
1117 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1118 * type in argv[1]. Then completes the upcall to the user.
1120 * argv[2] is of the form "123:234" where the first integer is the machine
1121 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1122 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1126 followup_gpob(q, sq, v, action, actarg, cl)
1127 register struct query *q;
1128 register struct save_queue *sq;
1129 register struct validate *v;
1130 register int (*action)();
1134 char **argv, *index();
1136 ## char box[129], *name;
1137 ## int mid, sid, rowcount;
1140 while (sq_get_data(sq, &argv)) {
1141 sms_trim_args(2, argv);
1143 p = index(argv[2], ':');
1145 mid = atoi(argv[2]);
1149 if (!strcmp(ptype, "POP")) {
1150 ## repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1151 ## inquire_equel(rowcount = "rowcount")
1153 return(SMS_MACHINE);
1154 } else if (!strcmp(ptype, "SMTP")) {
1155 ## repeat retrieve (box=strings.string) where strings.string_id=@sid
1156 ## inquire_equel(rowcount = "rowcount")
1159 } else /* ptype == "NONE" */ {
1163 if (!strcmp(q->shortname, "gpob")) {
1164 sid = atoi(argv[4]);
1166 argv[4] = malloc(9);
1168 ## repeat retrieve (name = users.login) where users.users_id = @sid
1169 ## inquire_equel(rowcount = "rowcount")
1171 sprintf(name, "#%d", sid);
1175 (*action)(q->vcnt, argv, actarg);
1177 /* free saved data */
1184 return (SMS_SUCCESS);
1188 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1189 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1190 * proper name based on the type, and repace that string in the argv.
1191 * Also fixes the modby field by called followup_fix_modby.
1194 followup_glin(q, sq, v, action, actarg, cl)
1195 register struct query *q;
1196 register struct save_queue *sq;
1197 register struct validate *v;
1198 register int (*action)();
1202 char **argv, *malloc(), *realloc(), *type;
1204 ## int id, rowcount;
1208 if (!strcmp(q->shortname, "gsin"))
1211 while (sq_get_data(sq, &argv)) {
1212 sms_trim_args(q->vcnt, argv);
1214 id = atoi(argv[i = q->vcnt - 2]);
1216 name = argv[i] = malloc(9);
1217 ## repeat retrieve (name = users.login) where users.users_id = @id
1218 ## inquire_equel(rowcount = "rowcount")
1220 sprintf(argv[i], "#%d", id);
1222 id = atoi(argv[idx]);
1223 type = argv[idx - 1];
1224 if ((name = malloc(33)) == NULL)
1227 if (!strcmp(type, "LIST")) {
1228 ## repeat retrieve (name = list.#name) where list.list_id = @id
1229 ## inquire_equel(rowcount = "rowcount")
1231 strcpy(name, "???");
1232 } else if (!strcmp(type, "USER")) {
1233 ## repeat retrieve (name = users.login) where users.users_id = @id
1234 ## inquire_equel(rowcount = "rowcount")
1236 strcpy(name, "???");
1237 } else if (!strcmp(type, "NONE")) {
1238 strcpy(name, "NONE");
1240 strcpy(name, "???");
1244 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1245 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1246 strcpy(argv[6], UNIQUE_GID);
1250 (*action)(q->vcnt, argv, actarg);
1252 /* free saved data */
1253 for (i = 0; i < q->vcnt; i++)
1259 return (SMS_SUCCESS);
1263 /** followup_amtl - followup for amtl and dmfl; when adding a list
1264 ** member to a maillist, make member list a maillist also
1265 ** unless list is a user-group.
1266 ** Then set_list_modtime_by_id.
1269 ** argv[0] - list_id
1270 ** argv[1] - member_type
1271 ** argv[2] - member_id
1275 followup_amtl(q, argv, cl)
1285 list_id = *(int *)argv[0];
1286 entity = cl->entity;
1289 ## range of l is list
1290 ## repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1291 ## where l.#list_id = @list_id
1293 /* if query is not amtl or if member_type is not LIST then return */
1294 if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4))
1295 return(SMS_SUCCESS);
1297 member_id = *(int *)argv[2];
1299 /* is parent list a mailing list? */
1300 ## repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1302 return(SMS_SUCCESS);
1304 /* list is not a user-group; add list to maillist table */
1305 ## repeat replace l (maillist = 1) where l.#list_id = @member_id
1306 return(SMS_SUCCESS);
1310 /* followup_anfq: Add allocation to nfsphys after creating quota.
1311 * argv[0] = filsys_id
1312 * argv[2] = ascii(quota)
1315 followup_anfq(q, argv, cl)
1320 ## int quota, user, fs, who;
1323 fs = *(int *)argv[0];
1324 user = *(int *)argv[1];
1325 quota = atoi(argv[2]);
1327 entity = cl->entity;
1329 ## repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1330 ## where nq.filsys_id = @fs and nq.users_id = @user
1331 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1332 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1333 return(SMS_SUCCESS);
1340 followup_gzcl(q, sq, v, action, actarg, cl)
1341 register struct query *q;
1342 register struct save_queue *sq;
1343 register struct validate *v;
1344 register int (*action)();
1349 ## int rowcount, id;
1353 while (sq_get_data(sq, &argv)) {
1354 sms_trim_args(q->vcnt, argv);
1356 id = atoi(argv[i = q->vcnt - 2]);
1358 name = argv[i] = malloc(9);
1359 ## repeat retrieve (name = users.login) where users.users_id = @id
1360 ## inquire_equel(rowcount = "rowcount")
1362 sprintf(argv[i], "#%d", id);
1364 for (i = 1; i < 8; i+=2) {
1365 id = atoi(argv[i+1]);
1367 if ((name = argv[i+1] = malloc(33)) == NULL)
1369 if (!strcmp(argv[i], "LIST")) {
1370 ## repeat retrieve (name = list.#name) where list.list_id = @id
1371 ## inquire_equel(rowcount = "rowcount")
1373 strcpy(name, "???");
1374 } else if (!strcmp(argv[i], "USER")) {
1375 ## repeat retrieve (name = users.login) where users.users_id = @id
1376 ## inquire_equel(rowcount = "rowcount")
1378 strcpy(name, "???");
1379 } else if (!strcmp(argv[i], "NONE")) {
1380 strcpy(name, "NONE");
1382 strcpy(name, "???");
1387 (*action)(q->vcnt, argv, actarg);
1389 /* free saved data */
1390 for (i = 0; i < q->vcnt; i++)
1395 return(SMS_SUCCESS);
1402 followup_gsha(q, sq, v, action, actarg, cl)
1403 register struct query *q;
1404 register struct save_queue *sq;
1405 register struct validate *v;
1406 register int (*action)();
1411 ## int rowcount, id;
1415 while (sq_get_data(sq, &argv)) {
1416 sms_trim_args(q->vcnt, argv);
1420 name = argv[4] = malloc(9);
1421 ## repeat retrieve (name = users.login) where users.users_id = @id
1422 ## inquire_equel(rowcount = "rowcount")
1424 sprintf(argv[4], "#%d", id);
1428 if ((name = argv[2] = malloc(33)) == NULL)
1430 if (!strcmp(argv[1], "LIST")) {
1431 ## repeat retrieve (name = list.#name) where list.list_id = @id
1432 ## inquire_equel(rowcount = "rowcount")
1434 strcpy(name, "???");
1435 } else if (!strcmp(argv[1], "USER")) {
1436 ## repeat retrieve (name = users.login) where users.users_id = @id
1437 ## inquire_equel(rowcount = "rowcount")
1439 strcpy(name, "???");
1440 } else if (!strcmp(argv[1], "NONE")) {
1441 strcpy(name, "NONE");
1443 strcpy(name, "???");
1447 (*action)(q->vcnt, argv, actarg);
1449 /* free saved data */
1450 for (i = 0; i < q->vcnt; i++)
1455 return(SMS_SUCCESS);
1460 /* Special query routines */
1462 /* set_pobox - this does all of the real work.
1463 * argv = user_id, type, box
1464 * if type is POP, then box should be a machine, and its ID should be put in
1465 * pop_id. If type is SMTP, then box should be a string and its ID should
1466 * be put in box_id. If type is NONE, then box doesn't matter.
1469 int set_pobox(q, argv, cl)
1474 ## int user, id, rowcount;
1475 ## char *box, potype[9];
1478 user = *(int *)argv[0];
1480 ## repeat retrieve (id = users.pop_id, potype = users.#potype)
1481 ## where users.users_id = @user
1482 if (!strcmp(potype, "POP"))
1483 set_pop_usage(id, -1);
1485 if (!strcmp(argv[1], "POP")) {
1486 ## repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1487 ## inquire_equel(rowcount = "rowcount")
1489 return(SMS_MACHINE);
1490 ## repeat replace users (#potype = "POP", pop_id = @id)
1491 ## where users.users_id = @user
1492 set_pop_usage(id, 1);
1493 } else if (!strcmp(argv[1], "SMTP")) {
1494 ## range of s is strings
1495 ## repeat retrieve (id = s.string_id) where s.string = @box
1496 ## inquire_equel (rowcount = "rowcount")
1497 if (rowcount == 0) {
1498 ## range of v is values
1499 ## repeat retrieve (id = v.value) where v.name = "strings_id"
1501 ## repeat replace v (value = @id) where v.name = "strings_id"
1502 ## append to strings (string_id = id, string = box)
1504 ## repeat replace users (#potype = "SMTP", box_id = @id)
1505 ## where users.users_id = @user
1506 } else /* argv[1] == "NONE" */ {
1507 ## repeat replace users (#potype = "NONE") where users.users_id = @user
1510 set_pobox_modtime(q, argv, cl);
1511 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1512 ## where tblstats.#table = "users"
1513 return(SMS_SUCCESS);
1517 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1518 * each list. This is tricky: first build a queue of all requested
1519 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1522 get_list_info(q, aargv, cl, action, actarg)
1523 register struct query *q;
1526 register int (*action)();
1529 char *argv[13], *malloc(), *realloc();
1530 ## char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1531 ## char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1532 ## char modby[9], modwith[9];
1533 ## int id, rowcount, acl_id, hid, modby_id;
1535 struct save_queue *sq, *sq_create();
1537 returned = rowcount = 0;
1541 ## range of l is list
1542 ## repeat retrieve (id = l.list_id) where l.#name = @name {
1543 sq_save_data(sq, id);
1547 return(SMS_NO_MATCH);
1549 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1550 argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1551 argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1554 while (sq_get_data(sq, &id)) {
1558 ## repeat retrieve (listname = l.#name, active = text(l.#active),
1559 ## public = text(l.#public), hidden = text(l.#hidden),
1560 ## hid = l.#hidden, maillist = text(l.#maillist),
1561 ## group = text(l.#group), gid = text(l.#gid),
1562 ## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1563 ## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1564 ## modwith =l.#modwith)
1565 ## where l.list_id = @id
1567 if (atoi(gid) == -1)
1568 argv[6] = UNIQUE_GID;
1570 if (!strcmp(acl_type, "LIST")) {
1571 ## repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1572 ## inquire_equel(rowcount = "rowcount")
1574 strcpy(acl_name, "???");
1575 } else if (!strcmp(acl_type, "USER")) {
1576 ## repeat retrieve (acl_name = users.#login)
1577 ## where users.users_id = @acl_id
1578 ## inquire_equel(rowcount = "rowcount")
1580 strcpy(acl_name, "???");
1581 } else if (!strcmp(acl_type, "NONE")) {
1582 strcpy(acl_name, "NONE");
1584 strcpy(acl_name, "???");
1586 ## repeat retrieve (modby = users.login) where users.users_id = @modby_id
1587 ## inquire_equel(rowcount = "rowcount")
1589 sprintf(modby, "#%d", id);
1591 sms_trim_args(q->vcnt, argv);
1593 (*action)(q->vcnt, argv, actarg);
1597 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1598 ## where tblstats.#table = "list"
1600 return (SMS_SUCCESS);
1604 /* get_ace_use - given a type and a name, return a type and a name.
1605 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1606 * and argv[1] will contain the ID of the entity in question. The R*
1607 * types mean to recursively look at every containing list, not just
1608 * when the object in question is a direct member. On return, the
1609 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1612 int get_ace_use(q, argv, cl, action, actarg)
1621 ## int aid, listid, id;
1622 struct save_queue *sq, *sq_create();
1625 aid = *(int *)argv[1];
1626 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER")) {
1627 return(get_ace_internal(atype, aid, action, actarg));
1631 if (!strcmp(atype, "RLIST")) {
1632 sq_save_data(sq, aid);
1633 /* get all the list_id's of containing lists */
1634 ## range of m is members
1635 while (sq_get_data(sq, &id)) {
1636 ## repeat retrieve (listid = m.list_id)
1637 ## where m.member_type = "LIST" and m.member_id = @id {
1638 sq_save_unique_data(sq, listid);
1641 /* now process each one */
1642 while (sq_get_data(sq, &id)) {
1643 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1648 if (!strcmp(atype, "RUSER")) {
1649 ## range of m is members
1650 ## repeat retrieve (listid = m.list_id)
1651 ## where m.member_type = "USER" and m.member_id = @aid {
1652 sq_save_data(sq, listid);
1654 /* get all the list_id's of containing lists */
1655 while (sq_get_data(sq, &id)) {
1656 ## repeat retrieve (listid = m.list_id)
1657 ## where m.member_type = "LIST" and m.member_id = @id {
1658 sq_save_unique_data(sq, listid);
1661 /* now process each one */
1662 while (sq_get_data(sq, &id)) {
1663 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1666 if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1671 if (!found) return(SMS_NO_MATCH);
1672 return(SMS_SUCCESS);
1676 /* This looks up a single list or user for ace use. atype must be "USER"
1677 * or "LIST", and aid is the ID of the corresponding object. This is used
1678 * by get_ace_use above.
1681 ##get_ace_internal(atype, aid, action, actarg)
1692 if (!strcmp(atype, "LIST")) {
1693 rargv[0] = "FILESYS";
1694 ## repeat retrieve (name = filesys.label)
1695 ## where filesys.owners = @aid {
1696 (*action)(2, rargv, actarg);
1701 ## repeat retrieve (name = capacls.capability)
1702 ## where capacls.list_id = @aid {
1703 (*action)(2, rargv, actarg);
1706 } else if (!strcmp(atype, "USER")) {
1707 rargv[0] = "FILESYS";
1708 ## repeat retrieve (name = filesys.label)
1709 ## where filesys.owner = @aid {
1710 (*action)(2, rargv, actarg);
1716 ## repeat retrieve (name = list.#name)
1717 ## where list.acl_type = @atype and list.acl_id = @aid {
1718 (*action)(2, rargv, actarg);
1722 rargv[0] = "SERVICE";
1723 ## repeat retrieve (name = servers.#name)
1724 ## where servers.acl_type = @atype and servers.acl_id = @aid {
1725 (*action)(2, rargv, actarg);
1729 rargv[0] = "HOSTACCESS";
1730 ## repeat retrieve (name = machine.#name)
1731 ## where machine.mach_id = hostaccess.mach_id and
1732 ## hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1733 (*action)(2, rargv, actarg);
1736 rargv[0] = "ZEPHYR";
1737 ## repeat retrieve (name = zephyr.class)
1738 ## where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
1739 ## zephyr.sub_type = @atype and zephyr.sub_id = @aid or
1740 ## zephyr.iws_type = @atype and zephyr.iws_id = @aid or
1741 ## zephyr.iui_type = @atype and zephyr.iui_id = @aid {
1742 (*action)(2, rargv, actarg);
1746 if (!found) return(SMS_NO_MATCH);
1747 return(SMS_SUCCESS);
1751 /* get_lists_of_member - given a type and a name, return the name and flags
1752 * of all of the lists of the given member. The member_type is one of
1753 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1754 * and argv[1] will contain the ID of the entity in question. The R*
1755 * types mean to recursively look at every containing list, not just
1756 * when the object in question is a direct member.
1759 int get_lists_of_member(q, argv, cl, action, actarg)
1768 ## int aid, listid, id;
1769 struct save_queue *sq, *sq_create();
1772 aid = *(int *)argv[1];
1773 if (!strcmp(atype, "LIST") ||
1774 !strcmp(atype, "USER") ||
1775 !strcmp(atype, "STRING")) {
1776 return(glom_internal(atype, aid, action, actarg));
1780 if (!strcmp(atype, "RLIST")) {
1781 sq_save_data(sq, aid);
1782 /* get all the list_id's of containing lists */
1783 ## range of m is members
1784 while (sq_get_data(sq, &id)) {
1785 ## repeat retrieve (listid = m.list_id)
1786 ## where m.member_type = "LIST" and m.member_id = @id {
1787 sq_save_unique_data(sq, listid);
1790 /* now process each one */
1791 while (sq_get_data(sq, &id)) {
1792 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1797 if (!strcmp(atype, "RUSER")) {
1798 ## range of m is members
1799 ## repeat retrieve (listid = m.list_id)
1800 ## where m.member_type = "USER" and m.member_id = @aid {
1801 sq_save_data(sq, listid);
1803 /* get all the list_id's of containing lists */
1804 while (sq_get_data(sq, &id)) {
1805 ## repeat retrieve (listid = m.list_id)
1806 ## where m.member_type = "LIST" and m.member_id = @id {
1807 sq_save_unique_data(sq, listid);
1810 /* now process each one */
1811 while (sq_get_data(sq, &id)) {
1812 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1815 if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1819 if (!strcmp(atype, "RSTRING")) {
1820 ## range of m is members
1821 ## repeat retrieve (listid = m.list_id)
1822 ## where m.member_type = "STRING" and m.member_id = @aid {
1823 sq_save_data(sq, listid);
1825 /* get all the list_id's of containing lists */
1826 while (sq_get_data(sq, &id)) {
1827 ## repeat retrieve (listid = m.list_id)
1828 ## where m.member_type = "LIST" and m.member_id = @id {
1829 sq_save_unique_data(sq, listid);
1832 /* now process each one */
1833 while (sq_get_data(sq, &id)) {
1834 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1837 if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
1841 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1842 ## where tblstats.#table = "members"
1844 if (!found) return(SMS_NO_MATCH);
1845 return(SMS_SUCCESS);
1849 /* This looks up a single list, user, or string as a member. atype must be
1850 * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
1851 * This is used by get_lists_of_members above.
1854 ##glom_internal(atype, aid, action, actarg)
1862 ## char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
1868 rargv[4] = maillist;
1870 ## repeat retrieve (name = list.#name, active = text(list.#active),
1871 ## public = text(list.#public), hidden = text(list.#hidden),
1872 ## maillist = text(list.#maillist), group = text(list.#group))
1873 ## where list.list_id = m.list_id and
1874 ## m.member_type = @atype and m.member_id = @aid {
1875 (*action)(6, rargv, actarg);
1879 if (!found) return(SMS_NO_MATCH);
1880 return(SMS_SUCCESS);
1884 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1885 * the five flags associated with each list. It will return the name of
1886 * each list that meets the quailifications. It does this by building a
1887 * where clause based on the arguments, then doing a retrieve.
1890 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
1892 int qualified_get_lists(q, argv, cl, action, actarg)
1899 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
1900 "l", "name", lflags));
1904 /** get_members_of_list - optimized query for retrieval of list members
1907 ** argv[0] - list_id
1910 ** - retrieve USER members, then LIST members, then STRING members
1913 get_members_of_list(q, argv, cl, action, actarg)
1921 ## char member_name[129];
1924 list_id = *(int *)argv[0];
1926 targv[1] = member_name;
1928 ## range of m is members
1929 ## repeat retrieve (member_name = users.login)
1930 ## where m.#list_id = @list_id and m.member_type = "USER"
1931 ## and m.member_id = users.users_id
1932 ## sort by #member_name
1934 (*action)(2, targv, actarg);
1938 ## repeat retrieve (member_name = list.name)
1939 ## where m.#list_id = @list_id and m.member_type = "LIST"
1940 ## and m.member_id = list.#list_id
1941 ## sort by #member_name
1943 (*action)(2, targv, actarg);
1946 targv[0] = "STRING";
1947 ## repeat retrieve (member_name = strings.string)
1948 ## where m.#list_id = @list_id and m.member_type = "STRING"
1949 ## and m.member_id = strings.string_id
1950 ## sort by #member_name
1952 (*action)(2, targv, actarg);
1955 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1956 ## where tblstats.#table = "members"
1957 return(SMS_SUCCESS);
1961 /* count_members_of_list: this is a simple query, but it cannot be done
1962 * through the dispatch table.
1965 int count_members_of_list(q, argv, cl, action, actarg)
1972 ## int list, ct = 0;
1973 char *rargv[1], countbuf[5];
1975 list = *(int *)argv[0];
1976 rargv[0] = countbuf;
1977 ## repeat retrieve (ct = count(members.list_id where members.list_id = @list))
1978 sprintf(countbuf, "%d", ct);
1979 (*action)(1, rargv, actarg);
1980 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1981 ## where tblstats.#table = "members"
1982 return(SMS_SUCCESS);
1986 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
1987 * the three flags associated with each service. It will return the name of
1988 * each service that meets the quailifications. It does this by building a
1989 * where clause based on the arguments, then doing a retrieve.
1992 static char *sflags[3] = { "enable", "inprogress", "harderror" };
1994 int qualified_get_server(q, argv, cl, action, actarg)
2001 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2002 "s", "name", sflags));
2006 /* generic qualified get routine, used by qualified_get_lists,
2007 * qualified_get_server, and qualified_get_serverhost.
2009 * start - a simple where clause, must not be empty
2010 * range - the name of the range variable
2011 * field - the field to return
2012 * flags - an array of strings, names of the flag variables
2015 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2025 ## char name[33], qual[256], *rvar, *rtbl, *rfield;
2026 char *rargv[1], buf[32];
2029 strcpy(qual, start);
2030 for (i = 0; i < q->argc; i++) {
2031 if (!strcmp(argv[i], "TRUE")) {
2032 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2033 (void) strcat(qual, buf);
2034 } else if (!strcmp(argv[i], "FALSE")) {
2035 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2036 (void) strcat(qual, buf);
2044 ## range of rvar is rtbl
2045 ## retrieve (name = rvar.rfield) where qual {
2046 (*action)(1, rargv, actarg);
2048 ## inquire_equel(rowcount = "rowcount")
2049 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2050 ## where tblstats.#table = @rtbl
2052 return(SMS_NO_MATCH);
2053 return(SMS_SUCCESS);
2057 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2058 * the five flags associated with each serverhost. It will return the name of
2059 * each service and host that meets the quailifications. It does this by
2060 * building a where clause based on the arguments, then doing a retrieve.
2063 static char *shflags[6] = { "service", "enable", "override", "success",
2064 "inprogress", "hosterror" };
2066 int qualified_get_serverhost(q, argv, cl, action, actarg)
2073 ## char sname[33], mname[33], qual[256];
2074 char *rargv[2], buf[32];
2077 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2079 for (i = 1; i < q->argc; i++) {
2080 if (!strcmp(argv[i], "TRUE")) {
2081 sprintf(buf, " and sh.%s != 0", shflags[i]);
2083 } else if (!strcmp(argv[i], "FALSE")) {
2084 sprintf(buf, " and sh.%s = 0", shflags[i]);
2091 ## range of sh is serverhosts
2092 ## retrieve (sname = sh.service, mname = machine.name) where qual {
2093 (*action)(2, rargv, actarg);
2095 ## inquire_equel(rowcount = "rowcount")
2096 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2097 ## where tblstats.#table = "serverhosts"
2099 return(SMS_NO_MATCH);
2100 return(SMS_SUCCESS);
2104 /* register_user - change user's login name and allocate a pobox, group,
2105 * filesystem, and quota for them. The user's status must start out as 0,
2106 * and is left as 2. Arguments are: user's UID, new login name, and user's
2107 * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY,
2108 * SMS_FS_STAFF, SMS_FS_MISC).
2111 register_user(q, argv, cl)
2116 ## char *login, dir[65], *entity, *directory, machname[33];
2117 ## int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2118 ## int size, alloc, pid, m_id;
2121 entity = cl->entity;
2124 uid = atoi(argv[0]);
2126 utype = atoi(argv[2]);
2128 ## range of u is users
2129 ## range of l is list
2130 ## range of sh is serverhosts
2131 ## range of n is nfsphys
2132 ## range of m is machine
2135 ## repeat retrieve (users_id = u.#users_id)
2136 ## where u.#uid = @uid and u.status = 0
2137 ## inquire_equel(rowcount = "rowcount");
2139 return(SMS_NO_MATCH);
2141 return(SMS_NOT_UNIQUE);
2143 /* check new login name */
2144 ## repeat retrieve (flag = any(u.#login where u.#login = @login))
2147 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2150 ## repeat retrieve (flag = any(filesys.#name where filesys.#name = @login))
2153 com_err(whoami, 0, "new login name OK");
2155 /* choose place for pobox, put in mid */
2156 ## repeat retrieve (mid = sh.mach_id, machname = m.name)
2157 ## where sh.service = "POP" and m.mach_id = sh.mach_id and
2158 ## sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2159 ## inquire_equel(rowcount = "rowcount");
2161 return(SMS_NO_POBOX);
2163 /* change login name, set pobox */
2164 ## repeat replace u (#login = @login, status = 2, modtime = "now",
2165 ## modby = @who, modwith = @entity, potype="POP",
2166 ## pop_id = @mid, pmodtime="now", pmodby=@who,
2167 ## pmodwith=@entity)
2168 ## where u.#users_id = @users_id
2169 ## inquire_equel(rowcount = "rowcount");
2171 return(SMS_INTERNAL);
2172 set_pop_usage(mid, 1);
2173 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2176 /* create group list */
2177 if (set_next_object_id("gid", "list"))
2179 if (set_next_object_id("list_id", "list"))
2181 ## repeat retrieve (list_id = values.value) where values.name = "list_id"
2182 ## inquire_equel(rowcount = "rowcount");
2184 return(SMS_INTERNAL);
2185 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2186 ## public = 0, hidden = 0, maillist = 0, group = 1,
2187 ## #gid = values.value, desc = "User Group",
2188 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2189 ## modby = @who, modwith = @entity)
2190 ## where values.name = "gid"
2191 ## inquire_equel(rowcount = "rowcount");
2193 return(SMS_INTERNAL);
2194 ## repeat append members (#list_id = @list_id, member_type = "USER",
2195 ## member_id = @users_id)
2196 ## inquire_equel(rowcount = "rowcount");
2198 return(SMS_INTERNAL);
2199 com_err(whoami, 0, "group list created");
2201 /* decide where to put filesystem */
2204 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2205 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2206 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2207 maxsize = size - alloc;
2210 directory = strsave(dir);
2216 return(SMS_NO_FILESYS);
2218 /* create filesystem */
2219 if (set_next_object_id("filsys_id", "filesys"))
2221 ## repeat append filesys (filsys_id = values.value, phys_id = @pid,
2222 ## label = @login, type = "NFS", mach_id = @m_id,
2223 ## name = @directory + "/" + @login,
2224 ## mount = "/mit/" + @login,
2225 ## access = "w", comments = "User Locker",
2226 ## owner = @users_id, owners = @list_id, createflg = 1,
2227 ## lockertype = "HOMEDIR", modtime = "now",
2228 ## modby = @who, modwith = @entity)
2229 ## where values.name = "filsys_id"
2230 ## inquire_equel(rowcount = "rowcount");
2232 return(SMS_INTERNAL);
2233 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2237 ## repeat retrieve (quota = values.value) where values.name = "def_quota"
2238 ## inquire_equel(rowcount = "rowcount");
2240 return(SMS_NO_QUOTA);
2241 ## repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2242 ## #quota = @quota, modtime = "now", modby = @who,
2243 ## modwith = @entity)
2244 ## where values.name = "filsys_id"
2245 ## inquire_equel(rowcount = "rowcount");
2247 return(SMS_INTERNAL);
2248 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2249 ## where nfsphys.nfsphys_id = filesys.#phys_id and
2250 ## filesys.filsys_id = values.value and values.name = "filsys_id"
2251 ## inquire_equel(rowcount = "rowcount");
2253 return(SMS_INTERNAL);
2254 com_err(whoami, 0, "quota of %d assigned", quota);
2256 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2257 ## where tblstats.table = "users"
2258 ## repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2259 ## where tblstats.table = "list" or tblstats.table = "filesys" or
2260 ## tblstats.table = "nfsquota"
2261 return(SMS_SUCCESS);
2266 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2270 ** delta (will be +/- 1)
2273 ** - incr/decr value field in serverhosts table for pop/mach_id
2277 static int set_pop_usage(id, count)
2281 ## int mach_id = id;
2284 ## range of sh is serverhosts
2285 ## repeat replace sh (value1 = sh.value1 + @n)
2286 ## where sh.service = "POP" and sh.#mach_id = @mach_id
2288 return(SMS_SUCCESS);
2293 /* Validation Routines */
2295 validate_row(q, argv, v)
2296 register struct query *q;
2298 register struct validate *v;
2306 /* build where clause */
2307 build_qual(v->qual, v->argc, argv, qual);
2309 /* setup ingres variables */
2314 if (log_flags & LOG_RES)
2315 /* tell the logfile what we're doing */
2316 com_err(whoami, 0, "validating row: %s", qual);
2318 /* look for the record */
2319 ## range of rvar is table
2320 ## retrieve (rowcount = count(rvar.name where qual))
2321 if (rowcount == 0) return(SMS_NO_MATCH);
2322 if (rowcount > 1) return(SMS_NOT_UNIQUE);
2326 validate_fields(q, argv, vo, n)
2328 register char *argv[];
2329 register struct valobj *vo;
2332 register int status;
2337 if (log_flags & LOG_RES)
2338 com_err(whoami, 0, "validating %s in %s: %s",
2339 vo->namefield, vo->table, argv[vo->index]);
2340 status = validate_name(argv, vo);
2344 if (log_flags & LOG_RES)
2345 com_err(whoami, 0, "validating %s in %s: %s",
2346 vo->idfield, vo->table, argv[vo->index]);
2347 status = validate_id(argv, vo);
2351 if (log_flags & LOG_RES)
2352 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2353 status = validate_date(argv, vo);
2357 if (log_flags & LOG_RES)
2358 com_err(whoami, 0, "validating %s type: %s",
2359 vo->table, argv[vo->index]);
2360 status = validate_type(argv, vo);
2364 if (log_flags & LOG_RES)
2365 com_err(whoami, 0, "validating typed data (%s): %s",
2366 argv[vo->index - 1], argv[vo->index]);
2367 status = validate_typedata(q, argv, vo);
2371 if (log_flags & LOG_RES)
2372 com_err(whoami, 0, "validating rename %s in %s",
2373 argv[vo->index], vo->table);
2374 status = validate_rename(argv, vo);
2378 if (log_flags & LOG_RES)
2379 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2380 status = validate_chars(argv[vo->index]);
2384 status = SMS_EXISTS;
2389 if (status != SMS_EXISTS) return(status);
2393 return(SMS_SUCCESS);
2397 /* validate_chars: verify that there are no illegal characters in
2398 * the string. Legal characters are printing chars other than
2401 static int illegalchars[] = {
2402 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2403 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2404 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2405 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2406 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2407 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, /* P - _ */
2408 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2409 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2410 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2411 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2412 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2413 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2414 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2415 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2416 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2417 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2424 if (illegalchars[*s++])
2425 return(SMS_BAD_CHAR);
2430 validate_id(argv, vo)
2432 register struct valobj *vo;
2442 name = argv[vo->index];
2444 /* minor kludge to upcasify machine names */
2445 if (!strcmp(table, "machine"))
2446 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2447 namefield = vo->namefield;
2448 idfield = vo->idfield;
2449 if (!strcmp(namefield, "uid")) {
2450 ## retrieve (id = table.idfield) where table.namefield = int4(name)
2451 ## inquire_equel (rowcount = "rowcount")
2453 ## retrieve (id = table.idfield) where table.namefield = name
2454 ## inquire_equel (rowcount = "rowcount")
2456 if (rowcount != 1) return(vo->error);
2457 *(int *)argv[vo->index] = id;
2461 validate_name(argv, vo)
2463 register struct valobj *vo;
2471 name = argv[vo->index];
2473 namefield = vo->namefield;
2474 if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2475 for (c = name; *c; c++)
2479 ## retrieve (rowcount = countu(table.namefield
2480 ## where table.namefield = name))
2481 return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2484 validate_date(argv, vo)
2492 idate = argv[vo->index];
2494 ## retrieve (dd = interval("years", date(idate) - date("today")))
2495 ## inquire_equel (errorno = "errorno")
2496 if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2501 validate_rename(argv, vo)
2505 ## char *name, *table, *namefield, *idfield;
2509 c = name = argv[vo->index];
2511 if (illegalchars[*c++])
2512 return(SMS_BAD_CHAR);
2514 /* minor kludge to upcasify machine names */
2515 if (!strcmp(table, "machine"))
2516 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2517 namefield = vo->namefield;
2518 idfield = vo->idfield;
2521 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2523 ## retrieve (id = any(table.namefield where table.namefield = name))
2529 ## retrieve (id = table.idfield) where table.namefield = name
2530 if (id == -1 || id == *(int *)argv[vo->index - 1])
2537 validate_type(argv, vo)
2539 register struct valobj *vo;
2546 typename = vo->table;
2547 c = value = argv[vo->index];
2549 if (illegalchars[*c++])
2550 return(SMS_BAD_CHAR);
2552 /* uppercase type fields */
2553 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2555 ## range of a is alias
2556 ## repeat retrieve (exists = any(a.trans where a.name = @typename and
2557 ## a.type = "TYPE" and
2558 ## a.trans = @value))
2559 return (exists ? SMS_EXISTS : vo->error);
2562 /* validate member or type-specific data field */
2564 validate_typedata(q, argv, vo)
2565 register struct query *q;
2566 register char *argv[];
2567 register struct valobj *vo;
2570 ## char *field_type;
2571 ## char data_type[129];
2577 /* get named object */
2578 name = argv[vo->index];
2580 /* get field type string (known to be at index-1) */
2581 field_type = argv[vo->index-1];
2583 /* get corresponding data type associated with field type name */
2584 ## repeat retrieve (data_type = alias.trans)
2585 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
2586 ## inquire_equel (rowcount = "rowcount")
2587 if (rowcount != 1) return(SMS_TYPE);
2589 /* now retrieve the record id corresponding to the named object */
2590 if (index(data_type, ' '))
2591 *index(data_type, ' ') = 0;
2592 if (!strcmp(data_type, "user")) {
2594 ## repeat retrieve (id = users.users_id) where users.login = @name
2595 ## inquire_equel (rowcount = "rowcount")
2596 if (rowcount != 1) return(SMS_USER);
2598 } else if (!strcmp(data_type, "list")) {
2600 ## repeat retrieve (id = list.list_id) where list.#name = @name
2601 ## inquire_equel (rowcount = "rowcount")
2602 if (rowcount != 1) {
2603 /* if idfield is non-zero, then if argv[0] matches the string
2604 * that we're trying to resolve, we should get the value of
2605 * values.[idfield] for the id.
2607 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2608 set_next_object_id(q->validate->object_id, q->rtable);
2610 ## repeat retrieve (id = values.value) where values.#name = @name
2611 ## inquire_equel(rowcount = "rowcount")
2612 if (rowcount != 1) return(SMS_LIST);
2616 } else if (!strcmp(data_type, "machine")) {
2618 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2619 ## repeat retrieve (id = machine.mach_id) where machine.#name = @name
2620 ## inquire_equel (rowcount = "rowcount")
2621 if (rowcount != 1) return(SMS_MACHINE);
2623 } else if (!strcmp(data_type, "string")) {
2625 ## range of s is strings
2626 ## repeat retrieve (id = s.string_id) where s.string = @name
2627 ## inquire_equel (rowcount = "rowcount")
2628 if (rowcount == 0) {
2629 if (q->type != APPEND) return(SMS_STRING);
2630 ## range of v is values
2631 ## retrieve (id = v.value) where v.#name = "strings_id"
2633 ## replace v (value = id) where v.#name = "strings_id"
2634 ## append to strings (string_id = id, string = name)
2636 } else if (!strcmp(data_type, "none")) {
2642 /* now set value in argv */
2643 *(int *)argv[vo->index] = id;
2645 return (SMS_EXISTS);
2649 /* This looks up a login name and returns the SMS internal ID. It is used
2650 * by authenticate to put the users_id in the client structure.
2653 int get_users_id(name)
2656 ## int id, rowcount;
2661 ## range of u is users
2662 ## repeat retrieve (id = u.#users_id) where u.#login = @login
2663 ## inquire_equel (rowcount = "rowcount")
2672 /* Check the database at startup time. For now this just resets the
2673 * inprogress flags that the DCM uses.
2676 sanity_check_database()
2678 ## replace servers (inprogress = 0)
2679 ## replace serverhosts (inprogress = 0)