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")
72 * argv[7] - group IID (only for query "ulis")
75 * - check that client is a member of the access control list
76 * - OR, if the query is add_member_to_list or delete_member_from_list
77 * and the list is public, allow access if client = member
80 access_list(q, argv, cl)
85 ## int list_id, acl_id, flags, rowcount, gid;
88 int client_id, status;
90 list_id = *(int *)argv[0];
91 ## repeat retrieve (acl_id = list.#acl_id, acl_type = list.#acl_type,
92 ## gid = list.#gid, flags = list.#public)
93 ## where list.#list_id = @list_id
94 ## inquire_equel(rowcount = "rowcount")
98 /* parse client structure */
99 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
102 /* if amtl or dmfl and list is public allow client to add or delete self */
103 if ((!strcmp("amtl", q->shortname) || !strcmp("dmfl", q->shortname)) &&
104 (flags && !strcmp("USER", argv[1]))) {
105 if (*(int *)argv[2] == client_id) return(SMS_SUCCESS);
106 /* if update_list, don't allow them to change the GID */
107 } else if (!strcmp("ulis", q->shortname)) {
108 if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
109 (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
113 /* check for client in access control list */
114 status = find_member(acl_type, acl_id, client_type, client_id, 0);
115 if (!status) return(SMS_PERM);
121 /* access_visible_list - allow access to list only if it is not hidden,
122 * or if the client is on the ACL
124 * Inputs: argv[0] - list_id
125 * cl - client identifier
128 access_visible_list(q, argv, cl)
133 ## int list_id, acl_id, flags, rowcount;
136 int client_id, status;
138 list_id = *(int *)argv[0];
139 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
140 ## acl_type = list.#acl_type) where list.#list_id = @list_id
141 ## inquire_equel(rowcount = "rowcount")
143 return(SMS_INTERNAL);
147 /* parse client structure */
148 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
151 /* check for client in access control list */
152 status = find_member(acl_type, acl_id, client_type, client_id, 0);
160 /* access_vis_list_by_name - allow access to list only if it is not hidden,
161 * or if the client is on the ACL
163 * Inputs: argv[0] - list name
164 * cl - client identifier
167 access_vis_list_by_name(q, argv, cl)
172 ## int acl_id, flags, rowcount;
173 ## char acl_type[9], *listname;
175 int client_id, status;
178 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
179 ## acl_type = list.#acl_type) where list.#name = @listname
180 ## inquire_equel(rowcount = "rowcount");
182 return(SMS_WILDCARD);
184 return(SMS_NO_MATCH);
188 /* parse client structure */
189 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
192 /* check for client in access control list */
193 status = find_member(acl_type, acl_id, client_type, client_id, 0);
201 /* access_member - allow user to access member of type "USER" and name matches
202 * username, or to access member of type "LIST" and list is one that user is
203 * on the acl of, or the list is visible.
206 access_member(q, argv, cl)
211 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
212 return(access_visible_list(q, &argv[1], cl));
214 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
215 if (cl->users_id == *(int *)argv[1])
223 /* access_qgli - special access routine for Qualified_get_lists. Allows
224 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
227 access_qgli(q, argv, cl)
232 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
238 /* access_service - allow access if user is on ACL of service. Don't
239 * allow access if a wildcard is used.
242 access_service(q, argv, cl)
247 ## int acl_id, rowcount;
248 ## char *name, acl_type[9];
249 int client_id, status;
253 ## repeat retrieve (acl_id = servers.#acl_id, acl_type = servers.#acl_type)
254 ## where servers.#name = uppercase(@name)
255 ## inquire_equel(rowcount = "rowcount")
259 /* parse client structure */
260 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
263 /* check for client in access control list */
264 status = find_member(acl_type, acl_id, client_type, client_id, 0);
265 if (!status) return(SMS_PERM);
272 /* access_filesys - verify that client is owner or on owners list of filesystem
276 access_filesys(q, argv, cl)
281 ## int rowcount, users_id, list_id;
283 int status, client_id;
287 ## repeat retrieve (users_id = filesys.owner, list_id = filesys.owners)
288 ## where filesys.label = @name
289 ## inquire_equel(rowcount = "rowcount")
293 if (users_id == cl->users_id)
295 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
297 status = find_member("LIST", list_id, client_type, client_id, 0);
307 /* Setup routine for add_user
309 * Inputs: argv[0] - login
314 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
315 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
318 setup_ausr(q, argv, cl)
320 register char *argv[];
323 ## int nuid, rowcount;
325 if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
326 if (set_next_object_id("uid", "users"))
327 return(SMS_INGRES_ERR);
328 ## repeat retrieve (nuid = values.value) where values.name = "uid"
329 ## inquire_equel(rowcount = "rowcount")
331 return(SMS_INTERNAL);
332 sprintf(argv[1], "%d", nuid);
335 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
336 sprintf(argv[0], "#%s", argv[1]);
343 /* setup_dusr - verify that the user is no longer being referenced
344 * and may safely be deleted.
347 int setup_dusr(q, argv)
353 id = *(int *)argv[0];
355 /* For now, only allow users to be deleted if their status is 0 */
356 ## repeat retrieve (flag = u.status) where u.users_id = @id
360 ## repeat delete nfsquota where nfsquota.users_id = @id
361 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
362 ## and members.member_type = "USER"))
365 ## repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
368 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
369 ## list.acl_type = "USER"))
372 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
373 ## servers.acl_type = "USER"))
376 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
377 ## hostaccess.acl_type = "USER"))
385 /* setup_spop: verify that there is already a valid POP machine_id in the
386 * pop_id field. Also take care of keeping track of the post office usage.
388 int setup_spop(q, argv)
392 ## int id, mid, flag;
395 id = *(int *)argv[0];
396 ## repeat retrieve (type = u.potype, mid = u.pop_id,
397 ## flag = any(machine.name where machine.mach_id = u.pop_id
398 ## and u.pop_id != 0 and u.users_id = @id))
399 ## where u.users_id = @id
402 if (strcmp(strtrim(type), "POP"))
403 set_pop_usage(mid, 1);
408 /* setup_dpob: Take care of keeping track of the post office usage.
410 int setup_dpob(q, argv)
417 user = *(int *)argv[0];
418 ## repeat retrieve (type = u.potype, id = u.pop_id)
419 ## where u.users_id = @user
421 if (!strcmp(strtrim(type), "POP"))
422 set_pop_usage(id, -1);
427 /* setup_dmac - verify that the machine is no longer being referenced
428 * and may safely be deleted.
431 int setup_dmac(q, argv)
437 id = *(int *)argv[0];
438 ## repeat retrieve (flag = any(users.login where users.potype = "POP"
439 ## and users.pop_id=@id))
442 ## repeat retrieve (flag = any(serverhosts.mach_id
443 ## where serverhosts.mach_id=@id))
446 ## repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
449 ## repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
452 ## repeat retrieve (flag = any(printcap.mach_id where printcap.mach_id=@id))
456 ## repeat delete mcmap where mcmap.mach_id = @id
461 /* setup_dclu - verify that the cluster is no longer being referenced
462 * and may safely be deleted.
465 int setup_dclu(q, argv)
471 id = *(int *)argv[0];
472 ## repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
475 ## repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
483 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
484 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
485 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
486 * a -1 there. Remember that this is also used for ulis, with the indexes
490 int setup_alis(q, argv)
498 if (!strcmp(q->shortname, "alis"))
500 else if (!strcmp(q->shortname, "ulis"))
503 if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
504 if (atoi(argv[idx - 1])) {
505 if (set_next_object_id("gid", "list"))
506 return(SMS_INGRES_ERR);
507 ## repeat retrieve (ngid = values.value) where values.name = "gid"
508 sprintf(argv[idx], "%d", ngid);
510 strcpy(argv[idx], "-1");
518 /* setup_dlist - verify that the list is no longer being referenced
519 * and may safely be deleted.
522 int setup_dlis(q, argv)
528 id = *(int *)argv[0];
529 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
530 ## and members.member_type = "LIST"))
533 ## repeat retrieve (flag = any(members.member_id where members.list_id=@id))
536 ## repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
539 ## repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
542 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
543 ## list.acl_type = "LIST" and list.list_id != @id))
546 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
547 ## servers.acl_type = "LIST"))
550 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
551 ## hostaccess.acl_type = "LIST"))
554 ## repeat retrieve (flag = any(zephyr.class
555 ## where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
556 ## zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
557 ## zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
558 ## zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
566 /* setup_dsin - verify that the service is no longer being referenced
567 * and may safely be deleted.
570 int setup_dsin(q, argv)
578 ## repeat retrieve (flag = any(serverhosts.service
579 ## where serverhosts.service=uppercase(@name)))
582 ## repeat retrieve (flag = servers.inprogress) where servers.#name = @name
590 /* setup_dshi - verify that the service-host is no longer being referenced
591 * and may safely be deleted.
594 int setup_dshi(q, argv)
602 id = *(int *)argv[1];
603 ## repeat retrieve (flag=serverhosts.inprogress)
604 ## where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
613 ** setup_add_filesys - verify existance of referenced file systems
625 ** * extract directory prefix from name
626 ** * verify mach_id/dir in nfsphys
627 ** * verify access in {r, w, R, W}
629 ** Side effect: sets variable var_phys_id to the ID of the physical
630 ** filesystem (nfsphys_id for NFS, 0 for RVD)
633 ** SMS_NFS - specified directory not exported
634 ** SMS_FILESYS_ACCESS - invalid filesys access
638 ##static int var_phys_id;
650 mach_id = *(int *)argv[2];
655 if (!strcmp(type, "NFS"))
656 return (check_nfs(mach_id, name, access));
662 /* Verify the arguments, depending on the FStype. Also, if this is an
663 * NFS filesystem, then update any quotas for that filesystem to reflect
672 char *type, *name, *access;
676 mach_id = *(int *)argv[3];
681 if (!strcmp(type, "NFS")) {
682 status = check_nfs(mach_id, name, access);
683 fid = *(int *)argv[0];
684 ## replace nfsquota (phys_id = var_phys_id) where nfsquota.filsys_id = fid
691 /* Find the NFS physical partition that the named directory is on.
692 * This is done by comparing the dir against the mount point of the
693 * partition. To make sure we get the correct match when there is
694 * more than one, we sort the query in reverse order by dir name.
697 ##check_nfs(mach_id, name, access)
708 caccess = (isupper(*access)) ? tolower(*access) : *access;
709 if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
712 ## range of np is nfsphys
713 ## repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
714 ## where np.#mach_id = @mach_id sort by #dir:d {
718 if (*cp1++ != *cp2) break;
722 status = SMS_SUCCESS;
731 /* setup_dfil: free any quota records associated with a filesystem
732 * when it is deleted.
735 setup_dfil(q, argv, cl)
742 id = *(int *)argv[0];
743 ## range of q is nfsquota
744 ## range of fs is filesys
745 ## range of n is nfsphys
746 ## repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
747 ## where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
749 ## repeat delete q where q.filsys_id = @id
754 /* setup_dnfp: check to see that the nfs physical partition does not have
755 * any filesystems assigned to it before allowing it to be deleted.
758 setup_dnfp(q, argv, cl)
765 id = *(int *)argv[0];
766 ## repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
773 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
774 * argv[0] = filsys_id
778 setup_dnfq(q, argv, cl)
783 ## int quota, fs, user;
785 fs = *(int *)argv[0];
786 user = *(int *)argv[1];
788 ## range of q is nfsquota
789 ## repeat retrieve (quota = q.#quota) where q.users_id = @user and
791 ## repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
792 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
798 /* FOLLOWUP ROUTINES */
800 /* generic set_modtime routine. This takes the table name from the query,
801 * and will update the modtime, modby, and modwho fields in the entry in
802 * the table whose name field matches argv[0].
805 set_modtime(q, argv, cl)
810 ## char *name, *entity, *table;
818 ## replace table (modtime = "now", modby = who, modwith = entity)
819 ## where table.#name = name
823 /* generic set_modtime_by_id routine. This takes the table name from
824 * the query, and the id name from the validate record,
825 * and will update the modtime, modby, and modwho fields in the entry in
826 * the table whose id matches argv[0].
829 set_modtime_by_id(q, argv, cl)
834 ## char *entity, *table, *id_name;
840 id_name = q->validate->object_id;
842 id = *(int *)argv[0];
843 ## replace table (modtime = "now", modby = who, modwith = entity)
844 ## where table.id_name = id
849 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
852 set_finger_modtime(q, argv, cl)
857 ## int users_id, who;
862 users_id = *(int *)argv[0];
864 ## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
865 ## where u.#users_id = @users_id
870 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
873 set_pobox_modtime(q, argv, cl)
878 ## int users_id, who;
883 users_id = *(int *)argv[0];
885 ## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
886 ## where users.#users_id = @users_id
891 /* Sets the modtime on a machine record. The machine name is in argv[0].
892 * This routine is different from the generic set_modtime in that the
893 * name is uppercased first.
896 set_mach_modtime(q, argv, cl)
901 ## char *host, *entity;
908 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
909 ## where m.name = uppercase(@host)
914 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
915 * is necessary for add_machine_to_cluster becuase the table that query
916 * operates on is "mcm", not "machine".
919 set_mach_modtime_by_id(q, argv, cl)
930 id = *(int *)argv[0];
931 ## range of m is machine
932 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
933 ## where m.mach_id = @id
938 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
939 * is necessary for add_cluster_data and delete_cluster_data becuase the
940 * table that query operates on is "svc", not "cluster".
943 set_cluster_modtime_by_id(q, argv, cl)
954 id = *(int *)argv[0];
955 ## range of c is cluster
956 ## repeat replace c (modtime = "now", modby = @who, modwith = @entity)
957 ## where c.clu_id = @id
962 /* sets the modtime on the serverhost where the service name is in argv[0]
963 * and the mach_id is in argv[1].
966 set_serverhost_modtime(q, argv, cl)
971 ## char *entity, *serv;
978 id = *(int *)argv[1];
979 ## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
980 ## where sh.service = uppercase(@serv) and sh.mach_id = @id
985 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
986 * directory name is in argv[1].
989 set_nfsphys_modtime(q, argv, cl)
994 ## char *entity, *dir;
1000 id = *(int *)argv[0];
1002 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1003 ## where np.#dir = @dir and np.mach_id = @id
1004 return(SMS_SUCCESS);
1008 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1012 set_filesys_modtime(q, argv, cl)
1017 ## char *label, *entity;
1020 entity = cl->entity;
1024 if (!strcmp(q->shortname, "ufil"))
1027 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1028 ## #phys_id = @var_phys_id) where fs.#label = @label
1029 return(SMS_SUCCESS);
1033 /* sets the modtime on a zephyr class, where argv[0] contains the class
1037 set_zephyr_modtime(q, argv, cl)
1042 ## char *class, *entity;
1045 entity = cl->entity;
1050 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1051 ## where z.#class = @class
1052 return(SMS_SUCCESS);
1056 /* fixes the modby field. This will be the second to last thing in the
1057 * argv, the argv length is determined from the query structure. It is
1058 * passed as a pointer to an integer. This will either turn it into a
1059 * username, or # + the users_id.
1061 followup_fix_modby(q, sq, v, action, actarg, cl)
1063 register struct save_queue *sq;
1065 register int (*action)();
1066 register int actarg;
1070 char **argv, *malloc();
1071 ## int id, rowcount;
1075 while (sq_get_data(sq, &argv)) {
1078 argv[i] = malloc(9);
1080 ## repeat retrieve (name = users.login) where users.users_id = @id
1081 ## inquire_equel(rowcount = "rowcount")
1082 if (rowcount != 1) {
1083 sprintf(argv[i], "#%d", id);
1085 (*action)(q->vcnt, argv, actarg);
1086 for (j = 0; j < q->vcnt; j++)
1091 return(SMS_SUCCESS);
1096 ** followup_ausr - add finger and pobox entries, set_user_modtime
1099 ** argv[0] - login (add_user)
1100 ** argv[3] - last name
1101 ** argv[4] - first name
1102 ** argv[5] - middle name
1106 followup_ausr(q, argv, cl)
1112 ## char *login, *entity;
1113 ## char fullname[129];
1117 entity = cl->entity;
1119 /* build fullname */
1120 if (strlen(argv[4]) && strlen(argv[5]))
1121 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1122 else if (strlen(argv[4]))
1123 sprintf(fullname, "%s %s", argv[4], argv[3]);
1125 sprintf(fullname, "%s", argv[3]);
1127 /* create finger entry, pobox & set modtime on user */
1128 ## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1129 ## #fullname=@fullname, mit_affil = u.mit_year,
1130 ## fmodtime="now", fmodby=@who, fmodwith=@entity,
1131 ## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1132 ## where u.#login = @login
1134 return(SMS_SUCCESS);
1138 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1139 * type in argv[1]. Then completes the upcall to the user.
1141 * argv[2] is of the form "123:234" where the first integer is the machine
1142 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1143 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1147 followup_gpob(q, sq, v, action, actarg, cl)
1148 register struct query *q;
1149 register struct save_queue *sq;
1150 register struct validate *v;
1151 register int (*action)();
1155 char **argv, *index();
1157 ## char box[129], *name;
1158 ## int mid, sid, rowcount;
1161 while (sq_get_data(sq, &argv)) {
1162 sms_trim_args(2, argv);
1164 p = index(argv[2], ':');
1166 mid = atoi(argv[2]);
1170 if (!strcmp(ptype, "POP")) {
1171 ## repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1172 ## inquire_equel(rowcount = "rowcount")
1174 return(SMS_MACHINE);
1175 } else if (!strcmp(ptype, "SMTP")) {
1176 ## repeat retrieve (box=strings.string) where strings.string_id=@sid
1177 ## inquire_equel(rowcount = "rowcount")
1180 } else /* ptype == "NONE" */ {
1184 if (!strcmp(q->shortname, "gpob")) {
1185 sid = atoi(argv[4]);
1187 argv[4] = malloc(9);
1189 ## repeat retrieve (name = users.login) where users.users_id = @sid
1190 ## inquire_equel(rowcount = "rowcount")
1192 sprintf(name, "#%d", sid);
1196 (*action)(q->vcnt, argv, actarg);
1198 /* free saved data */
1205 return (SMS_SUCCESS);
1209 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1210 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1211 * proper name based on the type, and repace that string in the argv.
1212 * Also fixes the modby field by called followup_fix_modby.
1215 followup_glin(q, sq, v, action, actarg, cl)
1216 register struct query *q;
1217 register struct save_queue *sq;
1218 register struct validate *v;
1219 register int (*action)();
1223 char **argv, *malloc(), *realloc(), *type;
1225 ## int id, rowcount;
1229 if (!strcmp(q->shortname, "gsin"))
1232 while (sq_get_data(sq, &argv)) {
1233 sms_trim_args(q->vcnt, argv);
1235 id = atoi(argv[i = q->vcnt - 2]);
1237 name = argv[i] = malloc(9);
1238 ## repeat retrieve (name = users.login) where users.users_id = @id
1239 ## inquire_equel(rowcount = "rowcount")
1241 sprintf(argv[i], "#%d", id);
1243 id = atoi(argv[idx]);
1244 type = argv[idx - 1];
1245 if ((name = malloc(33)) == NULL)
1248 if (!strcmp(type, "LIST")) {
1249 ## repeat retrieve (name = list.#name) where list.list_id = @id
1250 ## inquire_equel(rowcount = "rowcount")
1252 strcpy(name, "???");
1253 } else if (!strcmp(type, "USER")) {
1254 ## repeat retrieve (name = users.login) where users.users_id = @id
1255 ## inquire_equel(rowcount = "rowcount")
1257 strcpy(name, "???");
1258 } else if (!strcmp(type, "NONE")) {
1259 strcpy(name, "NONE");
1261 strcpy(name, "???");
1265 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1266 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1267 strcpy(argv[6], UNIQUE_GID);
1271 (*action)(q->vcnt, argv, actarg);
1273 /* free saved data */
1274 for (i = 0; i < q->vcnt; i++)
1280 return (SMS_SUCCESS);
1284 /** followup_amtl - followup for amtl and dmfl; when adding a list
1285 ** member to a maillist, make member list a maillist also
1286 ** unless list is a user-group.
1287 ** Then set_list_modtime_by_id.
1290 ** argv[0] - list_id
1291 ** argv[1] - member_type
1292 ** argv[2] - member_id
1296 followup_amtl(q, argv, cl)
1306 list_id = *(int *)argv[0];
1307 entity = cl->entity;
1310 ## range of l is list
1311 ## repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1312 ## where l.#list_id = @list_id
1314 /* if query is not amtl or if member_type is not LIST then return */
1315 if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4))
1316 return(SMS_SUCCESS);
1318 member_id = *(int *)argv[2];
1320 /* is parent list a mailing list? */
1321 ## repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1323 return(SMS_SUCCESS);
1325 /* list is not a user-group; add list to maillist table */
1326 ## repeat replace l (maillist = 1) where l.#list_id = @member_id
1327 return(SMS_SUCCESS);
1331 /* followup_anfq: Add allocation to nfsphys after creating quota.
1332 * argv[0] = filsys_id
1333 * argv[2] = ascii(quota)
1336 followup_anfq(q, argv, cl)
1341 ## int quota, user, fs, who;
1344 fs = *(int *)argv[0];
1345 user = *(int *)argv[1];
1346 quota = atoi(argv[2]);
1348 entity = cl->entity;
1350 ## repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1351 ## where nq.filsys_id = @fs and nq.users_id = @user
1352 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1353 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1354 return(SMS_SUCCESS);
1361 followup_gzcl(q, sq, v, action, actarg, cl)
1362 register struct query *q;
1363 register struct save_queue *sq;
1364 register struct validate *v;
1365 register int (*action)();
1370 ## int rowcount, id;
1374 while (sq_get_data(sq, &argv)) {
1375 sms_trim_args(q->vcnt, argv);
1377 id = atoi(argv[i = q->vcnt - 2]);
1379 name = argv[i] = malloc(9);
1380 ## repeat retrieve (name = users.login) where users.users_id = @id
1381 ## inquire_equel(rowcount = "rowcount")
1383 sprintf(argv[i], "#%d", id);
1385 for (i = 1; i < 8; i+=2) {
1386 id = atoi(argv[i+1]);
1388 if ((name = argv[i+1] = malloc(33)) == NULL)
1390 if (!strcmp(argv[i], "LIST")) {
1391 ## repeat retrieve (name = list.#name) where list.list_id = @id
1392 ## inquire_equel(rowcount = "rowcount")
1394 strcpy(name, "???");
1395 } else if (!strcmp(argv[i], "USER")) {
1396 ## repeat retrieve (name = users.login) where users.users_id = @id
1397 ## inquire_equel(rowcount = "rowcount")
1399 strcpy(name, "???");
1400 } else if (!strcmp(argv[i], "NONE")) {
1401 strcpy(name, "NONE");
1403 strcpy(name, "???");
1408 (*action)(q->vcnt, argv, actarg);
1410 /* free saved data */
1411 for (i = 0; i < q->vcnt; i++)
1416 return(SMS_SUCCESS);
1423 followup_gsha(q, sq, v, action, actarg, cl)
1424 register struct query *q;
1425 register struct save_queue *sq;
1426 register struct validate *v;
1427 register int (*action)();
1432 ## int rowcount, id;
1436 while (sq_get_data(sq, &argv)) {
1437 sms_trim_args(q->vcnt, argv);
1441 name = argv[4] = malloc(9);
1442 ## repeat retrieve (name = users.login) where users.users_id = @id
1443 ## inquire_equel(rowcount = "rowcount")
1445 sprintf(argv[4], "#%d", id);
1449 if ((name = argv[2] = malloc(33)) == NULL)
1451 if (!strcmp(argv[1], "LIST")) {
1452 ## repeat retrieve (name = list.#name) where list.list_id = @id
1453 ## inquire_equel(rowcount = "rowcount")
1455 strcpy(name, "???");
1456 } else if (!strcmp(argv[1], "USER")) {
1457 ## repeat retrieve (name = users.login) where users.users_id = @id
1458 ## inquire_equel(rowcount = "rowcount")
1460 strcpy(name, "???");
1461 } else if (!strcmp(argv[1], "NONE")) {
1462 strcpy(name, "NONE");
1464 strcpy(name, "???");
1468 (*action)(q->vcnt, argv, actarg);
1470 /* free saved data */
1471 for (i = 0; i < q->vcnt; i++)
1476 return(SMS_SUCCESS);
1481 /* Special query routines */
1483 /* set_pobox - this does all of the real work.
1484 * argv = user_id, type, box
1485 * if type is POP, then box should be a machine, and its ID should be put in
1486 * pop_id. If type is SMTP, then box should be a string and its ID should
1487 * be put in box_id. If type is NONE, then box doesn't matter.
1490 int set_pobox(q, argv, cl)
1495 ## int user, id, rowcount;
1496 ## char *box, potype[9];
1499 user = *(int *)argv[0];
1501 ## repeat retrieve (id = users.pop_id, potype = users.#potype)
1502 ## where users.users_id = @user
1503 if (!strcmp(strtrim(potype), "POP"))
1504 set_pop_usage(id, -1);
1506 if (!strcmp(argv[1], "POP")) {
1507 ## repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1508 ## inquire_equel(rowcount = "rowcount")
1510 return(SMS_MACHINE);
1511 ## repeat replace users (#potype = "POP", pop_id = @id)
1512 ## where users.users_id = @user
1513 set_pop_usage(id, 1);
1514 } else if (!strcmp(argv[1], "SMTP")) {
1515 ## range of s is strings
1516 ## repeat retrieve (id = s.string_id) where s.string = @box
1517 ## inquire_equel (rowcount = "rowcount")
1518 if (rowcount == 0) {
1519 ## range of v is values
1520 ## repeat retrieve (id = v.value) where v.name = "strings_id"
1522 ## repeat replace v (value = @id) where v.name = "strings_id"
1523 ## append to strings (string_id = id, string = box)
1525 ## repeat replace users (#potype = "SMTP", box_id = @id)
1526 ## where users.users_id = @user
1527 } else /* argv[1] == "NONE" */ {
1528 ## repeat replace users (#potype = "NONE") where users.users_id = @user
1531 set_pobox_modtime(q, argv, cl);
1532 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1533 ## where tblstats.#table = "users"
1534 return(SMS_SUCCESS);
1538 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1539 * each list. This is tricky: first build a queue of all requested
1540 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1543 get_list_info(q, aargv, cl, action, actarg)
1544 register struct query *q;
1547 register int (*action)();
1550 char *argv[13], *malloc(), *realloc();
1551 ## char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1552 ## char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1553 ## char modby[9], modwith[9];
1554 ## int id, rowcount, acl_id, hid, modby_id;
1556 struct save_queue *sq, *sq_create();
1558 returned = rowcount = 0;
1562 ## range of l is list
1563 ## repeat retrieve (id = l.list_id) where l.#name = @name {
1564 sq_save_data(sq, id);
1568 return(SMS_NO_MATCH);
1570 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1571 argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1572 argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1575 while (sq_get_data(sq, &id)) {
1579 ## repeat retrieve (listname = l.#name, active = text(l.#active),
1580 ## public = text(l.#public), hidden = text(l.#hidden),
1581 ## hid = l.#hidden, maillist = text(l.#maillist),
1582 ## group = text(l.#group), gid = text(l.#gid),
1583 ## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1584 ## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1585 ## modwith =l.#modwith)
1586 ## where l.list_id = @id
1588 if (atoi(gid) == -1)
1589 argv[6] = UNIQUE_GID;
1591 if (!strcmp(acl_type, "LIST")) {
1592 ## repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1593 ## inquire_equel(rowcount = "rowcount")
1595 strcpy(acl_name, "???");
1596 } else if (!strcmp(acl_type, "USER")) {
1597 ## repeat retrieve (acl_name = users.#login)
1598 ## where users.users_id = @acl_id
1599 ## inquire_equel(rowcount = "rowcount")
1601 strcpy(acl_name, "???");
1602 } else if (!strcmp(acl_type, "NONE")) {
1603 strcpy(acl_name, "NONE");
1605 strcpy(acl_name, "???");
1607 ## repeat retrieve (modby = users.login) where users.users_id = @modby_id
1608 ## inquire_equel(rowcount = "rowcount")
1610 sprintf(modby, "#%d", id);
1612 sms_trim_args(q->vcnt, argv);
1614 (*action)(q->vcnt, argv, actarg);
1618 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1619 ## where tblstats.#table = "list"
1621 return (SMS_SUCCESS);
1625 /* get_ace_use - given a type and a name, return a type and a name.
1626 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1627 * and argv[1] will contain the ID of the entity in question. The R*
1628 * types mean to recursively look at every containing list, not just
1629 * when the object in question is a direct member. On return, the
1630 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1633 int get_ace_use(q, argv, cl, action, actarg)
1642 ## int aid, listid, id;
1643 struct save_queue *sq, *sq_create();
1646 aid = *(int *)argv[1];
1647 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER")) {
1648 return(get_ace_internal(atype, aid, action, actarg));
1652 if (!strcmp(atype, "RLIST")) {
1653 sq_save_data(sq, aid);
1654 /* get all the list_id's of containing lists */
1655 ## range of m is members
1656 while (sq_get_data(sq, &id)) {
1657 ## repeat retrieve (listid = m.list_id)
1658 ## where m.member_type = "LIST" and m.member_id = @id {
1659 sq_save_unique_data(sq, listid);
1662 /* now process each one */
1663 while (sq_get_data(sq, &id)) {
1664 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1669 if (!strcmp(atype, "RUSER")) {
1670 ## range of m is members
1671 ## repeat retrieve (listid = m.list_id)
1672 ## where m.member_type = "USER" and m.member_id = @aid {
1673 sq_save_data(sq, listid);
1675 /* get all the list_id's of containing lists */
1676 while (sq_get_data(sq, &id)) {
1677 ## repeat retrieve (listid = m.list_id)
1678 ## where m.member_type = "LIST" and m.member_id = @id {
1679 sq_save_unique_data(sq, listid);
1682 /* now process each one */
1683 while (sq_get_data(sq, &id)) {
1684 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1687 if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1692 if (!found) return(SMS_NO_MATCH);
1693 return(SMS_SUCCESS);
1697 /* This looks up a single list or user for ace use. atype must be "USER"
1698 * or "LIST", and aid is the ID of the corresponding object. This is used
1699 * by get_ace_use above.
1702 ##get_ace_internal(atype, aid, action, actarg)
1713 if (!strcmp(atype, "LIST")) {
1714 rargv[0] = "FILESYS";
1715 ## repeat retrieve (name = filesys.label)
1716 ## where filesys.owners = @aid {
1717 (*action)(2, rargv, actarg);
1722 ## repeat retrieve (name = capacls.capability)
1723 ## where capacls.list_id = @aid {
1724 (*action)(2, rargv, actarg);
1727 } else if (!strcmp(atype, "USER")) {
1728 rargv[0] = "FILESYS";
1729 ## repeat retrieve (name = filesys.label)
1730 ## where filesys.owner = @aid {
1731 (*action)(2, rargv, actarg);
1737 ## repeat retrieve (name = list.#name)
1738 ## where list.acl_type = @atype and list.acl_id = @aid {
1739 (*action)(2, rargv, actarg);
1743 rargv[0] = "SERVICE";
1744 ## repeat retrieve (name = servers.#name)
1745 ## where servers.acl_type = @atype and servers.acl_id = @aid {
1746 (*action)(2, rargv, actarg);
1750 rargv[0] = "HOSTACCESS";
1751 ## repeat retrieve (name = machine.#name)
1752 ## where machine.mach_id = hostaccess.mach_id and
1753 ## hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1754 (*action)(2, rargv, actarg);
1757 rargv[0] = "ZEPHYR";
1758 ## repeat retrieve (name = zephyr.class)
1759 ## where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
1760 ## zephyr.sub_type = @atype and zephyr.sub_id = @aid or
1761 ## zephyr.iws_type = @atype and zephyr.iws_id = @aid or
1762 ## zephyr.iui_type = @atype and zephyr.iui_id = @aid {
1763 (*action)(2, rargv, actarg);
1767 if (!found) return(SMS_NO_MATCH);
1768 return(SMS_SUCCESS);
1772 /* get_lists_of_member - given a type and a name, return the name and flags
1773 * of all of the lists of the given member. The member_type is one of
1774 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1775 * and argv[1] will contain the ID of the entity in question. The R*
1776 * types mean to recursively look at every containing list, not just
1777 * when the object in question is a direct member.
1780 int get_lists_of_member(q, argv, cl, action, actarg)
1789 ## int aid, listid, id;
1790 struct save_queue *sq, *sq_create();
1793 aid = *(int *)argv[1];
1794 if (!strcmp(atype, "LIST") ||
1795 !strcmp(atype, "USER") ||
1796 !strcmp(atype, "STRING")) {
1797 return(glom_internal(atype, aid, action, actarg));
1801 if (!strcmp(atype, "RLIST")) {
1802 sq_save_data(sq, aid);
1803 /* get all the list_id's of containing lists */
1804 ## range of m is members
1805 while (sq_get_data(sq, &id)) {
1806 ## repeat retrieve (listid = m.list_id)
1807 ## where m.member_type = "LIST" and m.member_id = @id {
1808 sq_save_unique_data(sq, listid);
1811 /* now process each one */
1812 while (sq_get_data(sq, &id)) {
1813 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1818 if (!strcmp(atype, "RUSER")) {
1819 ## range of m is members
1820 ## repeat retrieve (listid = m.list_id)
1821 ## where m.member_type = "USER" and m.member_id = @aid {
1822 sq_save_data(sq, listid);
1824 /* get all the list_id's of containing lists */
1825 while (sq_get_data(sq, &id)) {
1826 ## repeat retrieve (listid = m.list_id)
1827 ## where m.member_type = "LIST" and m.member_id = @id {
1828 sq_save_unique_data(sq, listid);
1831 /* now process each one */
1832 while (sq_get_data(sq, &id)) {
1833 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1836 if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1840 if (!strcmp(atype, "RSTRING")) {
1841 ## range of m is members
1842 ## repeat retrieve (listid = m.list_id)
1843 ## where m.member_type = "STRING" and m.member_id = @aid {
1844 sq_save_data(sq, listid);
1846 /* get all the list_id's of containing lists */
1847 while (sq_get_data(sq, &id)) {
1848 ## repeat retrieve (listid = m.list_id)
1849 ## where m.member_type = "LIST" and m.member_id = @id {
1850 sq_save_unique_data(sq, listid);
1853 /* now process each one */
1854 while (sq_get_data(sq, &id)) {
1855 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1858 if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
1862 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1863 ## where tblstats.#table = "members"
1865 if (!found) return(SMS_NO_MATCH);
1866 return(SMS_SUCCESS);
1870 /* This looks up a single list, user, or string as a member. atype must be
1871 * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
1872 * This is used by get_lists_of_members above.
1875 ##glom_internal(atype, aid, action, actarg)
1883 ## char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
1889 rargv[4] = maillist;
1891 ## repeat retrieve (name = list.#name, active = text(list.#active),
1892 ## public = text(list.#public), hidden = text(list.#hidden),
1893 ## maillist = text(list.#maillist), group = text(list.#group))
1894 ## where list.list_id = m.list_id and
1895 ## m.member_type = @atype and m.member_id = @aid {
1896 (*action)(6, rargv, actarg);
1900 if (!found) return(SMS_NO_MATCH);
1901 return(SMS_SUCCESS);
1905 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1906 * the five flags associated with each list. It will return the name of
1907 * each list that meets the quailifications. It does this by building a
1908 * where clause based on the arguments, then doing a retrieve.
1911 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
1913 int qualified_get_lists(q, argv, cl, action, actarg)
1920 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
1921 "l", "name", lflags));
1925 /** get_members_of_list - optimized query for retrieval of list members
1928 ** argv[0] - list_id
1931 ** - retrieve USER members, then LIST members, then STRING members
1934 get_members_of_list(q, argv, cl, action, actarg)
1942 ## char member_name[129];
1945 list_id = *(int *)argv[0];
1947 targv[1] = member_name;
1949 ## range of m is members
1950 ## repeat retrieve (member_name = users.login)
1951 ## where m.#list_id = @list_id and m.member_type = "USER"
1952 ## and m.member_id = users.users_id
1953 ## sort by #member_name
1955 (*action)(2, targv, actarg);
1959 ## repeat retrieve (member_name = list.name)
1960 ## where m.#list_id = @list_id and m.member_type = "LIST"
1961 ## and m.member_id = list.#list_id
1962 ## sort by #member_name
1964 (*action)(2, targv, actarg);
1967 targv[0] = "STRING";
1968 ## repeat retrieve (member_name = strings.string)
1969 ## where m.#list_id = @list_id and m.member_type = "STRING"
1970 ## and m.member_id = strings.string_id
1971 ## sort by #member_name
1973 (*action)(2, targv, actarg);
1976 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1977 ## where tblstats.#table = "members"
1978 return(SMS_SUCCESS);
1982 /* count_members_of_list: this is a simple query, but it cannot be done
1983 * through the dispatch table.
1986 int count_members_of_list(q, argv, cl, action, actarg)
1993 ## int list, ct = 0;
1994 char *rargv[1], countbuf[5];
1996 list = *(int *)argv[0];
1997 rargv[0] = countbuf;
1998 ## repeat retrieve (ct = count(members.list_id where members.list_id = @list))
1999 sprintf(countbuf, "%d", ct);
2000 (*action)(1, rargv, actarg);
2001 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2002 ## where tblstats.#table = "members"
2003 return(SMS_SUCCESS);
2007 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2008 * the three flags associated with each service. It will return the name of
2009 * each service that meets the quailifications. It does this by building a
2010 * where clause based on the arguments, then doing a retrieve.
2013 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2015 int qualified_get_server(q, argv, cl, action, actarg)
2022 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2023 "s", "name", sflags));
2027 /* generic qualified get routine, used by qualified_get_lists,
2028 * qualified_get_server, and qualified_get_serverhost.
2030 * start - a simple where clause, must not be empty
2031 * range - the name of the range variable
2032 * field - the field to return
2033 * flags - an array of strings, names of the flag variables
2036 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2046 ## char name[33], qual[256], *rvar, *rtbl, *rfield;
2047 char *rargv[1], buf[32];
2050 strcpy(qual, start);
2051 for (i = 0; i < q->argc; i++) {
2052 if (!strcmp(argv[i], "TRUE")) {
2053 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2054 (void) strcat(qual, buf);
2055 } else if (!strcmp(argv[i], "FALSE")) {
2056 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2057 (void) strcat(qual, buf);
2065 ## range of rvar is rtbl
2066 ## retrieve (name = rvar.rfield) where qual {
2067 (*action)(1, rargv, actarg);
2069 ## inquire_equel(rowcount = "rowcount")
2070 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2071 ## where tblstats.#table = @rtbl
2073 return(SMS_NO_MATCH);
2074 return(SMS_SUCCESS);
2078 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2079 * the five flags associated with each serverhost. It will return the name of
2080 * each service and host that meets the quailifications. It does this by
2081 * building a where clause based on the arguments, then doing a retrieve.
2084 static char *shflags[6] = { "service", "enable", "override", "success",
2085 "inprogress", "hosterror" };
2087 int qualified_get_serverhost(q, argv, cl, action, actarg)
2094 ## char sname[33], mname[33], qual[256];
2095 char *rargv[2], buf[32];
2098 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2100 for (i = 1; i < q->argc; i++) {
2101 if (!strcmp(argv[i], "TRUE")) {
2102 sprintf(buf, " and sh.%s != 0", shflags[i]);
2104 } else if (!strcmp(argv[i], "FALSE")) {
2105 sprintf(buf, " and sh.%s = 0", shflags[i]);
2112 ## range of sh is serverhosts
2113 ## retrieve (sname = sh.service, mname = machine.name) where qual {
2114 (*action)(2, rargv, actarg);
2116 ## inquire_equel(rowcount = "rowcount")
2117 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2118 ## where tblstats.#table = "serverhosts"
2120 return(SMS_NO_MATCH);
2121 return(SMS_SUCCESS);
2125 /* register_user - change user's login name and allocate a pobox, group,
2126 * filesystem, and quota for them. The user's status must start out as 0,
2127 * and is left as 2. Arguments are: user's UID, new login name, and user's
2128 * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY,
2129 * SMS_FS_STAFF, SMS_FS_MISC).
2132 register_user(q, argv, cl)
2137 ## char *login, dir[65], *entity, *directory, machname[33];
2138 ## int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2139 ## int size, alloc, pid, m_id;
2142 entity = cl->entity;
2145 uid = atoi(argv[0]);
2147 utype = atoi(argv[2]);
2149 ## range of u is users
2150 ## range of l is list
2151 ## range of sh is serverhosts
2152 ## range of n is nfsphys
2153 ## range of m is machine
2156 ## repeat retrieve (users_id = u.#users_id)
2157 ## where u.#uid = @uid and u.status = 0
2158 ## inquire_equel(rowcount = "rowcount");
2160 return(SMS_NO_MATCH);
2162 return(SMS_NOT_UNIQUE);
2164 /* check new login name */
2165 ## repeat retrieve (flag = any(u.#login where u.#login = @login))
2168 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2171 ## repeat retrieve (flag = any(filesys.#name where filesys.#name = @login))
2174 com_err(whoami, 0, "new login name OK");
2176 /* choose place for pobox, put in mid */
2177 ## repeat retrieve (mid = sh.mach_id, machname = m.name)
2178 ## where sh.service = "POP" and m.mach_id = sh.mach_id and
2179 ## sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2180 ## inquire_equel(rowcount = "rowcount");
2182 return(SMS_NO_POBOX);
2184 /* change login name, set pobox */
2185 ## repeat replace u (#login = @login, status = 2, modtime = "now",
2186 ## modby = @who, modwith = @entity, potype="POP",
2187 ## pop_id = @mid, pmodtime="now", pmodby=@who,
2188 ## pmodwith=@entity)
2189 ## where u.#users_id = @users_id
2190 ## inquire_equel(rowcount = "rowcount");
2192 return(SMS_INTERNAL);
2193 set_pop_usage(mid, 1);
2194 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2197 /* create group list */
2198 if (set_next_object_id("gid", "list"))
2200 if (set_next_object_id("list_id", "list"))
2202 ## repeat retrieve (list_id = values.value) where values.name = "list_id"
2203 ## inquire_equel(rowcount = "rowcount");
2205 return(SMS_INTERNAL);
2206 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2207 ## public = 0, hidden = 0, maillist = 0, group = 1,
2208 ## #gid = values.value, desc = "User Group",
2209 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2210 ## modby = @who, modwith = @entity)
2211 ## where values.name = "gid"
2212 ## inquire_equel(rowcount = "rowcount");
2214 return(SMS_INTERNAL);
2215 ## repeat append members (#list_id = @list_id, member_type = "USER",
2216 ## member_id = @users_id)
2217 ## inquire_equel(rowcount = "rowcount");
2219 return(SMS_INTERNAL);
2220 com_err(whoami, 0, "group list created");
2222 /* decide where to put filesystem */
2225 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2226 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2227 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2228 maxsize = size - alloc;
2231 directory = strsave(dir);
2237 return(SMS_NO_FILESYS);
2239 /* create filesystem */
2240 if (set_next_object_id("filsys_id", "filesys"))
2242 ## repeat append filesys (filsys_id = values.value, phys_id = @pid,
2243 ## label = @login, type = "NFS", mach_id = @m_id,
2244 ## name = @directory + "/" + @login,
2245 ## mount = "/mit/" + @login,
2246 ## access = "w", comments = "User Locker",
2247 ## owner = @users_id, owners = @list_id, createflg = 1,
2248 ## lockertype = "HOMEDIR", modtime = "now",
2249 ## modby = @who, modwith = @entity)
2250 ## where values.name = "filsys_id"
2251 ## inquire_equel(rowcount = "rowcount");
2253 return(SMS_INTERNAL);
2254 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2258 ## repeat retrieve (quota = values.value) where values.name = "def_quota"
2259 ## inquire_equel(rowcount = "rowcount");
2261 return(SMS_NO_QUOTA);
2262 ## repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2263 ## #quota = @quota, phys_id = @pid, modtime = "now",
2264 ## modby = @who, modwith = @entity)
2265 ## where values.name = "filsys_id"
2266 ## inquire_equel(rowcount = "rowcount");
2268 return(SMS_INTERNAL);
2269 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2270 ## where nfsphys.nfsphys_id = filesys.#phys_id and
2271 ## filesys.filsys_id = values.value and values.name = "filsys_id"
2272 ## inquire_equel(rowcount = "rowcount");
2274 return(SMS_INTERNAL);
2275 com_err(whoami, 0, "quota of %d assigned", quota);
2277 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2278 ## where tblstats.table = "users"
2279 ## repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2280 ## where tblstats.table = "list" or tblstats.table = "filesys" or
2281 ## tblstats.table = "nfsquota"
2282 return(SMS_SUCCESS);
2287 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2291 ** delta (will be +/- 1)
2294 ** - incr/decr value field in serverhosts table for pop/mach_id
2298 static int set_pop_usage(id, count)
2302 ## int mach_id = id;
2305 ## range of sh is serverhosts
2306 ## repeat replace sh (value1 = sh.value1 + @n)
2307 ## where sh.service = "POP" and sh.#mach_id = @mach_id
2309 return(SMS_SUCCESS);
2314 /* Validation Routines */
2316 validate_row(q, argv, v)
2317 register struct query *q;
2319 register struct validate *v;
2327 /* build where clause */
2328 build_qual(v->qual, v->argc, argv, qual);
2330 /* setup ingres variables */
2335 if (log_flags & LOG_VALID)
2336 /* tell the logfile what we're doing */
2337 com_err(whoami, 0, "validating row: %s", qual);
2339 /* look for the record */
2340 ## range of rvar is table
2341 ## retrieve (rowcount = count(rvar.name where qual))
2342 if (rowcount == 0) return(SMS_NO_MATCH);
2343 if (rowcount > 1) return(SMS_NOT_UNIQUE);
2347 validate_fields(q, argv, vo, n)
2349 register char *argv[];
2350 register struct valobj *vo;
2353 register int status;
2358 if (log_flags & LOG_VALID)
2359 com_err(whoami, 0, "validating %s in %s: %s",
2360 vo->namefield, vo->table, argv[vo->index]);
2361 status = validate_name(argv, vo);
2365 if (log_flags & LOG_VALID)
2366 com_err(whoami, 0, "validating %s in %s: %s",
2367 vo->idfield, vo->table, argv[vo->index]);
2368 status = validate_id(argv, vo);
2372 if (log_flags & LOG_VALID)
2373 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2374 status = validate_date(argv, vo);
2378 if (log_flags & LOG_VALID)
2379 com_err(whoami, 0, "validating %s type: %s",
2380 vo->table, argv[vo->index]);
2381 status = validate_type(argv, vo);
2385 if (log_flags & LOG_VALID)
2386 com_err(whoami, 0, "validating typed data (%s): %s",
2387 argv[vo->index - 1], argv[vo->index]);
2388 status = validate_typedata(q, argv, vo);
2392 if (log_flags & LOG_VALID)
2393 com_err(whoami, 0, "validating rename %s in %s",
2394 argv[vo->index], vo->table);
2395 status = validate_rename(argv, vo);
2399 if (log_flags & LOG_VALID)
2400 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2401 status = validate_chars(argv[vo->index]);
2405 status = SMS_EXISTS;
2410 if (status != SMS_EXISTS) return(status);
2414 return(SMS_SUCCESS);
2418 /* validate_chars: verify that there are no illegal characters in
2419 * the string. Legal characters are printing chars other than
2420 * ", *, ?, \, [ and ].
2422 static int illegalchars[] = {
2423 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2424 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2425 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2426 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2427 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2428 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2429 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2430 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2431 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2432 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2433 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2434 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2435 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2436 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2437 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2438 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2445 if (illegalchars[*s++])
2446 return(SMS_BAD_CHAR);
2451 validate_id(argv, vo)
2453 register struct valobj *vo;
2463 name = argv[vo->index];
2465 /* minor kludge to upcasify machine names */
2466 if (!strcmp(table, "machine"))
2467 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2468 namefield = vo->namefield;
2469 idfield = vo->idfield;
2470 if (!strcmp(namefield, "uid")) {
2471 ## retrieve (id = table.idfield) where table.namefield = int4(name)
2472 ## inquire_equel (rowcount = "rowcount")
2474 ## retrieve (id = table.idfield) where table.namefield = name
2475 ## inquire_equel (rowcount = "rowcount")
2477 if (rowcount != 1) return(vo->error);
2478 *(int *)argv[vo->index] = id;
2482 validate_name(argv, vo)
2484 register struct valobj *vo;
2492 name = argv[vo->index];
2494 namefield = vo->namefield;
2495 if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2496 for (c = name; *c; c++)
2500 ## retrieve (rowcount = countu(table.namefield
2501 ## where table.namefield = name))
2502 return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2505 validate_date(argv, vo)
2513 idate = argv[vo->index];
2515 ## retrieve (dd = interval("years", date(idate) - date("today")))
2516 ## inquire_equel (errorno = "errorno")
2517 if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2522 validate_rename(argv, vo)
2526 ## char *name, *table, *namefield, *idfield;
2530 c = name = argv[vo->index];
2532 if (illegalchars[*c++])
2533 return(SMS_BAD_CHAR);
2535 /* minor kludge to upcasify machine names */
2536 if (!strcmp(table, "machine"))
2537 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2538 namefield = vo->namefield;
2539 idfield = vo->idfield;
2542 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2544 ## retrieve (id = any(table.namefield where table.namefield = name))
2550 ## retrieve (id = table.idfield) where table.namefield = name
2551 if (id == -1 || id == *(int *)argv[vo->index - 1])
2558 validate_type(argv, vo)
2560 register struct valobj *vo;
2567 typename = vo->table;
2568 c = value = argv[vo->index];
2570 if (illegalchars[*c++])
2571 return(SMS_BAD_CHAR);
2573 /* uppercase type fields */
2574 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2576 ## range of a is alias
2577 ## repeat retrieve (exists = any(a.trans where a.name = @typename and
2578 ## a.type = "TYPE" and
2579 ## a.trans = @value))
2580 return (exists ? SMS_EXISTS : vo->error);
2583 /* validate member or type-specific data field */
2585 validate_typedata(q, argv, vo)
2586 register struct query *q;
2587 register char *argv[];
2588 register struct valobj *vo;
2591 ## char *field_type;
2592 ## char data_type[129];
2598 /* get named object */
2599 name = argv[vo->index];
2601 /* get field type string (known to be at index-1) */
2602 field_type = argv[vo->index-1];
2604 /* get corresponding data type associated with field type name */
2605 ## repeat retrieve (data_type = alias.trans)
2606 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
2607 ## inquire_equel (rowcount = "rowcount")
2608 if (rowcount != 1) return(SMS_TYPE);
2610 /* now retrieve the record id corresponding to the named object */
2611 if (index(data_type, ' '))
2612 *index(data_type, ' ') = 0;
2613 if (!strcmp(data_type, "user")) {
2615 ## repeat retrieve (id = users.users_id) where users.login = @name
2616 ## inquire_equel (rowcount = "rowcount")
2617 if (rowcount != 1) return(SMS_USER);
2619 } else if (!strcmp(data_type, "list")) {
2621 ## repeat retrieve (id = list.list_id) where list.#name = @name
2622 ## inquire_equel (rowcount = "rowcount")
2623 if (rowcount != 1) {
2624 /* if idfield is non-zero, then if argv[0] matches the string
2625 * that we're trying to resolve, we should get the value of
2626 * values.[idfield] for the id.
2628 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2629 set_next_object_id(q->validate->object_id, q->rtable);
2631 ## repeat retrieve (id = values.value) where values.#name = @name
2632 ## inquire_equel(rowcount = "rowcount")
2633 if (rowcount != 1) return(SMS_LIST);
2637 } else if (!strcmp(data_type, "machine")) {
2639 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2640 ## repeat retrieve (id = machine.mach_id) where machine.#name = @name
2641 ## inquire_equel (rowcount = "rowcount")
2642 if (rowcount != 1) return(SMS_MACHINE);
2644 } else if (!strcmp(data_type, "string")) {
2646 ## range of s is strings
2647 ## repeat retrieve (id = s.string_id) where s.string = @name
2648 ## inquire_equel (rowcount = "rowcount")
2649 if (rowcount == 0) {
2650 if (q->type != APPEND) return(SMS_STRING);
2651 ## range of v is values
2652 ## retrieve (id = v.value) where v.#name = "strings_id"
2654 ## replace v (value = id) where v.#name = "strings_id"
2655 ## append to strings (string_id = id, string = name)
2657 } else if (!strcmp(data_type, "none")) {
2663 /* now set value in argv */
2664 *(int *)argv[vo->index] = id;
2666 return (SMS_EXISTS);
2670 /* This looks up a login name and returns the SMS internal ID. It is used
2671 * by authenticate to put the users_id in the client structure.
2674 int get_users_id(name)
2677 ## int id, rowcount;
2682 ## range of u is users
2683 ## repeat retrieve (id = u.#users_id) where u.#login = @login
2684 ## inquire_equel (rowcount = "rowcount")
2693 /* Check the database at startup time. For now this just resets the
2694 * inprogress flags that the DCM uses.
2697 sanity_check_database()