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)
395 id = *(int *)argv[0];
396 ## repeat retrieve (type = u.potype, flag = any(machine.name
397 ## where machine.mach_id = u.pop_id
399 ## and u.users_id = @id))
400 ## where u.users_id = @id
403 if (strcmp(type, "POP"))
404 set_pop_usage(id, 1);
409 /* setup_dpob: Take care of keeping track of the post office usage.
411 int setup_dpob(q, argv)
418 user = *(int *)argv[0];
419 ## repeat retrieve (type = u.potype, id = u.pop_id)
420 ## where u.users_id = @user
422 if (strcmp(type, "POP"))
423 set_pop_usage(id, -1);
428 /* setup_dmac - verify that the machine is no longer being referenced
429 * and may safely be deleted.
432 int setup_dmac(q, argv)
438 id = *(int *)argv[0];
439 ## repeat retrieve (flag = any(users.login where users.potype = "POP"
440 ## and users.pop_id=@id))
443 ## repeat retrieve (flag = any(serverhosts.mach_id
444 ## where serverhosts.mach_id=@id))
447 ## repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
450 ## repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
453 ## repeat retrieve (flag = any(pcap.mach_id where pcap.mach_id=@id))
457 ## repeat delete mcmap where mcmap.mach_id = @id
462 /* setup_dclu - verify that the cluster is no longer being referenced
463 * and may safely be deleted.
466 int setup_dclu(q, argv)
472 id = *(int *)argv[0];
473 ## repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
476 ## repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
484 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
485 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
486 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
487 * a -1 there. Remember that this is also used for ulis, with the indexes
491 int setup_alis(q, argv)
499 if (!strcmp(q->shortname, "alis"))
501 else if (!strcmp(q->shortname, "ulis"))
504 if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
505 if (atoi(argv[idx - 1])) {
506 if (set_next_object_id("gid", "list"))
507 return(SMS_INGRES_ERR);
508 ## repeat retrieve (ngid = values.value) where values.name = "gid"
509 sprintf(argv[idx], "%d", ngid);
511 strcpy(argv[idx], "-1");
519 /* setup_dlist - verify that the list is no longer being referenced
520 * and may safely be deleted.
523 int setup_dlis(q, argv)
529 id = *(int *)argv[0];
530 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
531 ## and members.member_type = "LIST"))
534 ## repeat retrieve (flag = any(members.member_id where members.list_id=@id))
537 ## repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
540 ## repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
543 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
544 ## list.acl_type = "LIST" and list.list_id != @id))
547 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
548 ## servers.acl_type = "LIST"))
551 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
552 ## hostaccess.acl_type = "LIST"))
555 ## repeat retrieve (flag = any(zephyr.class
556 ## where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
557 ## zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
558 ## zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
559 ## zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
567 /* setup_dsin - verify that the service is no longer being referenced
568 * and may safely be deleted.
571 int setup_dsin(q, argv)
579 ## repeat retrieve (flag = any(serverhosts.service
580 ## where serverhosts.service=uppercase(@name)))
583 ## repeat retrieve (flag = servers.inprogress) where servers.#name = @name
591 /* setup_dshi - verify that the service-host is no longer being referenced
592 * and may safely be deleted.
595 int setup_dshi(q, argv)
603 id = *(int *)argv[1];
604 ## repeat retrieve (flag=serverhosts.inprogress)
605 ## where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
614 ** setup_add_filesys - verify existance of referenced file systems
626 ** * extract directory prefix from name
627 ** * verify mach_id/dir in nfsphys
628 ** * verify access in {r, w, R, W}
630 ** Side effect: sets variable var_phys_id to the ID of the physical
631 ** filesystem (nfsphys_id for NFS, 0 for RVD)
634 ** SMS_NFS - specified directory not exported
635 ** SMS_FILESYS_ACCESS - invalid filesys access
639 ##static int var_phys_id;
651 mach_id = *(int *)argv[2];
656 if (!strcmp(type, "NFS"))
657 return (check_nfs(mach_id, name, access));
673 mach_id = *(int *)argv[3];
678 if (!strcmp(type, "NFS"))
679 return (check_nfs(mach_id, name, access));
685 /* Find the NFS physical partition that the named directory is on.
686 * This is done by comparing the dir against the mount point of the
687 * partition. To make sure we get the correct match when there is
688 * more than one, we sort the query in reverse order by dir name.
691 ##check_nfs(mach_id, name, access)
702 caccess = (isupper(*access)) ? tolower(*access) : *access;
703 if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
706 ## range of np is nfsphys
707 ## repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
708 ## where np.#mach_id = @mach_id sort by #dir:d {
712 if (*cp1++ != *cp2) break;
716 status = SMS_SUCCESS;
725 /* setup_dfil: free any quota records associated with a filesystem
726 * when it is deleted.
729 setup_dfil(q, argv, cl)
736 id = *(int *)argv[0];
737 ## range of q is nfsquota
738 ## range of fs is filesys
739 ## range of n is nfsphys
740 ## repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
741 ## where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
743 ## repeat delete q where q.filsys_id = @id
748 /* setup_dnfp: check to see that the nfs physical partition does not have
749 * any filesystems assigned to it before allowing it to be deleted.
752 setup_dnfp(q, argv, cl)
759 id = *(int *)argv[0];
760 ## repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
767 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
768 * argv[0] = filsys_id
772 setup_dnfq(q, argv, cl)
777 ## int quota, fs, user;
779 fs = *(int *)argv[0];
780 user = *(int *)argv[1];
782 ## range of q is nfsquota
783 ## repeat retrieve (quota = q.#quota) where q.users_id = @user and
785 ## repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
786 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
792 /* FOLLOWUP ROUTINES */
794 /* generic set_modtime routine. This takes the table name from the query,
795 * and will update the modtime, modby, and modwho fields in the entry in
796 * the table whose name field matches argv[0].
799 set_modtime(q, argv, cl)
804 ## char *name, *entity, *table;
812 ## replace table (modtime = "now", modby = who, modwith = entity)
813 ## where table.#name = name
817 /* generic set_modtime_by_id routine. This takes the table name from
818 * the query, and the id name from the validate record,
819 * and will update the modtime, modby, and modwho fields in the entry in
820 * the table whose id matches argv[0].
823 set_modtime_by_id(q, argv, cl)
828 ## char *entity, *table, *id_name;
834 id_name = q->validate->object_id;
836 id = *(int *)argv[0];
837 ## replace table (modtime = "now", modby = who, modwith = entity)
838 ## where table.id_name = id
843 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
846 set_finger_modtime(q, argv, cl)
851 ## int users_id, who;
856 users_id = *(int *)argv[0];
858 ## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
859 ## where u.#users_id = @users_id
864 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
867 set_pobox_modtime(q, argv, cl)
872 ## int users_id, who;
877 users_id = *(int *)argv[0];
879 ## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
880 ## where users.#users_id = @users_id
885 /* Sets the modtime on a machine record. The machine name is in argv[0].
886 * This routine is different from the generic set_modtime in that the
887 * name is uppercased first.
890 set_mach_modtime(q, argv, cl)
895 ## char *host, *entity;
902 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
903 ## where m.name = uppercase(@host)
908 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
909 * is necessary for add_machine_to_cluster becuase the table that query
910 * operates on is "mcm", not "machine".
913 set_mach_modtime_by_id(q, argv, cl)
924 id = *(int *)argv[0];
925 ## range of m is machine
926 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
927 ## where m.mach_id = @id
932 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
933 * is necessary for add_cluster_data and delete_cluster_data becuase the
934 * table that query operates on is "svc", not "cluster".
937 set_cluster_modtime_by_id(q, argv, cl)
948 id = *(int *)argv[0];
949 ## range of c is cluster
950 ## repeat replace c (modtime = "now", modby = @who, modwith = @entity)
951 ## where c.clu_id = @id
956 /* sets the modtime on the serverhost where the service name is in argv[0]
957 * and the mach_id is in argv[1].
960 set_serverhost_modtime(q, argv, cl)
965 ## char *entity, *serv;
972 id = *(int *)argv[1];
973 ## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
974 ## where sh.service = uppercase(@serv) and sh.mach_id = @id
979 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
980 * directory name is in argv[1].
983 set_nfsphys_modtime(q, argv, cl)
988 ## char *entity, *dir;
994 id = *(int *)argv[0];
996 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
997 ## where np.#dir = @dir and np.mach_id = @id
1002 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1006 set_filesys_modtime(q, argv, cl)
1011 ## char *label, *entity;
1014 entity = cl->entity;
1018 if (!strcmp(q->shortname, "ufil"))
1021 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1022 ## #phys_id = @var_phys_id) where fs.#label = @label
1023 return(SMS_SUCCESS);
1027 /* sets the modtime on a zephyr class, where argv[0] contains the class
1031 set_zephyr_modtime(q, argv, cl)
1036 ## char *class, *entity;
1039 entity = cl->entity;
1044 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1045 ## where z.#class = @class
1046 return(SMS_SUCCESS);
1050 /* fixes the modby field. This will be the second to last thing in the
1051 * argv, the argv length is determined from the query structure. It is
1052 * passed as a pointer to an integer. This will either turn it into a
1053 * username, or # + the users_id.
1055 followup_fix_modby(q, sq, v, action, actarg, cl)
1057 register struct save_queue *sq;
1059 register int (*action)();
1060 register int actarg;
1064 char **argv, *malloc();
1065 ## int id, rowcount;
1069 while (sq_get_data(sq, &argv)) {
1072 argv[i] = malloc(9);
1074 ## repeat retrieve (name = users.login) where users.users_id = @id
1075 ## inquire_equel(rowcount = "rowcount")
1076 if (rowcount != 1) {
1077 sprintf(argv[i], "#%d", id);
1079 (*action)(q->vcnt, argv, actarg);
1080 for (j = 0; j < q->vcnt; j++)
1085 return(SMS_SUCCESS);
1090 ** followup_ausr - add finger and pobox entries, set_user_modtime
1093 ** argv[0] - login (add_user)
1094 ** argv[3] - last name
1095 ** argv[4] - first name
1096 ** argv[5] - middle name
1100 followup_ausr(q, argv, cl)
1106 ## char *login, *entity;
1107 ## char fullname[129];
1111 entity = cl->entity;
1113 /* build fullname */
1114 if (strlen(argv[4]) && strlen(argv[5]))
1115 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1116 else if (strlen(argv[4]))
1117 sprintf(fullname, "%s %s", argv[4], argv[3]);
1119 sprintf(fullname, "%s", argv[3]);
1121 /* create finger entry, pobox & set modtime on user */
1122 ## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1123 ## #fullname=@fullname, mit_affil = u.mit_year,
1124 ## fmodtime="now", fmodby=@who, fmodwith=@entity,
1125 ## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1126 ## where u.#login = @login
1128 return(SMS_SUCCESS);
1132 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1133 * type in argv[1]. Then completes the upcall to the user.
1135 * argv[2] is of the form "123:234" where the first integer is the machine
1136 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1137 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1141 followup_gpob(q, sq, v, action, actarg, cl)
1142 register struct query *q;
1143 register struct save_queue *sq;
1144 register struct validate *v;
1145 register int (*action)();
1149 char **argv, *index();
1151 ## char box[129], *name;
1152 ## int mid, sid, rowcount;
1155 while (sq_get_data(sq, &argv)) {
1156 sms_trim_args(2, argv);
1158 p = index(argv[2], ':');
1160 mid = atoi(argv[2]);
1164 if (!strcmp(ptype, "POP")) {
1165 ## repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1166 ## inquire_equel(rowcount = "rowcount")
1168 return(SMS_MACHINE);
1169 } else if (!strcmp(ptype, "SMTP")) {
1170 ## repeat retrieve (box=strings.string) where strings.string_id=@sid
1171 ## inquire_equel(rowcount = "rowcount")
1174 } else /* ptype == "NONE" */ {
1178 if (!strcmp(q->shortname, "gpob")) {
1179 sid = atoi(argv[4]);
1181 argv[4] = malloc(9);
1183 ## repeat retrieve (name = users.login) where users.users_id = @sid
1184 ## inquire_equel(rowcount = "rowcount")
1186 sprintf(name, "#%d", sid);
1190 (*action)(q->vcnt, argv, actarg);
1192 /* free saved data */
1199 return (SMS_SUCCESS);
1203 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1204 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1205 * proper name based on the type, and repace that string in the argv.
1206 * Also fixes the modby field by called followup_fix_modby.
1209 followup_glin(q, sq, v, action, actarg, cl)
1210 register struct query *q;
1211 register struct save_queue *sq;
1212 register struct validate *v;
1213 register int (*action)();
1217 char **argv, *malloc(), *realloc(), *type;
1219 ## int id, rowcount;
1223 if (!strcmp(q->shortname, "gsin"))
1226 while (sq_get_data(sq, &argv)) {
1227 sms_trim_args(q->vcnt, argv);
1229 id = atoi(argv[i = q->vcnt - 2]);
1231 name = argv[i] = malloc(9);
1232 ## repeat retrieve (name = users.login) where users.users_id = @id
1233 ## inquire_equel(rowcount = "rowcount")
1235 sprintf(argv[i], "#%d", id);
1237 id = atoi(argv[idx]);
1238 type = argv[idx - 1];
1239 if ((name = malloc(33)) == NULL)
1242 if (!strcmp(type, "LIST")) {
1243 ## repeat retrieve (name = list.#name) where list.list_id = @id
1244 ## inquire_equel(rowcount = "rowcount")
1246 strcpy(name, "???");
1247 } else if (!strcmp(type, "USER")) {
1248 ## repeat retrieve (name = users.login) where users.users_id = @id
1249 ## inquire_equel(rowcount = "rowcount")
1251 strcpy(name, "???");
1252 } else if (!strcmp(type, "NONE")) {
1253 strcpy(name, "NONE");
1255 strcpy(name, "???");
1259 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1260 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1261 strcpy(argv[6], UNIQUE_GID);
1265 (*action)(q->vcnt, argv, actarg);
1267 /* free saved data */
1268 for (i = 0; i < q->vcnt; i++)
1274 return (SMS_SUCCESS);
1278 /** followup_amtl - followup for amtl and dmfl; when adding a list
1279 ** member to a maillist, make member list a maillist also
1280 ** unless list is a user-group.
1281 ** Then set_list_modtime_by_id.
1284 ** argv[0] - list_id
1285 ** argv[1] - member_type
1286 ** argv[2] - member_id
1290 followup_amtl(q, argv, cl)
1300 list_id = *(int *)argv[0];
1301 entity = cl->entity;
1304 ## range of l is list
1305 ## repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1306 ## where l.#list_id = @list_id
1308 /* if query is not amtl or if member_type is not LIST then return */
1309 if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4))
1310 return(SMS_SUCCESS);
1312 member_id = *(int *)argv[2];
1314 /* is parent list a mailing list? */
1315 ## repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1317 return(SMS_SUCCESS);
1319 /* list is not a user-group; add list to maillist table */
1320 ## repeat replace l (maillist = 1) where l.#list_id = @member_id
1321 return(SMS_SUCCESS);
1325 /* followup_anfq: Add allocation to nfsphys after creating quota.
1326 * argv[0] = filsys_id
1327 * argv[2] = ascii(quota)
1330 followup_anfq(q, argv, cl)
1335 ## int quota, user, fs, who;
1338 fs = *(int *)argv[0];
1339 user = *(int *)argv[1];
1340 quota = atoi(argv[2]);
1342 entity = cl->entity;
1344 ## repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1345 ## where nq.filsys_id = @fs and nq.users_id = @user
1346 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1347 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1348 return(SMS_SUCCESS);
1355 followup_gzcl(q, sq, v, action, actarg, cl)
1356 register struct query *q;
1357 register struct save_queue *sq;
1358 register struct validate *v;
1359 register int (*action)();
1364 ## int rowcount, id;
1368 while (sq_get_data(sq, &argv)) {
1369 sms_trim_args(q->vcnt, argv);
1371 id = atoi(argv[i = q->vcnt - 2]);
1373 name = argv[i] = malloc(9);
1374 ## repeat retrieve (name = users.login) where users.users_id = @id
1375 ## inquire_equel(rowcount = "rowcount")
1377 sprintf(argv[i], "#%d", id);
1379 for (i = 1; i < 8; i+=2) {
1380 id = atoi(argv[i+1]);
1382 if ((name = argv[i+1] = malloc(33)) == NULL)
1384 if (!strcmp(argv[i], "LIST")) {
1385 ## repeat retrieve (name = list.#name) where list.list_id = @id
1386 ## inquire_equel(rowcount = "rowcount")
1388 strcpy(name, "???");
1389 } else if (!strcmp(argv[i], "USER")) {
1390 ## repeat retrieve (name = users.login) where users.users_id = @id
1391 ## inquire_equel(rowcount = "rowcount")
1393 strcpy(name, "???");
1394 } else if (!strcmp(argv[i], "NONE")) {
1395 strcpy(name, "NONE");
1397 strcpy(name, "???");
1402 (*action)(q->vcnt, argv, actarg);
1404 /* free saved data */
1405 for (i = 0; i < q->vcnt; i++)
1410 return(SMS_SUCCESS);
1417 followup_gsha(q, sq, v, action, actarg, cl)
1418 register struct query *q;
1419 register struct save_queue *sq;
1420 register struct validate *v;
1421 register int (*action)();
1426 ## int rowcount, id;
1430 while (sq_get_data(sq, &argv)) {
1431 sms_trim_args(q->vcnt, argv);
1435 name = argv[4] = malloc(9);
1436 ## repeat retrieve (name = users.login) where users.users_id = @id
1437 ## inquire_equel(rowcount = "rowcount")
1439 sprintf(argv[4], "#%d", id);
1443 if ((name = argv[2] = malloc(33)) == NULL)
1445 if (!strcmp(argv[1], "LIST")) {
1446 ## repeat retrieve (name = list.#name) where list.list_id = @id
1447 ## inquire_equel(rowcount = "rowcount")
1449 strcpy(name, "???");
1450 } else if (!strcmp(argv[1], "USER")) {
1451 ## repeat retrieve (name = users.login) where users.users_id = @id
1452 ## inquire_equel(rowcount = "rowcount")
1454 strcpy(name, "???");
1455 } else if (!strcmp(argv[1], "NONE")) {
1456 strcpy(name, "NONE");
1458 strcpy(name, "???");
1462 (*action)(q->vcnt, argv, actarg);
1464 /* free saved data */
1465 for (i = 0; i < q->vcnt; i++)
1470 return(SMS_SUCCESS);
1475 /* Special query routines */
1477 /* set_pobox - this does all of the real work.
1478 * argv = user_id, type, box
1479 * if type is POP, then box should be a machine, and its ID should be put in
1480 * pop_id. If type is SMTP, then box should be a string and its ID should
1481 * be put in box_id. If type is NONE, then box doesn't matter.
1484 int set_pobox(q, argv, cl)
1489 ## int user, id, rowcount;
1490 ## char *box, potype[9];
1493 user = *(int *)argv[0];
1495 ## repeat retrieve (id = users.pop_id, potype = users.#potype)
1496 ## where users.users_id = @user
1497 if (!strcmp(potype, "POP"))
1498 set_pop_usage(id, -1);
1500 if (!strcmp(argv[1], "POP")) {
1501 ## repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1502 ## inquire_equel(rowcount = "rowcount")
1504 return(SMS_MACHINE);
1505 ## repeat replace users (#potype = "POP", pop_id = @id)
1506 ## where users.users_id = @user
1507 set_pop_usage(id, 1);
1508 } else if (!strcmp(argv[1], "SMTP")) {
1509 ## range of s is strings
1510 ## repeat retrieve (id = s.string_id) where s.string = @box
1511 ## inquire_equel (rowcount = "rowcount")
1512 if (rowcount == 0) {
1513 ## range of v is values
1514 ## repeat retrieve (id = v.value) where v.name = "strings_id"
1516 ## repeat replace v (value = @id) where v.name = "strings_id"
1517 ## append to strings (string_id = id, string = box)
1519 ## repeat replace users (#potype = "SMTP", box_id = @id)
1520 ## where users.users_id = @user
1521 } else /* argv[1] == "NONE" */ {
1522 ## repeat replace users (#potype = "NONE") where users.users_id = @user
1525 set_pobox_modtime(q, argv, cl);
1526 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1527 ## where tblstats.#table = "users"
1528 return(SMS_SUCCESS);
1532 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1533 * each list. This is tricky: first build a queue of all requested
1534 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1537 get_list_info(q, aargv, cl, action, actarg)
1538 register struct query *q;
1541 register int (*action)();
1544 char *argv[13], *malloc(), *realloc();
1545 ## char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1546 ## char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1547 ## char modby[9], modwith[9];
1548 ## int id, rowcount, acl_id, hid, modby_id;
1550 struct save_queue *sq, *sq_create();
1552 returned = rowcount = 0;
1556 ## range of l is list
1557 ## repeat retrieve (id = l.list_id) where l.#name = @name {
1558 sq_save_data(sq, id);
1562 return(SMS_NO_MATCH);
1564 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1565 argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1566 argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1569 while (sq_get_data(sq, &id)) {
1573 ## repeat retrieve (listname = l.#name, active = text(l.#active),
1574 ## public = text(l.#public), hidden = text(l.#hidden),
1575 ## hid = l.#hidden, maillist = text(l.#maillist),
1576 ## group = text(l.#group), gid = text(l.#gid),
1577 ## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1578 ## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1579 ## modwith =l.#modwith)
1580 ## where l.list_id = @id
1582 if (atoi(gid) == -1)
1583 argv[6] = UNIQUE_GID;
1585 if (!strcmp(acl_type, "LIST")) {
1586 ## repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1587 ## inquire_equel(rowcount = "rowcount")
1589 strcpy(acl_name, "???");
1590 } else if (!strcmp(acl_type, "USER")) {
1591 ## repeat retrieve (acl_name = users.#login)
1592 ## where users.users_id = @acl_id
1593 ## inquire_equel(rowcount = "rowcount")
1595 strcpy(acl_name, "???");
1596 } else if (!strcmp(acl_type, "NONE")) {
1597 strcpy(acl_name, "NONE");
1599 strcpy(acl_name, "???");
1601 ## repeat retrieve (modby = users.login) where users.users_id = @modby_id
1602 ## inquire_equel(rowcount = "rowcount")
1604 sprintf(modby, "#%d", id);
1606 sms_trim_args(q->vcnt, argv);
1608 (*action)(q->vcnt, argv, actarg);
1612 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1613 ## where tblstats.#table = "list"
1615 return (SMS_SUCCESS);
1619 /* get_ace_use - given a type and a name, return a type and a name.
1620 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1621 * and argv[1] will contain the ID of the entity in question. The R*
1622 * types mean to recursively look at every containing list, not just
1623 * when the object in question is a direct member. On return, the
1624 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1627 int get_ace_use(q, argv, cl, action, actarg)
1636 ## int aid, listid, id;
1637 struct save_queue *sq, *sq_create();
1640 aid = *(int *)argv[1];
1641 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER")) {
1642 return(get_ace_internal(atype, aid, action, actarg));
1646 if (!strcmp(atype, "RLIST")) {
1647 sq_save_data(sq, aid);
1648 /* get all the list_id's of containing lists */
1649 ## range of m is members
1650 while (sq_get_data(sq, &id)) {
1651 ## repeat retrieve (listid = m.list_id)
1652 ## where m.member_type = "LIST" and m.member_id = @id {
1653 sq_save_unique_data(sq, listid);
1656 /* now process each one */
1657 while (sq_get_data(sq, &id)) {
1658 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1663 if (!strcmp(atype, "RUSER")) {
1664 ## range of m is members
1665 ## repeat retrieve (listid = m.list_id)
1666 ## where m.member_type = "USER" and m.member_id = @aid {
1667 sq_save_data(sq, listid);
1669 /* get all the list_id's of containing lists */
1670 while (sq_get_data(sq, &id)) {
1671 ## repeat retrieve (listid = m.list_id)
1672 ## where m.member_type = "LIST" and m.member_id = @id {
1673 sq_save_unique_data(sq, listid);
1676 /* now process each one */
1677 while (sq_get_data(sq, &id)) {
1678 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1681 if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1686 if (!found) return(SMS_NO_MATCH);
1687 return(SMS_SUCCESS);
1691 /* This looks up a single list or user for ace use. atype must be "USER"
1692 * or "LIST", and aid is the ID of the corresponding object. This is used
1693 * by get_ace_use above.
1696 ##get_ace_internal(atype, aid, action, actarg)
1707 if (!strcmp(atype, "LIST")) {
1708 rargv[0] = "FILESYS";
1709 ## repeat retrieve (name = filesys.label)
1710 ## where filesys.owners = @aid {
1711 (*action)(2, rargv, actarg);
1716 ## repeat retrieve (name = capacls.capability)
1717 ## where capacls.list_id = @aid {
1718 (*action)(2, rargv, actarg);
1721 } else if (!strcmp(atype, "USER")) {
1722 rargv[0] = "FILESYS";
1723 ## repeat retrieve (name = filesys.label)
1724 ## where filesys.owner = @aid {
1725 (*action)(2, rargv, actarg);
1731 ## repeat retrieve (name = list.#name)
1732 ## where list.acl_type = @atype and list.acl_id = @aid {
1733 (*action)(2, rargv, actarg);
1737 rargv[0] = "SERVICE";
1738 ## repeat retrieve (name = servers.#name)
1739 ## where servers.acl_type = @atype and servers.acl_id = @aid {
1740 (*action)(2, rargv, actarg);
1744 rargv[0] = "HOSTACCESS";
1745 ## repeat retrieve (name = machine.#name)
1746 ## where machine.mach_id = hostaccess.mach_id and
1747 ## hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1748 (*action)(2, rargv, actarg);
1751 rargv[0] = "ZEPHYR";
1752 ## repeat retrieve (name = zephyr.class)
1753 ## where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
1754 ## zephyr.sub_type = @atype and zephyr.sub_id = @aid or
1755 ## zephyr.iws_type = @atype and zephyr.iws_id = @aid or
1756 ## zephyr.iui_type = @atype and zephyr.iui_id = @aid {
1757 (*action)(2, rargv, actarg);
1761 if (!found) return(SMS_NO_MATCH);
1762 return(SMS_SUCCESS);
1766 /* get_lists_of_member - given a type and a name, return the name and flags
1767 * of all of the lists of the given member. The member_type is one of
1768 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1769 * and argv[1] will contain the ID of the entity in question. The R*
1770 * types mean to recursively look at every containing list, not just
1771 * when the object in question is a direct member.
1774 int get_lists_of_member(q, argv, cl, action, actarg)
1783 ## int aid, listid, id;
1784 struct save_queue *sq, *sq_create();
1787 aid = *(int *)argv[1];
1788 if (!strcmp(atype, "LIST") ||
1789 !strcmp(atype, "USER") ||
1790 !strcmp(atype, "STRING")) {
1791 return(glom_internal(atype, aid, action, actarg));
1795 if (!strcmp(atype, "RLIST")) {
1796 sq_save_data(sq, aid);
1797 /* get all the list_id's of containing lists */
1798 ## range of m is members
1799 while (sq_get_data(sq, &id)) {
1800 ## repeat retrieve (listid = m.list_id)
1801 ## where m.member_type = "LIST" and m.member_id = @id {
1802 sq_save_unique_data(sq, listid);
1805 /* now process each one */
1806 while (sq_get_data(sq, &id)) {
1807 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1812 if (!strcmp(atype, "RUSER")) {
1813 ## range of m is members
1814 ## repeat retrieve (listid = m.list_id)
1815 ## where m.member_type = "USER" and m.member_id = @aid {
1816 sq_save_data(sq, listid);
1818 /* get all the list_id's of containing lists */
1819 while (sq_get_data(sq, &id)) {
1820 ## repeat retrieve (listid = m.list_id)
1821 ## where m.member_type = "LIST" and m.member_id = @id {
1822 sq_save_unique_data(sq, listid);
1825 /* now process each one */
1826 while (sq_get_data(sq, &id)) {
1827 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1830 if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1834 if (!strcmp(atype, "RSTRING")) {
1835 ## range of m is members
1836 ## repeat retrieve (listid = m.list_id)
1837 ## where m.member_type = "STRING" and m.member_id = @aid {
1838 sq_save_data(sq, listid);
1840 /* get all the list_id's of containing lists */
1841 while (sq_get_data(sq, &id)) {
1842 ## repeat retrieve (listid = m.list_id)
1843 ## where m.member_type = "LIST" and m.member_id = @id {
1844 sq_save_unique_data(sq, listid);
1847 /* now process each one */
1848 while (sq_get_data(sq, &id)) {
1849 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1852 if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
1856 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1857 ## where tblstats.#table = "members"
1859 if (!found) return(SMS_NO_MATCH);
1860 return(SMS_SUCCESS);
1864 /* This looks up a single list, user, or string as a member. atype must be
1865 * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
1866 * This is used by get_lists_of_members above.
1869 ##glom_internal(atype, aid, action, actarg)
1877 ## char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
1883 rargv[4] = maillist;
1885 ## repeat retrieve (name = list.#name, active = text(list.#active),
1886 ## public = text(list.#public), hidden = text(list.#hidden),
1887 ## maillist = text(list.#maillist), group = text(list.#group))
1888 ## where list.list_id = m.list_id and
1889 ## m.member_type = @atype and m.member_id = @aid {
1890 (*action)(6, rargv, actarg);
1894 if (!found) return(SMS_NO_MATCH);
1895 return(SMS_SUCCESS);
1899 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1900 * the five flags associated with each list. It will return the name of
1901 * each list that meets the quailifications. It does this by building a
1902 * where clause based on the arguments, then doing a retrieve.
1905 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
1907 int qualified_get_lists(q, argv, cl, action, actarg)
1914 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
1915 "l", "name", lflags));
1919 /** get_members_of_list - optimized query for retrieval of list members
1922 ** argv[0] - list_id
1925 ** - retrieve USER members, then LIST members, then STRING members
1928 get_members_of_list(q, argv, cl, action, actarg)
1936 ## char member_name[129];
1939 list_id = *(int *)argv[0];
1941 targv[1] = member_name;
1943 ## range of m is members
1944 ## repeat retrieve (member_name = users.login)
1945 ## where m.#list_id = @list_id and m.member_type = "USER"
1946 ## and m.member_id = users.users_id
1947 ## sort by #member_name
1949 (*action)(2, targv, actarg);
1953 ## repeat retrieve (member_name = list.name)
1954 ## where m.#list_id = @list_id and m.member_type = "LIST"
1955 ## and m.member_id = list.#list_id
1956 ## sort by #member_name
1958 (*action)(2, targv, actarg);
1961 targv[0] = "STRING";
1962 ## repeat retrieve (member_name = strings.string)
1963 ## where m.#list_id = @list_id and m.member_type = "STRING"
1964 ## and m.member_id = strings.string_id
1965 ## sort by #member_name
1967 (*action)(2, targv, actarg);
1970 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1971 ## where tblstats.#table = "members"
1972 return(SMS_SUCCESS);
1976 /* count_members_of_list: this is a simple query, but it cannot be done
1977 * through the dispatch table.
1980 int count_members_of_list(q, argv, cl, action, actarg)
1987 ## int list, ct = 0;
1988 char *rargv[1], countbuf[5];
1990 list = *(int *)argv[0];
1991 rargv[0] = countbuf;
1992 ## repeat retrieve (ct = count(members.list_id where members.list_id = @list))
1993 sprintf(countbuf, "%d", ct);
1994 (*action)(1, rargv, actarg);
1995 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1996 ## where tblstats.#table = "members"
1997 return(SMS_SUCCESS);
2001 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2002 * the three flags associated with each service. It will return the name of
2003 * each service that meets the quailifications. It does this by building a
2004 * where clause based on the arguments, then doing a retrieve.
2007 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2009 int qualified_get_server(q, argv, cl, action, actarg)
2016 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2017 "s", "name", sflags));
2021 /* generic qualified get routine, used by qualified_get_lists,
2022 * qualified_get_server, and qualified_get_serverhost.
2024 * start - a simple where clause, must not be empty
2025 * range - the name of the range variable
2026 * field - the field to return
2027 * flags - an array of strings, names of the flag variables
2030 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2040 ## char name[33], qual[256], *rvar, *rtbl, *rfield;
2041 char *rargv[1], buf[32];
2044 strcpy(qual, start);
2045 for (i = 0; i < q->argc; i++) {
2046 if (!strcmp(argv[i], "TRUE")) {
2047 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2048 (void) strcat(qual, buf);
2049 } else if (!strcmp(argv[i], "FALSE")) {
2050 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2051 (void) strcat(qual, buf);
2059 ## range of rvar is rtbl
2060 ## retrieve (name = rvar.rfield) where qual {
2061 (*action)(1, rargv, actarg);
2063 ## inquire_equel(rowcount = "rowcount")
2064 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2065 ## where tblstats.#table = @rtbl
2067 return(SMS_NO_MATCH);
2068 return(SMS_SUCCESS);
2072 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2073 * the five flags associated with each serverhost. It will return the name of
2074 * each service and host that meets the quailifications. It does this by
2075 * building a where clause based on the arguments, then doing a retrieve.
2078 static char *shflags[6] = { "service", "enable", "override", "success",
2079 "inprogress", "hosterror" };
2081 int qualified_get_serverhost(q, argv, cl, action, actarg)
2088 ## char sname[33], mname[33], qual[256];
2089 char *rargv[2], buf[32];
2092 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2094 for (i = 1; i < q->argc; i++) {
2095 if (!strcmp(argv[i], "TRUE")) {
2096 sprintf(buf, " and sh.%s != 0", shflags[i]);
2098 } else if (!strcmp(argv[i], "FALSE")) {
2099 sprintf(buf, " and sh.%s = 0", shflags[i]);
2106 ## range of sh is serverhosts
2107 ## retrieve (sname = sh.service, mname = machine.name) where qual {
2108 (*action)(2, rargv, actarg);
2110 ## inquire_equel(rowcount = "rowcount")
2111 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2112 ## where tblstats.#table = "serverhosts"
2114 return(SMS_NO_MATCH);
2115 return(SMS_SUCCESS);
2119 /* register_user - change user's login name and allocate a pobox, group,
2120 * filesystem, and quota for them. The user's status must start out as 0,
2121 * and is left as 2. Arguments are: user's UID, new login name, and user's
2122 * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY,
2123 * SMS_FS_STAFF, SMS_FS_MISC).
2126 register_user(q, argv, cl)
2131 ## char *login, dir[65], *entity, *directory, machname[33];
2132 ## int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2133 ## int size, alloc, pid, m_id;
2136 entity = cl->entity;
2139 uid = atoi(argv[0]);
2141 utype = atoi(argv[2]);
2143 ## range of u is users
2144 ## range of l is list
2145 ## range of sh is serverhosts
2146 ## range of n is nfsphys
2147 ## range of m is machine
2150 ## repeat retrieve (users_id = u.#users_id)
2151 ## where u.#uid = @uid and u.status = 0
2152 ## inquire_equel(rowcount = "rowcount");
2154 return(SMS_NO_MATCH);
2156 return(SMS_NOT_UNIQUE);
2158 /* check new login name */
2159 ## repeat retrieve (flag = any(u.#login where u.#login = @login))
2162 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2165 ## repeat retrieve (flag = any(filesys.#name where filesys.#name = @login))
2168 com_err(whoami, 0, "new login name OK");
2170 /* choose place for pobox, put in mid */
2171 ## repeat retrieve (mid = sh.mach_id, machname = m.name)
2172 ## where sh.service = "POP" and m.mach_id = sh.mach_id and
2173 ## sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2174 ## inquire_equel(rowcount = "rowcount");
2176 return(SMS_NO_POBOX);
2178 /* change login name, set pobox */
2179 ## repeat replace u (#login = @login, status = 2, modtime = "now",
2180 ## modby = @who, modwith = @entity, potype="POP",
2181 ## pop_id = @mid, pmodtime="now", pmodby=@who,
2182 ## pmodwith=@entity)
2183 ## where u.#users_id = @users_id
2184 ## inquire_equel(rowcount = "rowcount");
2186 return(SMS_INTERNAL);
2187 set_pop_usage(mid, 1);
2188 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2191 /* create group list */
2192 if (set_next_object_id("gid", "list"))
2194 if (set_next_object_id("list_id", "list"))
2196 ## repeat retrieve (list_id = values.value) where values.name = "list_id"
2197 ## inquire_equel(rowcount = "rowcount");
2199 return(SMS_INTERNAL);
2200 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2201 ## public = 0, hidden = 0, maillist = 0, group = 1,
2202 ## #gid = values.value, desc = "User Group",
2203 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2204 ## modby = @who, modwith = @entity)
2205 ## where values.name = "gid"
2206 ## inquire_equel(rowcount = "rowcount");
2208 return(SMS_INTERNAL);
2209 ## repeat append members (#list_id = @list_id, member_type = "USER",
2210 ## member_id = @users_id)
2211 ## inquire_equel(rowcount = "rowcount");
2213 return(SMS_INTERNAL);
2214 com_err(whoami, 0, "group list created");
2216 /* decide where to put filesystem */
2219 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2220 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2221 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2222 maxsize = size - alloc;
2225 directory = strsave(dir);
2231 return(SMS_NO_FILESYS);
2233 /* create filesystem */
2234 if (set_next_object_id("filsys_id", "filesys"))
2236 ## repeat append filesys (filsys_id = values.value, phys_id = @pid,
2237 ## label = @login, type = "NFS", mach_id = @m_id,
2238 ## name = @directory + "/" + @login,
2239 ## mount = "/mit/" + @login,
2240 ## access = "w", comments = "User Locker",
2241 ## owner = @users_id, owners = @list_id, createflg = 1,
2242 ## lockertype = "HOMEDIR", modtime = "now",
2243 ## modby = @who, modwith = @entity)
2244 ## where values.name = "filsys_id"
2245 ## inquire_equel(rowcount = "rowcount");
2247 return(SMS_INTERNAL);
2248 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2252 ## repeat retrieve (quota = values.value) where values.name = "def_quota"
2253 ## inquire_equel(rowcount = "rowcount");
2255 return(SMS_NO_QUOTA);
2256 ## repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2257 ## #quota = @quota, modtime = "now", modby = @who,
2258 ## modwith = @entity)
2259 ## where values.name = "filsys_id"
2260 ## inquire_equel(rowcount = "rowcount");
2262 return(SMS_INTERNAL);
2263 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2264 ## where nfsphys.nfsphys_id = filesys.#phys_id and
2265 ## filesys.filsys_id = values.value and values.name = "filsys_id"
2266 ## inquire_equel(rowcount = "rowcount");
2268 return(SMS_INTERNAL);
2269 com_err(whoami, 0, "quota of %d assigned", quota);
2271 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2272 ## where tblstats.table = "users"
2273 ## repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2274 ## where tblstats.table = "list" or tblstats.table = "filesys" or
2275 ## tblstats.table = "nfsquota"
2276 return(SMS_SUCCESS);
2281 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2285 ** delta (will be +/- 1)
2288 ** - incr/decr value field in serverhosts table for pop/mach_id
2292 static int set_pop_usage(id, count)
2296 ## int mach_id = id;
2299 ## range of sh is serverhosts
2300 ## repeat replace sh (value1 = sh.value1 + @n)
2301 ## where sh.service = "POP" and sh.#mach_id = @mach_id
2303 return(SMS_SUCCESS);
2308 /* Validation Routines */
2310 validate_row(q, argv, v)
2311 register struct query *q;
2313 register struct validate *v;
2321 /* build where clause */
2322 build_qual(v->qual, v->argc, argv, qual);
2324 /* setup ingres variables */
2329 if (log_flags & LOG_VALID)
2330 /* tell the logfile what we're doing */
2331 com_err(whoami, 0, "validating row: %s", qual);
2333 /* look for the record */
2334 ## range of rvar is table
2335 ## retrieve (rowcount = count(rvar.name where qual))
2336 if (rowcount == 0) return(SMS_NO_MATCH);
2337 if (rowcount > 1) return(SMS_NOT_UNIQUE);
2341 validate_fields(q, argv, vo, n)
2343 register char *argv[];
2344 register struct valobj *vo;
2347 register int status;
2352 if (log_flags & LOG_VALID)
2353 com_err(whoami, 0, "validating %s in %s: %s",
2354 vo->namefield, vo->table, argv[vo->index]);
2355 status = validate_name(argv, vo);
2359 if (log_flags & LOG_VALID)
2360 com_err(whoami, 0, "validating %s in %s: %s",
2361 vo->idfield, vo->table, argv[vo->index]);
2362 status = validate_id(argv, vo);
2366 if (log_flags & LOG_VALID)
2367 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2368 status = validate_date(argv, vo);
2372 if (log_flags & LOG_VALID)
2373 com_err(whoami, 0, "validating %s type: %s",
2374 vo->table, argv[vo->index]);
2375 status = validate_type(argv, vo);
2379 if (log_flags & LOG_VALID)
2380 com_err(whoami, 0, "validating typed data (%s): %s",
2381 argv[vo->index - 1], argv[vo->index]);
2382 status = validate_typedata(q, argv, vo);
2386 if (log_flags & LOG_VALID)
2387 com_err(whoami, 0, "validating rename %s in %s",
2388 argv[vo->index], vo->table);
2389 status = validate_rename(argv, vo);
2393 if (log_flags & LOG_VALID)
2394 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2395 status = validate_chars(argv[vo->index]);
2399 status = SMS_EXISTS;
2404 if (status != SMS_EXISTS) return(status);
2408 return(SMS_SUCCESS);
2412 /* validate_chars: verify that there are no illegal characters in
2413 * the string. Legal characters are printing chars other than
2414 * ", *, ?, \, [ and ].
2416 static int illegalchars[] = {
2417 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2418 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2419 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2420 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2421 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2422 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2423 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2424 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
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,
2427 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2428 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2429 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2430 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
2439 if (illegalchars[*s++])
2440 return(SMS_BAD_CHAR);
2445 validate_id(argv, vo)
2447 register struct valobj *vo;
2457 name = argv[vo->index];
2459 /* minor kludge to upcasify machine names */
2460 if (!strcmp(table, "machine"))
2461 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2462 namefield = vo->namefield;
2463 idfield = vo->idfield;
2464 if (!strcmp(namefield, "uid")) {
2465 ## retrieve (id = table.idfield) where table.namefield = int4(name)
2466 ## inquire_equel (rowcount = "rowcount")
2468 ## retrieve (id = table.idfield) where table.namefield = name
2469 ## inquire_equel (rowcount = "rowcount")
2471 if (rowcount != 1) return(vo->error);
2472 *(int *)argv[vo->index] = id;
2476 validate_name(argv, vo)
2478 register struct valobj *vo;
2486 name = argv[vo->index];
2488 namefield = vo->namefield;
2489 if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2490 for (c = name; *c; c++)
2494 ## retrieve (rowcount = countu(table.namefield
2495 ## where table.namefield = name))
2496 return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2499 validate_date(argv, vo)
2507 idate = argv[vo->index];
2509 ## retrieve (dd = interval("years", date(idate) - date("today")))
2510 ## inquire_equel (errorno = "errorno")
2511 if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2516 validate_rename(argv, vo)
2520 ## char *name, *table, *namefield, *idfield;
2524 c = name = argv[vo->index];
2526 if (illegalchars[*c++])
2527 return(SMS_BAD_CHAR);
2529 /* minor kludge to upcasify machine names */
2530 if (!strcmp(table, "machine"))
2531 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2532 namefield = vo->namefield;
2533 idfield = vo->idfield;
2536 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2538 ## retrieve (id = any(table.namefield where table.namefield = name))
2544 ## retrieve (id = table.idfield) where table.namefield = name
2545 if (id == -1 || id == *(int *)argv[vo->index - 1])
2552 validate_type(argv, vo)
2554 register struct valobj *vo;
2561 typename = vo->table;
2562 c = value = argv[vo->index];
2564 if (illegalchars[*c++])
2565 return(SMS_BAD_CHAR);
2567 /* uppercase type fields */
2568 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2570 ## range of a is alias
2571 ## repeat retrieve (exists = any(a.trans where a.name = @typename and
2572 ## a.type = "TYPE" and
2573 ## a.trans = @value))
2574 return (exists ? SMS_EXISTS : vo->error);
2577 /* validate member or type-specific data field */
2579 validate_typedata(q, argv, vo)
2580 register struct query *q;
2581 register char *argv[];
2582 register struct valobj *vo;
2585 ## char *field_type;
2586 ## char data_type[129];
2592 /* get named object */
2593 name = argv[vo->index];
2595 /* get field type string (known to be at index-1) */
2596 field_type = argv[vo->index-1];
2598 /* get corresponding data type associated with field type name */
2599 ## repeat retrieve (data_type = alias.trans)
2600 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
2601 ## inquire_equel (rowcount = "rowcount")
2602 if (rowcount != 1) return(SMS_TYPE);
2604 /* now retrieve the record id corresponding to the named object */
2605 if (index(data_type, ' '))
2606 *index(data_type, ' ') = 0;
2607 if (!strcmp(data_type, "user")) {
2609 ## repeat retrieve (id = users.users_id) where users.login = @name
2610 ## inquire_equel (rowcount = "rowcount")
2611 if (rowcount != 1) return(SMS_USER);
2613 } else if (!strcmp(data_type, "list")) {
2615 ## repeat retrieve (id = list.list_id) where list.#name = @name
2616 ## inquire_equel (rowcount = "rowcount")
2617 if (rowcount != 1) {
2618 /* if idfield is non-zero, then if argv[0] matches the string
2619 * that we're trying to resolve, we should get the value of
2620 * values.[idfield] for the id.
2622 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2623 set_next_object_id(q->validate->object_id, q->rtable);
2625 ## repeat retrieve (id = values.value) where values.#name = @name
2626 ## inquire_equel(rowcount = "rowcount")
2627 if (rowcount != 1) return(SMS_LIST);
2631 } else if (!strcmp(data_type, "machine")) {
2633 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2634 ## repeat retrieve (id = machine.mach_id) where machine.#name = @name
2635 ## inquire_equel (rowcount = "rowcount")
2636 if (rowcount != 1) return(SMS_MACHINE);
2638 } else if (!strcmp(data_type, "string")) {
2640 ## range of s is strings
2641 ## repeat retrieve (id = s.string_id) where s.string = @name
2642 ## inquire_equel (rowcount = "rowcount")
2643 if (rowcount == 0) {
2644 if (q->type != APPEND) return(SMS_STRING);
2645 ## range of v is values
2646 ## retrieve (id = v.value) where v.#name = "strings_id"
2648 ## replace v (value = id) where v.#name = "strings_id"
2649 ## append to strings (string_id = id, string = name)
2651 } else if (!strcmp(data_type, "none")) {
2657 /* now set value in argv */
2658 *(int *)argv[vo->index] = id;
2660 return (SMS_EXISTS);
2664 /* This looks up a login name and returns the SMS internal ID. It is used
2665 * by authenticate to put the users_id in the client structure.
2668 int get_users_id(name)
2671 ## int id, rowcount;
2676 ## range of u is users
2677 ## repeat retrieve (id = u.#users_id) where u.#login = @login
2678 ## inquire_equel (rowcount = "rowcount")
2687 /* Check the database at startup time. For now this just resets the
2688 * inprogress flags that the DCM uses.
2691 sanity_check_database()