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];
349 /* For now, only allow users to be deleted if their status is 0 */
350 ## repeat retrieve (flag = u.status) where u.users_id = @id
354 ## repeat delete nfsquota where nfsquota.users_id = @id
355 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
356 ## and members.member_type = "USER"))
359 ## repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
362 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
363 ## list.acl_type = "USER"))
366 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
367 ## servers.acl_type = "USER"))
370 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
371 ## hostaccess.acl_type = "USER"))
379 /* setup_spop: verify that there is already a valid POP machine_id in the
380 * pop_id field. Also take care of keeping track of the post office usage.
382 int setup_spop(q, argv)
389 id = *(int *)argv[0];
390 ## repeat retrieve (type = u.potype, flag = any(machine.name
391 ## where machine.mach_id = u.pop_id
393 ## and u.users_id = @id))
394 ## where u.users_id = @id
397 if (strcmp(type, "POP"))
398 set_pop_usage(id, 1);
403 /* setup_dpob: Take care of keeping track of the post office usage.
405 int setup_dpob(q, argv)
412 user = *(int *)argv[0];
413 ## repeat retrieve (type = u.potype, id = u.pop_id)
414 ## where u.users_id = @user
416 if (strcmp(type, "POP"))
417 set_pop_usage(id, -1);
422 /* setup_dmac - verify that the machine is no longer being referenced
423 * and may safely be deleted.
426 int setup_dmac(q, argv)
432 id = *(int *)argv[0];
433 ## repeat retrieve (flag = any(users.login where users.potype = "POP"
434 ## and users.pop_id=@id))
437 ## repeat retrieve (flag = any(serverhosts.mach_id
438 ## where serverhosts.mach_id=@id))
441 ## repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
444 ## repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
447 ## repeat retrieve (flag = any(pcap.mach_id where pcap.mach_id=@id))
451 ## repeat delete mcmap where mcmap.mach_id = @id
456 /* setup_dclu - verify that the cluster is no longer being referenced
457 * and may safely be deleted.
460 int setup_dclu(q, argv)
466 id = *(int *)argv[0];
467 ## repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
470 ## repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
478 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
479 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
480 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
481 * a -1 there. Remember that this is also used for ulis, with the indexes
485 int setup_alis(q, argv)
493 if (!strcmp(q->shortname, "alis"))
495 else if (!strcmp(q->shortname, "ulis"))
498 if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
499 if (atoi(argv[idx - 1])) {
500 if (set_next_object_id("gid", "list"))
501 return(SMS_INGRES_ERR);
502 ## repeat retrieve (ngid = values.value) where values.name = "gid"
503 sprintf(argv[idx], "%d", ngid);
505 strcpy(argv[idx], "-1");
513 /* setup_dlist - verify that the list is no longer being referenced
514 * and may safely be deleted.
517 int setup_dlis(q, argv)
523 id = *(int *)argv[0];
524 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
525 ## and members.member_type = "LIST"))
528 ## repeat retrieve (flag = any(members.member_id where members.list_id=@id))
531 ## repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
534 ## repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
537 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
538 ## list.acl_type = "LIST" and list.list_id != @id))
541 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
542 ## servers.acl_type = "LIST"))
545 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
546 ## hostaccess.acl_type = "LIST"))
549 ## repeat retrieve (flag = any(zephyr.class
550 ## where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
551 ## zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
552 ## zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
553 ## zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
561 /* setup_dsin - verify that the service is no longer being referenced
562 * and may safely be deleted.
565 int setup_dsin(q, argv)
573 ## repeat retrieve (flag = any(serverhosts.service
574 ## where serverhosts.service=uppercase(@name)))
577 ## repeat retrieve (flag = servers.inprogress) where servers.#name = @name
585 /* setup_dshi - verify that the service-host is no longer being referenced
586 * and may safely be deleted.
589 int setup_dshi(q, argv)
597 id = *(int *)argv[1];
598 ## repeat retrieve (flag=serverhosts.inprogress)
599 ## where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
608 ** setup_add_filesys - verify existance of referenced file systems
620 ** * extract directory prefix from name
621 ** * verify mach_id/dir in nfsphys
622 ** * verify access in {r, w, R, W}
624 ** Side effect: sets variable var_phys_id to the ID of the physical
625 ** filesystem (nfsphys_id for NFS, 0 for RVD)
628 ** SMS_NFS - specified directory not exported
629 ** SMS_FILESYS_ACCESS - invalid filesys access
633 ##static int var_phys_id;
645 mach_id = *(int *)argv[2];
650 if (!strcmp(type, "NFS"))
651 return (check_nfs(mach_id, name, access));
667 mach_id = *(int *)argv[3];
672 if (!strcmp(type, "NFS"))
673 return (check_nfs(mach_id, name, access));
679 /* Find the NFS physical partition that the named directory is on.
680 * This is done by comparing the dir against the mount point of the
681 * partition. To make sure we get the correct match when there is
682 * more than one, we sort the query in reverse order by dir name.
685 ##check_nfs(mach_id, name, access)
696 caccess = (isupper(*access)) ? tolower(*access) : *access;
697 if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
700 ## range of np is nfsphys
701 ## repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
702 ## where np.#mach_id = @mach_id sort by #dir:d {
706 if (*cp1++ != *cp2) break;
710 status = SMS_SUCCESS;
719 /* setup_dfil: free any quota records associated with a filesystem
720 * when it is deleted.
723 setup_dfil(q, argv, cl)
730 id = *(int *)argv[0];
731 ## range of q is nfsquota
732 ## range of fs is filesys
733 ## range of n is nfsphys
734 ## repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
735 ## where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
737 ## repeat delete q where q.filsys_id = @id
742 /* setup_dnfp: check to see that the nfs physical partition does not have
743 * any filesystems assigned to it before allowing it to be deleted.
746 setup_dnfp(q, argv, cl)
753 id = *(int *)argv[0];
754 ## repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
761 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
762 * argv[0] = filsys_id
766 setup_dnfq(q, argv, cl)
771 ## int quota, fs, user;
773 fs = *(int *)argv[0];
774 user = *(int *)argv[1];
776 ## range of q is nfsquota
777 ## repeat retrieve (quota = q.#quota) where q.users_id = @user and
779 ## repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
780 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
786 /* FOLLOWUP ROUTINES */
788 /* generic set_modtime routine. This takes the table name from the query,
789 * and will update the modtime, modby, and modwho fields in the entry in
790 * the table whose name field matches argv[0].
793 set_modtime(q, argv, cl)
798 ## char *name, *entity, *table;
806 ## replace table (modtime = "now", modby = who, modwith = entity)
807 ## where table.#name = name
811 /* generic set_modtime_by_id routine. This takes the table name from
812 * the query, and the id name from the validate record,
813 * and will update the modtime, modby, and modwho fields in the entry in
814 * the table whose id matches argv[0].
817 set_modtime_by_id(q, argv, cl)
822 ## char *entity, *table, *id_name;
828 id_name = q->validate->object_id;
830 id = *(int *)argv[0];
831 ## replace table (modtime = "now", modby = who, modwith = entity)
832 ## where table.id_name = id
837 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
840 set_finger_modtime(q, argv, cl)
845 ## int users_id, who;
850 users_id = *(int *)argv[0];
852 ## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
853 ## where u.#users_id = @users_id
858 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
861 set_pobox_modtime(q, argv, cl)
866 ## int users_id, who;
871 users_id = *(int *)argv[0];
873 ## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
874 ## where users.#users_id = @users_id
879 /* Sets the modtime on a machine record. The machine name is in argv[0].
880 * This routine is different from the generic set_modtime in that the
881 * name is uppercased first.
884 set_mach_modtime(q, argv, cl)
889 ## char *host, *entity;
896 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
897 ## where m.name = uppercase(@host)
902 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
903 * is necessary for add_machine_to_cluster becuase the table that query
904 * operates on is "mcm", not "machine".
907 set_mach_modtime_by_id(q, argv, cl)
918 id = *(int *)argv[0];
919 ## range of m is machine
920 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
921 ## where m.mach_id = @id
926 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
927 * is necessary for add_cluster_data and delete_cluster_data becuase the
928 * table that query operates on is "svc", not "cluster".
931 set_cluster_modtime_by_id(q, argv, cl)
942 id = *(int *)argv[0];
943 ## range of c is cluster
944 ## repeat replace c (modtime = "now", modby = @who, modwith = @entity)
945 ## where c.clu_id = @id
950 /* sets the modtime on the serverhost where the service name is in argv[0]
951 * and the mach_id is in argv[1].
954 set_serverhost_modtime(q, argv, cl)
959 ## char *entity, *serv;
966 id = *(int *)argv[1];
967 ## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
968 ## where sh.service = uppercase(@serv) and sh.mach_id = @id
973 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
974 * directory name is in argv[1].
977 set_nfsphys_modtime(q, argv, cl)
982 ## char *entity, *dir;
988 id = *(int *)argv[0];
990 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
991 ## where np.#dir = @dir and np.mach_id = @id
996 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1000 set_filesys_modtime(q, argv, cl)
1005 ## char *label, *entity;
1008 entity = cl->entity;
1012 if (!strcmp(q->shortname, "ufil"))
1015 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1016 ## #phys_id = @var_phys_id) where fs.#label = @label
1017 return(SMS_SUCCESS);
1021 /* sets the modtime on a zephyr class, where argv[0] contains the class
1025 set_zephyr_modtime(q, argv, cl)
1030 ## char *class, *entity;
1033 entity = cl->entity;
1038 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1039 ## where z.#class = @class
1040 return(SMS_SUCCESS);
1044 /* fixes the modby field. This will be the second to last thing in the
1045 * argv, the argv length is determined from the query structure. It is
1046 * passed as a pointer to an integer. This will either turn it into a
1047 * username, or # + the users_id.
1049 followup_fix_modby(q, sq, v, action, actarg, cl)
1051 register struct save_queue *sq;
1053 register int (*action)();
1054 register int actarg;
1058 char **argv, *malloc();
1059 ## int id, rowcount;
1063 while (sq_get_data(sq, &argv)) {
1066 argv[i] = malloc(9);
1068 ## repeat retrieve (name = users.login) where users.users_id = @id
1069 ## inquire_equel(rowcount = "rowcount")
1070 if (rowcount != 1) {
1071 sprintf(argv[i], "#%d", id);
1073 (*action)(q->vcnt, argv, actarg);
1074 for (j = 0; j < q->vcnt; j++)
1079 return(SMS_SUCCESS);
1084 ** followup_ausr - add finger and pobox entries, set_user_modtime
1087 ** argv[0] - login (add_user)
1088 ** argv[3] - last name
1089 ** argv[4] - first name
1090 ** argv[5] - middle name
1094 followup_ausr(q, argv, cl)
1100 ## char *login, *entity;
1101 ## char fullname[129];
1105 entity = cl->entity;
1107 /* build fullname */
1108 if (strlen(argv[4]) && strlen(argv[5]))
1109 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1110 else if (strlen(argv[4]))
1111 sprintf(fullname, "%s %s", argv[4], argv[3]);
1113 sprintf(fullname, "%s", argv[3]);
1115 /* create finger entry, pobox & set modtime on user */
1116 ## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1117 ## #fullname=@fullname, mit_affil = u.mit_year,
1118 ## fmodtime="now", fmodby=@who, fmodwith=@entity,
1119 ## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1120 ## where u.#login = @login
1122 return(SMS_SUCCESS);
1126 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1127 * type in argv[1]. Then completes the upcall to the user.
1129 * argv[2] is of the form "123:234" where the first integer is the machine
1130 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1131 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1135 followup_gpob(q, sq, v, action, actarg, cl)
1136 register struct query *q;
1137 register struct save_queue *sq;
1138 register struct validate *v;
1139 register int (*action)();
1143 char **argv, *index();
1145 ## char box[129], *name;
1146 ## int mid, sid, rowcount;
1149 while (sq_get_data(sq, &argv)) {
1150 sms_trim_args(2, argv);
1152 p = index(argv[2], ':');
1154 mid = atoi(argv[2]);
1158 if (!strcmp(ptype, "POP")) {
1159 ## repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1160 ## inquire_equel(rowcount = "rowcount")
1162 return(SMS_MACHINE);
1163 } else if (!strcmp(ptype, "SMTP")) {
1164 ## repeat retrieve (box=strings.string) where strings.string_id=@sid
1165 ## inquire_equel(rowcount = "rowcount")
1168 } else /* ptype == "NONE" */ {
1172 if (!strcmp(q->shortname, "gpob")) {
1173 sid = atoi(argv[4]);
1175 argv[4] = malloc(9);
1177 ## repeat retrieve (name = users.login) where users.users_id = @sid
1178 ## inquire_equel(rowcount = "rowcount")
1180 sprintf(name, "#%d", sid);
1184 (*action)(q->vcnt, argv, actarg);
1186 /* free saved data */
1193 return (SMS_SUCCESS);
1197 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1198 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1199 * proper name based on the type, and repace that string in the argv.
1200 * Also fixes the modby field by called followup_fix_modby.
1203 followup_glin(q, sq, v, action, actarg, cl)
1204 register struct query *q;
1205 register struct save_queue *sq;
1206 register struct validate *v;
1207 register int (*action)();
1211 char **argv, *malloc(), *realloc(), *type;
1213 ## int id, rowcount;
1217 if (!strcmp(q->shortname, "gsin"))
1220 while (sq_get_data(sq, &argv)) {
1221 sms_trim_args(q->vcnt, argv);
1223 id = atoi(argv[i = q->vcnt - 2]);
1225 name = argv[i] = malloc(9);
1226 ## repeat retrieve (name = users.login) where users.users_id = @id
1227 ## inquire_equel(rowcount = "rowcount")
1229 sprintf(argv[i], "#%d", id);
1231 id = atoi(argv[idx]);
1232 type = argv[idx - 1];
1233 if ((name = malloc(33)) == NULL)
1236 if (!strcmp(type, "LIST")) {
1237 ## repeat retrieve (name = list.#name) where list.list_id = @id
1238 ## inquire_equel(rowcount = "rowcount")
1240 strcpy(name, "???");
1241 } else if (!strcmp(type, "USER")) {
1242 ## repeat retrieve (name = users.login) where users.users_id = @id
1243 ## inquire_equel(rowcount = "rowcount")
1245 strcpy(name, "???");
1246 } else if (!strcmp(type, "NONE")) {
1247 strcpy(name, "NONE");
1249 strcpy(name, "???");
1253 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1254 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1255 strcpy(argv[6], UNIQUE_GID);
1259 (*action)(q->vcnt, argv, actarg);
1261 /* free saved data */
1262 for (i = 0; i < q->vcnt; i++)
1268 return (SMS_SUCCESS);
1272 /** followup_amtl - followup for amtl and dmfl; when adding a list
1273 ** member to a maillist, make member list a maillist also
1274 ** unless list is a user-group.
1275 ** Then set_list_modtime_by_id.
1278 ** argv[0] - list_id
1279 ** argv[1] - member_type
1280 ** argv[2] - member_id
1284 followup_amtl(q, argv, cl)
1294 list_id = *(int *)argv[0];
1295 entity = cl->entity;
1298 ## range of l is list
1299 ## repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1300 ## where l.#list_id = @list_id
1302 /* if query is not amtl or if member_type is not LIST then return */
1303 if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4))
1304 return(SMS_SUCCESS);
1306 member_id = *(int *)argv[2];
1308 /* is parent list a mailing list? */
1309 ## repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1311 return(SMS_SUCCESS);
1313 /* list is not a user-group; add list to maillist table */
1314 ## repeat replace l (maillist = 1) where l.#list_id = @member_id
1315 return(SMS_SUCCESS);
1319 /* followup_anfq: Add allocation to nfsphys after creating quota.
1320 * argv[0] = filsys_id
1321 * argv[2] = ascii(quota)
1324 followup_anfq(q, argv, cl)
1329 ## int quota, user, fs, who;
1332 fs = *(int *)argv[0];
1333 user = *(int *)argv[1];
1334 quota = atoi(argv[2]);
1336 entity = cl->entity;
1338 ## repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1339 ## where nq.filsys_id = @fs and nq.users_id = @user
1340 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1341 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1342 return(SMS_SUCCESS);
1349 followup_gzcl(q, sq, v, action, actarg, cl)
1350 register struct query *q;
1351 register struct save_queue *sq;
1352 register struct validate *v;
1353 register int (*action)();
1358 ## int rowcount, id;
1362 while (sq_get_data(sq, &argv)) {
1363 sms_trim_args(q->vcnt, argv);
1365 id = atoi(argv[i = q->vcnt - 2]);
1367 name = argv[i] = malloc(9);
1368 ## repeat retrieve (name = users.login) where users.users_id = @id
1369 ## inquire_equel(rowcount = "rowcount")
1371 sprintf(argv[i], "#%d", id);
1373 for (i = 1; i < 8; i+=2) {
1374 id = atoi(argv[i+1]);
1376 if ((name = argv[i+1] = malloc(33)) == NULL)
1378 if (!strcmp(argv[i], "LIST")) {
1379 ## repeat retrieve (name = list.#name) where list.list_id = @id
1380 ## inquire_equel(rowcount = "rowcount")
1382 strcpy(name, "???");
1383 } else if (!strcmp(argv[i], "USER")) {
1384 ## repeat retrieve (name = users.login) where users.users_id = @id
1385 ## inquire_equel(rowcount = "rowcount")
1387 strcpy(name, "???");
1388 } else if (!strcmp(argv[i], "NONE")) {
1389 strcpy(name, "NONE");
1391 strcpy(name, "???");
1396 (*action)(q->vcnt, argv, actarg);
1398 /* free saved data */
1399 for (i = 0; i < q->vcnt; i++)
1404 return(SMS_SUCCESS);
1411 followup_gsha(q, sq, v, action, actarg, cl)
1412 register struct query *q;
1413 register struct save_queue *sq;
1414 register struct validate *v;
1415 register int (*action)();
1420 ## int rowcount, id;
1424 while (sq_get_data(sq, &argv)) {
1425 sms_trim_args(q->vcnt, argv);
1429 name = argv[4] = malloc(9);
1430 ## repeat retrieve (name = users.login) where users.users_id = @id
1431 ## inquire_equel(rowcount = "rowcount")
1433 sprintf(argv[4], "#%d", id);
1437 if ((name = argv[2] = malloc(33)) == NULL)
1439 if (!strcmp(argv[1], "LIST")) {
1440 ## repeat retrieve (name = list.#name) where list.list_id = @id
1441 ## inquire_equel(rowcount = "rowcount")
1443 strcpy(name, "???");
1444 } else if (!strcmp(argv[1], "USER")) {
1445 ## repeat retrieve (name = users.login) where users.users_id = @id
1446 ## inquire_equel(rowcount = "rowcount")
1448 strcpy(name, "???");
1449 } else if (!strcmp(argv[1], "NONE")) {
1450 strcpy(name, "NONE");
1452 strcpy(name, "???");
1456 (*action)(q->vcnt, argv, actarg);
1458 /* free saved data */
1459 for (i = 0; i < q->vcnt; i++)
1464 return(SMS_SUCCESS);
1469 /* Special query routines */
1471 /* set_pobox - this does all of the real work.
1472 * argv = user_id, type, box
1473 * if type is POP, then box should be a machine, and its ID should be put in
1474 * pop_id. If type is SMTP, then box should be a string and its ID should
1475 * be put in box_id. If type is NONE, then box doesn't matter.
1478 int set_pobox(q, argv, cl)
1483 ## int user, id, rowcount;
1484 ## char *box, potype[9];
1487 user = *(int *)argv[0];
1489 ## repeat retrieve (id = users.pop_id, potype = users.#potype)
1490 ## where users.users_id = @user
1491 if (!strcmp(potype, "POP"))
1492 set_pop_usage(id, -1);
1494 if (!strcmp(argv[1], "POP")) {
1495 ## repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1496 ## inquire_equel(rowcount = "rowcount")
1498 return(SMS_MACHINE);
1499 ## repeat replace users (#potype = "POP", pop_id = @id)
1500 ## where users.users_id = @user
1501 set_pop_usage(id, 1);
1502 } else if (!strcmp(argv[1], "SMTP")) {
1503 ## range of s is strings
1504 ## repeat retrieve (id = s.string_id) where s.string = @box
1505 ## inquire_equel (rowcount = "rowcount")
1506 if (rowcount == 0) {
1507 ## range of v is values
1508 ## repeat retrieve (id = v.value) where v.name = "strings_id"
1510 ## repeat replace v (value = @id) where v.name = "strings_id"
1511 ## append to strings (string_id = id, string = box)
1513 ## repeat replace users (#potype = "SMTP", box_id = @id)
1514 ## where users.users_id = @user
1515 } else /* argv[1] == "NONE" */ {
1516 ## repeat replace users (#potype = "NONE") where users.users_id = @user
1519 set_pobox_modtime(q, argv, cl);
1520 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1521 ## where tblstats.#table = "users"
1522 return(SMS_SUCCESS);
1526 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1527 * each list. This is tricky: first build a queue of all requested
1528 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1531 get_list_info(q, aargv, cl, action, actarg)
1532 register struct query *q;
1535 register int (*action)();
1538 char *argv[13], *malloc(), *realloc();
1539 ## char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1540 ## char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1541 ## char modby[9], modwith[9];
1542 ## int id, rowcount, acl_id, hid, modby_id;
1544 struct save_queue *sq, *sq_create();
1546 returned = rowcount = 0;
1550 ## range of l is list
1551 ## repeat retrieve (id = l.list_id) where l.#name = @name {
1552 sq_save_data(sq, id);
1556 return(SMS_NO_MATCH);
1558 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1559 argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1560 argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1563 while (sq_get_data(sq, &id)) {
1567 ## repeat retrieve (listname = l.#name, active = text(l.#active),
1568 ## public = text(l.#public), hidden = text(l.#hidden),
1569 ## hid = l.#hidden, maillist = text(l.#maillist),
1570 ## group = text(l.#group), gid = text(l.#gid),
1571 ## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1572 ## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1573 ## modwith =l.#modwith)
1574 ## where l.list_id = @id
1576 if (atoi(gid) == -1)
1577 argv[6] = UNIQUE_GID;
1579 if (!strcmp(acl_type, "LIST")) {
1580 ## repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1581 ## inquire_equel(rowcount = "rowcount")
1583 strcpy(acl_name, "???");
1584 } else if (!strcmp(acl_type, "USER")) {
1585 ## repeat retrieve (acl_name = users.#login)
1586 ## where users.users_id = @acl_id
1587 ## inquire_equel(rowcount = "rowcount")
1589 strcpy(acl_name, "???");
1590 } else if (!strcmp(acl_type, "NONE")) {
1591 strcpy(acl_name, "NONE");
1593 strcpy(acl_name, "???");
1595 ## repeat retrieve (modby = users.login) where users.users_id = @modby_id
1596 ## inquire_equel(rowcount = "rowcount")
1598 sprintf(modby, "#%d", id);
1600 sms_trim_args(q->vcnt, argv);
1602 (*action)(q->vcnt, argv, actarg);
1606 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1607 ## where tblstats.#table = "list"
1609 return (SMS_SUCCESS);
1613 /* get_ace_use - given a type and a name, return a type and a name.
1614 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1615 * and argv[1] will contain the ID of the entity in question. The R*
1616 * types mean to recursively look at every containing list, not just
1617 * when the object in question is a direct member. On return, the
1618 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1621 int get_ace_use(q, argv, cl, action, actarg)
1630 ## int aid, listid, id;
1631 struct save_queue *sq, *sq_create();
1634 aid = *(int *)argv[1];
1635 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER")) {
1636 return(get_ace_internal(atype, aid, action, actarg));
1640 if (!strcmp(atype, "RLIST")) {
1641 sq_save_data(sq, aid);
1642 /* get all the list_id's of containing lists */
1643 ## range of m is members
1644 while (sq_get_data(sq, &id)) {
1645 ## repeat retrieve (listid = m.list_id)
1646 ## where m.member_type = "LIST" and m.member_id = @id {
1647 sq_save_unique_data(sq, listid);
1650 /* now process each one */
1651 while (sq_get_data(sq, &id)) {
1652 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1657 if (!strcmp(atype, "RUSER")) {
1658 ## range of m is members
1659 ## repeat retrieve (listid = m.list_id)
1660 ## where m.member_type = "USER" and m.member_id = @aid {
1661 sq_save_data(sq, listid);
1663 /* get all the list_id's of containing lists */
1664 while (sq_get_data(sq, &id)) {
1665 ## repeat retrieve (listid = m.list_id)
1666 ## where m.member_type = "LIST" and m.member_id = @id {
1667 sq_save_unique_data(sq, listid);
1670 /* now process each one */
1671 while (sq_get_data(sq, &id)) {
1672 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1675 if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1680 if (!found) return(SMS_NO_MATCH);
1681 return(SMS_SUCCESS);
1685 /* This looks up a single list or user for ace use. atype must be "USER"
1686 * or "LIST", and aid is the ID of the corresponding object. This is used
1687 * by get_ace_use above.
1690 ##get_ace_internal(atype, aid, action, actarg)
1701 if (!strcmp(atype, "LIST")) {
1702 rargv[0] = "FILESYS";
1703 ## repeat retrieve (name = filesys.label)
1704 ## where filesys.owners = @aid {
1705 (*action)(2, rargv, actarg);
1710 ## repeat retrieve (name = capacls.capability)
1711 ## where capacls.list_id = @aid {
1712 (*action)(2, rargv, actarg);
1715 } else if (!strcmp(atype, "USER")) {
1716 rargv[0] = "FILESYS";
1717 ## repeat retrieve (name = filesys.label)
1718 ## where filesys.owner = @aid {
1719 (*action)(2, rargv, actarg);
1725 ## repeat retrieve (name = list.#name)
1726 ## where list.acl_type = @atype and list.acl_id = @aid {
1727 (*action)(2, rargv, actarg);
1731 rargv[0] = "SERVICE";
1732 ## repeat retrieve (name = servers.#name)
1733 ## where servers.acl_type = @atype and servers.acl_id = @aid {
1734 (*action)(2, rargv, actarg);
1738 rargv[0] = "HOSTACCESS";
1739 ## repeat retrieve (name = machine.#name)
1740 ## where machine.mach_id = hostaccess.mach_id and
1741 ## hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1742 (*action)(2, rargv, actarg);
1745 rargv[0] = "ZEPHYR";
1746 ## repeat retrieve (name = zephyr.class)
1747 ## where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
1748 ## zephyr.sub_type = @atype and zephyr.sub_id = @aid or
1749 ## zephyr.iws_type = @atype and zephyr.iws_id = @aid or
1750 ## zephyr.iui_type = @atype and zephyr.iui_id = @aid {
1751 (*action)(2, rargv, actarg);
1755 if (!found) return(SMS_NO_MATCH);
1756 return(SMS_SUCCESS);
1760 /* get_lists_of_member - given a type and a name, return the name and flags
1761 * of all of the lists of the given member. The member_type is one of
1762 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1763 * and argv[1] will contain the ID of the entity in question. The R*
1764 * types mean to recursively look at every containing list, not just
1765 * when the object in question is a direct member.
1768 int get_lists_of_member(q, argv, cl, action, actarg)
1777 ## int aid, listid, id;
1778 struct save_queue *sq, *sq_create();
1781 aid = *(int *)argv[1];
1782 if (!strcmp(atype, "LIST") ||
1783 !strcmp(atype, "USER") ||
1784 !strcmp(atype, "STRING")) {
1785 return(glom_internal(atype, aid, action, actarg));
1789 if (!strcmp(atype, "RLIST")) {
1790 sq_save_data(sq, aid);
1791 /* get all the list_id's of containing lists */
1792 ## range of m is members
1793 while (sq_get_data(sq, &id)) {
1794 ## repeat retrieve (listid = m.list_id)
1795 ## where m.member_type = "LIST" and m.member_id = @id {
1796 sq_save_unique_data(sq, listid);
1799 /* now process each one */
1800 while (sq_get_data(sq, &id)) {
1801 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1806 if (!strcmp(atype, "RUSER")) {
1807 ## range of m is members
1808 ## repeat retrieve (listid = m.list_id)
1809 ## where m.member_type = "USER" and m.member_id = @aid {
1810 sq_save_data(sq, listid);
1812 /* get all the list_id's of containing lists */
1813 while (sq_get_data(sq, &id)) {
1814 ## repeat retrieve (listid = m.list_id)
1815 ## where m.member_type = "LIST" and m.member_id = @id {
1816 sq_save_unique_data(sq, listid);
1819 /* now process each one */
1820 while (sq_get_data(sq, &id)) {
1821 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1824 if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1828 if (!strcmp(atype, "RSTRING")) {
1829 ## range of m is members
1830 ## repeat retrieve (listid = m.list_id)
1831 ## where m.member_type = "STRING" and m.member_id = @aid {
1832 sq_save_data(sq, listid);
1834 /* get all the list_id's of containing lists */
1835 while (sq_get_data(sq, &id)) {
1836 ## repeat retrieve (listid = m.list_id)
1837 ## where m.member_type = "LIST" and m.member_id = @id {
1838 sq_save_unique_data(sq, listid);
1841 /* now process each one */
1842 while (sq_get_data(sq, &id)) {
1843 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1846 if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
1850 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1851 ## where tblstats.#table = "members"
1853 if (!found) return(SMS_NO_MATCH);
1854 return(SMS_SUCCESS);
1858 /* This looks up a single list, user, or string as a member. atype must be
1859 * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
1860 * This is used by get_lists_of_members above.
1863 ##glom_internal(atype, aid, action, actarg)
1871 ## char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
1877 rargv[4] = maillist;
1879 ## repeat retrieve (name = list.#name, active = text(list.#active),
1880 ## public = text(list.#public), hidden = text(list.#hidden),
1881 ## maillist = text(list.#maillist), group = text(list.#group))
1882 ## where list.list_id = m.list_id and
1883 ## m.member_type = @atype and m.member_id = @aid {
1884 (*action)(6, rargv, actarg);
1888 if (!found) return(SMS_NO_MATCH);
1889 return(SMS_SUCCESS);
1893 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1894 * the five flags associated with each list. It will return the name of
1895 * each list that meets the quailifications. It does this by building a
1896 * where clause based on the arguments, then doing a retrieve.
1899 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
1901 int qualified_get_lists(q, argv, cl, action, actarg)
1908 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
1909 "l", "name", lflags));
1913 /** get_members_of_list - optimized query for retrieval of list members
1916 ** argv[0] - list_id
1919 ** - retrieve USER members, then LIST members, then STRING members
1922 get_members_of_list(q, argv, cl, action, actarg)
1930 ## char member_name[129];
1933 list_id = *(int *)argv[0];
1935 targv[1] = member_name;
1937 ## range of m is members
1938 ## repeat retrieve (member_name = users.login)
1939 ## where m.#list_id = @list_id and m.member_type = "USER"
1940 ## and m.member_id = users.users_id
1941 ## sort by #member_name
1943 (*action)(2, targv, actarg);
1947 ## repeat retrieve (member_name = list.name)
1948 ## where m.#list_id = @list_id and m.member_type = "LIST"
1949 ## and m.member_id = list.#list_id
1950 ## sort by #member_name
1952 (*action)(2, targv, actarg);
1955 targv[0] = "STRING";
1956 ## repeat retrieve (member_name = strings.string)
1957 ## where m.#list_id = @list_id and m.member_type = "STRING"
1958 ## and m.member_id = strings.string_id
1959 ## sort by #member_name
1961 (*action)(2, targv, actarg);
1964 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1965 ## where tblstats.#table = "members"
1966 return(SMS_SUCCESS);
1970 /* count_members_of_list: this is a simple query, but it cannot be done
1971 * through the dispatch table.
1974 int count_members_of_list(q, argv, cl, action, actarg)
1981 ## int list, ct = 0;
1982 char *rargv[1], countbuf[5];
1984 list = *(int *)argv[0];
1985 rargv[0] = countbuf;
1986 ## repeat retrieve (ct = count(members.list_id where members.list_id = @list))
1987 sprintf(countbuf, "%d", ct);
1988 (*action)(1, rargv, actarg);
1989 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1990 ## where tblstats.#table = "members"
1991 return(SMS_SUCCESS);
1995 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
1996 * the three flags associated with each service. It will return the name of
1997 * each service that meets the quailifications. It does this by building a
1998 * where clause based on the arguments, then doing a retrieve.
2001 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2003 int qualified_get_server(q, argv, cl, action, actarg)
2010 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2011 "s", "name", sflags));
2015 /* generic qualified get routine, used by qualified_get_lists,
2016 * qualified_get_server, and qualified_get_serverhost.
2018 * start - a simple where clause, must not be empty
2019 * range - the name of the range variable
2020 * field - the field to return
2021 * flags - an array of strings, names of the flag variables
2024 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2034 ## char name[33], qual[256], *rvar, *rtbl, *rfield;
2035 char *rargv[1], buf[32];
2038 strcpy(qual, start);
2039 for (i = 0; i < q->argc; i++) {
2040 if (!strcmp(argv[i], "TRUE")) {
2041 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2042 (void) strcat(qual, buf);
2043 } else if (!strcmp(argv[i], "FALSE")) {
2044 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2045 (void) strcat(qual, buf);
2053 ## range of rvar is rtbl
2054 ## retrieve (name = rvar.rfield) where qual {
2055 (*action)(1, rargv, actarg);
2057 ## inquire_equel(rowcount = "rowcount")
2058 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2059 ## where tblstats.#table = @rtbl
2061 return(SMS_NO_MATCH);
2062 return(SMS_SUCCESS);
2066 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2067 * the five flags associated with each serverhost. It will return the name of
2068 * each service and host that meets the quailifications. It does this by
2069 * building a where clause based on the arguments, then doing a retrieve.
2072 static char *shflags[6] = { "service", "enable", "override", "success",
2073 "inprogress", "hosterror" };
2075 int qualified_get_serverhost(q, argv, cl, action, actarg)
2082 ## char sname[33], mname[33], qual[256];
2083 char *rargv[2], buf[32];
2086 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2088 for (i = 1; i < q->argc; i++) {
2089 if (!strcmp(argv[i], "TRUE")) {
2090 sprintf(buf, " and sh.%s != 0", shflags[i]);
2092 } else if (!strcmp(argv[i], "FALSE")) {
2093 sprintf(buf, " and sh.%s = 0", shflags[i]);
2100 ## range of sh is serverhosts
2101 ## retrieve (sname = sh.service, mname = machine.name) where qual {
2102 (*action)(2, rargv, actarg);
2104 ## inquire_equel(rowcount = "rowcount")
2105 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2106 ## where tblstats.#table = "serverhosts"
2108 return(SMS_NO_MATCH);
2109 return(SMS_SUCCESS);
2113 /* register_user - change user's login name and allocate a pobox, group,
2114 * filesystem, and quota for them. The user's status must start out as 0,
2115 * and is left as 2. Arguments are: user's UID, new login name, and user's
2116 * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY,
2117 * SMS_FS_STAFF, SMS_FS_MISC).
2120 register_user(q, argv, cl)
2125 ## char *login, dir[65], *entity, *directory, machname[33];
2126 ## int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2127 ## int size, alloc, pid, m_id;
2130 entity = cl->entity;
2133 uid = atoi(argv[0]);
2135 utype = atoi(argv[2]);
2137 ## range of u is users
2138 ## range of l is list
2139 ## range of sh is serverhosts
2140 ## range of n is nfsphys
2141 ## range of m is machine
2144 ## repeat retrieve (users_id = u.#users_id)
2145 ## where u.#uid = @uid and u.status = 0
2146 ## inquire_equel(rowcount = "rowcount");
2148 return(SMS_NO_MATCH);
2150 return(SMS_NOT_UNIQUE);
2152 /* check new login name */
2153 ## repeat retrieve (flag = any(u.#login where u.#login = @login))
2156 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2159 ## repeat retrieve (flag = any(filesys.#name where filesys.#name = @login))
2162 com_err(whoami, 0, "new login name OK");
2164 /* choose place for pobox, put in mid */
2165 ## repeat retrieve (mid = sh.mach_id, machname = m.name)
2166 ## where sh.service = "POP" and m.mach_id = sh.mach_id and
2167 ## sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2168 ## inquire_equel(rowcount = "rowcount");
2170 return(SMS_NO_POBOX);
2172 /* change login name, set pobox */
2173 ## repeat replace u (#login = @login, status = 2, modtime = "now",
2174 ## modby = @who, modwith = @entity, potype="POP",
2175 ## pop_id = @mid, pmodtime="now", pmodby=@who,
2176 ## pmodwith=@entity)
2177 ## where u.#users_id = @users_id
2178 ## inquire_equel(rowcount = "rowcount");
2180 return(SMS_INTERNAL);
2181 set_pop_usage(mid, 1);
2182 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2185 /* create group list */
2186 if (set_next_object_id("gid", "list"))
2188 if (set_next_object_id("list_id", "list"))
2190 ## repeat retrieve (list_id = values.value) where values.name = "list_id"
2191 ## inquire_equel(rowcount = "rowcount");
2193 return(SMS_INTERNAL);
2194 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2195 ## public = 0, hidden = 0, maillist = 0, group = 1,
2196 ## #gid = values.value, desc = "User Group",
2197 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2198 ## modby = @who, modwith = @entity)
2199 ## where values.name = "gid"
2200 ## inquire_equel(rowcount = "rowcount");
2202 return(SMS_INTERNAL);
2203 ## repeat append members (#list_id = @list_id, member_type = "USER",
2204 ## member_id = @users_id)
2205 ## inquire_equel(rowcount = "rowcount");
2207 return(SMS_INTERNAL);
2208 com_err(whoami, 0, "group list created");
2210 /* decide where to put filesystem */
2213 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2214 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2215 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2216 maxsize = size - alloc;
2219 directory = strsave(dir);
2225 return(SMS_NO_FILESYS);
2227 /* create filesystem */
2228 if (set_next_object_id("filsys_id", "filesys"))
2230 ## repeat append filesys (filsys_id = values.value, phys_id = @pid,
2231 ## label = @login, type = "NFS", mach_id = @m_id,
2232 ## name = @directory + "/" + @login,
2233 ## mount = "/mit/" + @login,
2234 ## access = "w", comments = "User Locker",
2235 ## owner = @users_id, owners = @list_id, createflg = 1,
2236 ## lockertype = "HOMEDIR", modtime = "now",
2237 ## modby = @who, modwith = @entity)
2238 ## where values.name = "filsys_id"
2239 ## inquire_equel(rowcount = "rowcount");
2241 return(SMS_INTERNAL);
2242 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2246 ## repeat retrieve (quota = values.value) where values.name = "def_quota"
2247 ## inquire_equel(rowcount = "rowcount");
2249 return(SMS_NO_QUOTA);
2250 ## repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2251 ## #quota = @quota, modtime = "now", modby = @who,
2252 ## modwith = @entity)
2253 ## where values.name = "filsys_id"
2254 ## inquire_equel(rowcount = "rowcount");
2256 return(SMS_INTERNAL);
2257 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2258 ## where nfsphys.nfsphys_id = filesys.#phys_id and
2259 ## filesys.filsys_id = values.value and values.name = "filsys_id"
2260 ## inquire_equel(rowcount = "rowcount");
2262 return(SMS_INTERNAL);
2263 com_err(whoami, 0, "quota of %d assigned", quota);
2265 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2266 ## where tblstats.table = "users"
2267 ## repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2268 ## where tblstats.table = "list" or tblstats.table = "filesys" or
2269 ## tblstats.table = "nfsquota"
2270 return(SMS_SUCCESS);
2275 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2279 ** delta (will be +/- 1)
2282 ** - incr/decr value field in serverhosts table for pop/mach_id
2286 static int set_pop_usage(id, count)
2290 ## int mach_id = id;
2293 ## range of sh is serverhosts
2294 ## repeat replace sh (value1 = sh.value1 + @n)
2295 ## where sh.service = "POP" and sh.#mach_id = @mach_id
2297 return(SMS_SUCCESS);
2302 /* Validation Routines */
2304 validate_row(q, argv, v)
2305 register struct query *q;
2307 register struct validate *v;
2315 /* build where clause */
2316 build_qual(v->qual, v->argc, argv, qual);
2318 /* setup ingres variables */
2323 if (log_flags & LOG_RES)
2324 /* tell the logfile what we're doing */
2325 com_err(whoami, 0, "validating row: %s", qual);
2327 /* look for the record */
2328 ## range of rvar is table
2329 ## retrieve (rowcount = count(rvar.name where qual))
2330 if (rowcount == 0) return(SMS_NO_MATCH);
2331 if (rowcount > 1) return(SMS_NOT_UNIQUE);
2335 validate_fields(q, argv, vo, n)
2337 register char *argv[];
2338 register struct valobj *vo;
2341 register int status;
2346 if (log_flags & LOG_RES)
2347 com_err(whoami, 0, "validating %s in %s: %s",
2348 vo->namefield, vo->table, argv[vo->index]);
2349 status = validate_name(argv, vo);
2353 if (log_flags & LOG_RES)
2354 com_err(whoami, 0, "validating %s in %s: %s",
2355 vo->idfield, vo->table, argv[vo->index]);
2356 status = validate_id(argv, vo);
2360 if (log_flags & LOG_RES)
2361 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2362 status = validate_date(argv, vo);
2366 if (log_flags & LOG_RES)
2367 com_err(whoami, 0, "validating %s type: %s",
2368 vo->table, argv[vo->index]);
2369 status = validate_type(argv, vo);
2373 if (log_flags & LOG_RES)
2374 com_err(whoami, 0, "validating typed data (%s): %s",
2375 argv[vo->index - 1], argv[vo->index]);
2376 status = validate_typedata(q, argv, vo);
2380 if (log_flags & LOG_RES)
2381 com_err(whoami, 0, "validating rename %s in %s",
2382 argv[vo->index], vo->table);
2383 status = validate_rename(argv, vo);
2387 if (log_flags & LOG_RES)
2388 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2389 status = validate_chars(argv[vo->index]);
2393 status = SMS_EXISTS;
2398 if (status != SMS_EXISTS) return(status);
2402 return(SMS_SUCCESS);
2406 /* validate_chars: verify that there are no illegal characters in
2407 * the string. Legal characters are printing chars other than
2408 * ", *, ?, \, [ and ].
2410 static int illegalchars[] = {
2411 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2412 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2413 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2414 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2415 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2416 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2417 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2418 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2419 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2420 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2421 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2422 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2423 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2424 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2425 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2426 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2433 if (illegalchars[*s++])
2434 return(SMS_BAD_CHAR);
2439 validate_id(argv, vo)
2441 register struct valobj *vo;
2451 name = argv[vo->index];
2453 /* minor kludge to upcasify machine names */
2454 if (!strcmp(table, "machine"))
2455 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2456 namefield = vo->namefield;
2457 idfield = vo->idfield;
2458 if (!strcmp(namefield, "uid")) {
2459 ## retrieve (id = table.idfield) where table.namefield = int4(name)
2460 ## inquire_equel (rowcount = "rowcount")
2462 ## retrieve (id = table.idfield) where table.namefield = name
2463 ## inquire_equel (rowcount = "rowcount")
2465 if (rowcount != 1) return(vo->error);
2466 *(int *)argv[vo->index] = id;
2470 validate_name(argv, vo)
2472 register struct valobj *vo;
2480 name = argv[vo->index];
2482 namefield = vo->namefield;
2483 if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2484 for (c = name; *c; c++)
2488 ## retrieve (rowcount = countu(table.namefield
2489 ## where table.namefield = name))
2490 return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2493 validate_date(argv, vo)
2501 idate = argv[vo->index];
2503 ## retrieve (dd = interval("years", date(idate) - date("today")))
2504 ## inquire_equel (errorno = "errorno")
2505 if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2510 validate_rename(argv, vo)
2514 ## char *name, *table, *namefield, *idfield;
2518 c = name = argv[vo->index];
2520 if (illegalchars[*c++])
2521 return(SMS_BAD_CHAR);
2523 /* minor kludge to upcasify machine names */
2524 if (!strcmp(table, "machine"))
2525 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2526 namefield = vo->namefield;
2527 idfield = vo->idfield;
2530 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2532 ## retrieve (id = any(table.namefield where table.namefield = name))
2538 ## retrieve (id = table.idfield) where table.namefield = name
2539 if (id == -1 || id == *(int *)argv[vo->index - 1])
2546 validate_type(argv, vo)
2548 register struct valobj *vo;
2555 typename = vo->table;
2556 c = value = argv[vo->index];
2558 if (illegalchars[*c++])
2559 return(SMS_BAD_CHAR);
2561 /* uppercase type fields */
2562 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2564 ## range of a is alias
2565 ## repeat retrieve (exists = any(a.trans where a.name = @typename and
2566 ## a.type = "TYPE" and
2567 ## a.trans = @value))
2568 return (exists ? SMS_EXISTS : vo->error);
2571 /* validate member or type-specific data field */
2573 validate_typedata(q, argv, vo)
2574 register struct query *q;
2575 register char *argv[];
2576 register struct valobj *vo;
2579 ## char *field_type;
2580 ## char data_type[129];
2586 /* get named object */
2587 name = argv[vo->index];
2589 /* get field type string (known to be at index-1) */
2590 field_type = argv[vo->index-1];
2592 /* get corresponding data type associated with field type name */
2593 ## repeat retrieve (data_type = alias.trans)
2594 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
2595 ## inquire_equel (rowcount = "rowcount")
2596 if (rowcount != 1) return(SMS_TYPE);
2598 /* now retrieve the record id corresponding to the named object */
2599 if (index(data_type, ' '))
2600 *index(data_type, ' ') = 0;
2601 if (!strcmp(data_type, "user")) {
2603 ## repeat retrieve (id = users.users_id) where users.login = @name
2604 ## inquire_equel (rowcount = "rowcount")
2605 if (rowcount != 1) return(SMS_USER);
2607 } else if (!strcmp(data_type, "list")) {
2609 ## repeat retrieve (id = list.list_id) where list.#name = @name
2610 ## inquire_equel (rowcount = "rowcount")
2611 if (rowcount != 1) {
2612 /* if idfield is non-zero, then if argv[0] matches the string
2613 * that we're trying to resolve, we should get the value of
2614 * values.[idfield] for the id.
2616 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2617 set_next_object_id(q->validate->object_id, q->rtable);
2619 ## repeat retrieve (id = values.value) where values.#name = @name
2620 ## inquire_equel(rowcount = "rowcount")
2621 if (rowcount != 1) return(SMS_LIST);
2625 } else if (!strcmp(data_type, "machine")) {
2627 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2628 ## repeat retrieve (id = machine.mach_id) where machine.#name = @name
2629 ## inquire_equel (rowcount = "rowcount")
2630 if (rowcount != 1) return(SMS_MACHINE);
2632 } else if (!strcmp(data_type, "string")) {
2634 ## range of s is strings
2635 ## repeat retrieve (id = s.string_id) where s.string = @name
2636 ## inquire_equel (rowcount = "rowcount")
2637 if (rowcount == 0) {
2638 if (q->type != APPEND) return(SMS_STRING);
2639 ## range of v is values
2640 ## retrieve (id = v.value) where v.#name = "strings_id"
2642 ## replace v (value = id) where v.#name = "strings_id"
2643 ## append to strings (string_id = id, string = name)
2645 } else if (!strcmp(data_type, "none")) {
2651 /* now set value in argv */
2652 *(int *)argv[vo->index] = id;
2654 return (SMS_EXISTS);
2658 /* This looks up a login name and returns the SMS internal ID. It is used
2659 * by authenticate to put the users_id in the client structure.
2662 int get_users_id(name)
2665 ## int id, rowcount;
2670 ## range of u is users
2671 ## repeat retrieve (id = u.#users_id) where u.#login = @login
2672 ## inquire_equel (rowcount = "rowcount")
2681 /* Check the database at startup time. For now this just resets the
2682 * inprogress flags that the DCM uses.
2685 sanity_check_database()