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();
20 extern int ingres_errno;
23 /* Specialized Access Routines */
25 /* access_user - verify that client name equals specified login name
27 * - since field validation routines are called first, a users_id is
28 * now in argv[0] instead of the login name.
31 access_user(q, argv, cl)
36 if (cl->users_id != *(int *)argv[0])
44 /* access_login - verify that client name equals specified login name
46 * argv[0...n] contain search info. q->
49 access_login(q, argv, cl)
57 build_qual(q->qual, q->argc, argv, qual);
58 ## retrieve (id = u.users_id) where qual
59 ## inquire_equel(rowcount = "rowcount")
60 if (rowcount != 1 || id != cl->users_id)
68 /* access_list - check access for most list operations
70 * Inputs: argv[0] - list_id
72 * argv[2] - member ID (only for queries "amtl" and "dmfl")
73 * argv[7] - group IID (only for query "ulis")
76 * - check that client is a member of the access control list
77 * - OR, if the query is add_member_to_list or delete_member_from_list
78 * and the list is public, allow access if client = member
81 access_list(q, argv, cl)
86 ## int list_id, acl_id, flags, rowcount, gid;
89 int client_id, status;
91 list_id = *(int *)argv[0];
92 ## repeat retrieve (acl_id = list.#acl_id, acl_type = list.#acl_type,
93 ## gid = list.#gid, flags = list.#public)
94 ## where list.#list_id = @list_id
95 ## inquire_equel(rowcount = "rowcount")
99 /* parse client structure */
100 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
103 /* if amtl or dmfl and list is public allow client to add or delete self */
104 if ((!strcmp("amtl", q->shortname) || !strcmp("dmfl", q->shortname)) &&
105 (flags && !strcmp("USER", argv[1]))) {
106 if (*(int *)argv[2] == client_id) return(SMS_SUCCESS);
107 /* if update_list, don't allow them to change the GID */
108 } else if (!strcmp("ulis", q->shortname)) {
109 if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
110 (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
114 /* check for client in access control list */
115 status = find_member(acl_type, acl_id, client_type, client_id, 0);
116 if (!status) return(SMS_PERM);
122 /* access_visible_list - allow access to list only if it is not hidden,
123 * or if the client is on the ACL
125 * Inputs: argv[0] - list_id
126 * cl - client identifier
129 access_visible_list(q, argv, cl)
134 ## int list_id, acl_id, flags, rowcount;
137 int client_id, status;
139 list_id = *(int *)argv[0];
140 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
141 ## acl_type = list.#acl_type) where list.#list_id = @list_id
142 ## inquire_equel(rowcount = "rowcount")
144 return(SMS_INTERNAL);
148 /* parse client structure */
149 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
152 /* check for client in access control list */
153 status = find_member(acl_type, acl_id, client_type, client_id, 0);
161 /* access_vis_list_by_name - allow access to list only if it is not hidden,
162 * or if the client is on the ACL
164 * Inputs: argv[0] - list name
165 * cl - client identifier
168 access_vis_list_by_name(q, argv, cl)
173 ## int acl_id, flags, rowcount;
174 ## char acl_type[9], *listname;
176 int client_id, status;
179 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
180 ## acl_type = list.#acl_type) where list.#name = @listname
181 ## inquire_equel(rowcount = "rowcount");
183 return(SMS_WILDCARD);
185 return(SMS_NO_MATCH);
189 /* parse client structure */
190 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
193 /* check for client in access control list */
194 status = find_member(acl_type, acl_id, client_type, client_id, 0);
202 /* access_member - allow user to access member of type "USER" and name matches
203 * username, or to access member of type "LIST" and list is one that user is
204 * on the acl of, or the list is visible.
207 access_member(q, argv, cl)
212 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
213 return(access_visible_list(q, &argv[1], cl));
215 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
216 if (cl->users_id == *(int *)argv[1])
224 /* access_qgli - special access routine for Qualified_get_lists. Allows
225 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
228 access_qgli(q, argv, cl)
233 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
239 /* access_service - allow access if user is on ACL of service. Don't
240 * allow access if a wildcard is used.
243 access_service(q, argv, cl)
248 ## int acl_id, rowcount;
249 ## char *name, acl_type[9];
250 int client_id, status;
254 ## repeat retrieve (acl_id = servers.#acl_id, acl_type = servers.#acl_type)
255 ## where servers.#name = uppercase(@name)
256 ## inquire_equel(rowcount = "rowcount")
260 /* parse client structure */
261 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
264 /* check for client in access control list */
265 status = find_member(acl_type, acl_id, client_type, client_id, 0);
266 if (!status) return(SMS_PERM);
273 /* access_filesys - verify that client is owner or on owners list of filesystem
277 access_filesys(q, argv, cl)
282 ## int rowcount, users_id, list_id;
284 int status, client_id;
288 ## repeat retrieve (users_id = filesys.owner, list_id = filesys.owners)
289 ## where filesys.label = @name
290 ## inquire_equel(rowcount = "rowcount")
294 if (users_id == cl->users_id)
296 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
298 status = find_member("LIST", list_id, client_type, client_id, 0);
308 /* Setup routine for add_user
310 * Inputs: argv[0] - login
315 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
316 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
319 setup_ausr(q, argv, cl)
321 register char *argv[];
324 ## int nuid, rowcount;
326 if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
327 if (set_next_object_id("uid", "users"))
328 return(SMS_INGRES_ERR);
329 ## repeat retrieve (nuid = values.value) where values.name = "uid"
330 ## inquire_equel(rowcount = "rowcount")
332 return(SMS_INTERNAL);
333 sprintf(argv[1], "%d", nuid);
336 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
337 sprintf(argv[0], "#%s", argv[1]);
344 /* setup_dusr - verify that the user is no longer being referenced
345 * and may safely be deleted.
348 int setup_dusr(q, argv)
354 id = *(int *)argv[0];
356 /* For now, only allow users to be deleted if their status is 0 */
357 ## repeat retrieve (flag = u.status) where u.users_id = @id
361 ## repeat delete nfsquota where nfsquota.users_id = @id
362 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
363 ## and members.member_type = "USER"))
366 ## repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
369 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
370 ## list.acl_type = "USER"))
373 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
374 ## servers.acl_type = "USER"))
377 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
378 ## hostaccess.acl_type = "USER"))
386 /* setup_spop: verify that there is already a valid POP machine_id in the
387 * pop_id field. Also take care of keeping track of the post office usage.
389 int setup_spop(q, argv)
393 ## int id, mid, flag;
396 id = *(int *)argv[0];
397 ## repeat retrieve (type = u.potype, mid = u.pop_id,
398 ## flag = any(machine.name where machine.mach_id = u.pop_id
399 ## and u.pop_id != 0 and u.users_id = @id))
400 ## where u.users_id = @id
403 if (strcmp(strtrim(type), "POP"))
404 set_pop_usage(mid, 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(strtrim(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(printcap.mach_id where printcap.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));
663 /* Verify the arguments, depending on the FStype. Also, if this is an
664 * NFS filesystem, then update any quotas for that filesystem to reflect
673 char *type, *name, *access;
677 mach_id = *(int *)argv[3];
682 if (!strcmp(type, "NFS")) {
683 status = check_nfs(mach_id, name, access);
684 fid = *(int *)argv[0];
685 ## replace nfsquota (phys_id = var_phys_id) where nfsquota.filsys_id = fid
692 /* Find the NFS physical partition that the named directory is on.
693 * This is done by comparing the dir against the mount point of the
694 * partition. To make sure we get the correct match when there is
695 * more than one, we sort the query in reverse order by dir name.
698 ##check_nfs(mach_id, name, access)
709 caccess = (isupper(*access)) ? tolower(*access) : *access;
710 if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
713 ## range of np is nfsphys
714 ## repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
715 ## where np.#mach_id = @mach_id sort by #dir:d {
719 if (*cp1++ != *cp2) break;
723 status = SMS_SUCCESS;
732 /* setup_dfil: free any quota records associated with a filesystem
733 * when it is deleted.
736 setup_dfil(q, argv, cl)
743 id = *(int *)argv[0];
744 ## range of q is nfsquota
745 ## range of fs is filesys
746 ## range of n is nfsphys
747 ## repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
748 ## where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
750 ## repeat delete q where q.filsys_id = @id
755 /* setup_dnfp: check to see that the nfs physical partition does not have
756 * any filesystems assigned to it before allowing it to be deleted.
759 setup_dnfp(q, argv, cl)
766 id = *(int *)argv[0];
767 ## repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
774 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
775 * argv[0] = filsys_id
779 setup_dnfq(q, argv, cl)
784 ## int quota, fs, user;
786 fs = *(int *)argv[0];
787 user = *(int *)argv[1];
789 ## range of q is nfsquota
790 ## repeat retrieve (quota = q.#quota) where q.users_id = @user and
792 ## repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
793 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
799 /* FOLLOWUP ROUTINES */
801 /* generic set_modtime routine. This takes the table name from the query,
802 * and will update the modtime, modby, and modwho fields in the entry in
803 * the table whose name field matches argv[0].
806 set_modtime(q, argv, cl)
811 ## char *name, *entity, *table;
819 ## replace table (modtime = "now", modby = who, modwith = entity)
820 ## where table.#name = name
824 /* generic set_modtime_by_id routine. This takes the table name from
825 * the query, and the id name from the validate record,
826 * and will update the modtime, modby, and modwho fields in the entry in
827 * the table whose id matches argv[0].
830 set_modtime_by_id(q, argv, cl)
835 ## char *entity, *table, *id_name;
841 id_name = q->validate->object_id;
843 id = *(int *)argv[0];
844 ## replace table (modtime = "now", modby = who, modwith = entity)
845 ## where table.id_name = id
850 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
853 set_finger_modtime(q, argv, cl)
858 ## int users_id, who;
863 users_id = *(int *)argv[0];
865 ## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
866 ## where u.#users_id = @users_id
871 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
874 set_pobox_modtime(q, argv, cl)
879 ## int users_id, who;
884 users_id = *(int *)argv[0];
886 ## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
887 ## where users.#users_id = @users_id
892 /* Sets the modtime on a machine record. The machine name is in argv[0].
893 * This routine is different from the generic set_modtime in that the
894 * name is uppercased first.
897 set_mach_modtime(q, argv, cl)
902 ## char *host, *entity;
909 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
910 ## where m.name = uppercase(@host)
915 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
916 * is necessary for add_machine_to_cluster becuase the table that query
917 * operates on is "mcm", not "machine".
920 set_mach_modtime_by_id(q, argv, cl)
931 id = *(int *)argv[0];
932 ## range of m is machine
933 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
934 ## where m.mach_id = @id
939 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
940 * is necessary for add_cluster_data and delete_cluster_data becuase the
941 * table that query operates on is "svc", not "cluster".
944 set_cluster_modtime_by_id(q, argv, cl)
955 id = *(int *)argv[0];
956 ## range of c is cluster
957 ## repeat replace c (modtime = "now", modby = @who, modwith = @entity)
958 ## where c.clu_id = @id
963 /* sets the modtime on the serverhost where the service name is in argv[0]
964 * and the mach_id is in argv[1].
967 set_serverhost_modtime(q, argv, cl)
972 ## char *entity, *serv;
979 id = *(int *)argv[1];
980 ## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
981 ## where sh.service = uppercase(@serv) and sh.mach_id = @id
986 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
987 * directory name is in argv[1].
990 set_nfsphys_modtime(q, argv, cl)
995 ## char *entity, *dir;
1001 id = *(int *)argv[0];
1003 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1004 ## where np.#dir = @dir and np.mach_id = @id
1005 return(SMS_SUCCESS);
1009 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1013 set_filesys_modtime(q, argv, cl)
1018 ## char *label, *entity;
1021 entity = cl->entity;
1025 if (!strcmp(q->shortname, "ufil"))
1028 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1029 ## #phys_id = @var_phys_id) where fs.#label = @label
1030 return(SMS_SUCCESS);
1034 /* sets the modtime on a zephyr class, where argv[0] contains the class
1038 set_zephyr_modtime(q, argv, cl)
1043 ## char *class, *entity;
1046 entity = cl->entity;
1051 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1052 ## where z.#class = @class
1053 return(SMS_SUCCESS);
1057 /* fixes the modby field. This will be the second to last thing in the
1058 * argv, the argv length is determined from the query structure. It is
1059 * passed as a pointer to an integer. This will either turn it into a
1060 * username, or # + the users_id.
1062 followup_fix_modby(q, sq, v, action, actarg, cl)
1064 register struct save_queue *sq;
1066 register int (*action)();
1067 register int actarg;
1071 char **argv, *malloc();
1072 ## int id, rowcount;
1076 while (sq_get_data(sq, &argv)) {
1079 argv[i] = malloc(9);
1081 ## repeat retrieve (name = users.login) where users.users_id = @id
1082 ## inquire_equel(rowcount = "rowcount")
1083 if (rowcount != 1) {
1084 sprintf(argv[i], "#%d", id);
1086 (*action)(q->vcnt, argv, actarg);
1087 for (j = 0; j < q->vcnt; j++)
1092 return(SMS_SUCCESS);
1097 ** followup_ausr - add finger and pobox entries, set_user_modtime
1100 ** argv[0] - login (add_user)
1101 ** argv[3] - last name
1102 ** argv[4] - first name
1103 ** argv[5] - middle name
1107 followup_ausr(q, argv, cl)
1113 ## char *login, *entity;
1114 ## char fullname[129];
1118 entity = cl->entity;
1120 /* build fullname */
1121 if (strlen(argv[4]) && strlen(argv[5]))
1122 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1123 else if (strlen(argv[4]))
1124 sprintf(fullname, "%s %s", argv[4], argv[3]);
1126 sprintf(fullname, "%s", argv[3]);
1128 /* create finger entry, pobox & set modtime on user */
1129 ## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1130 ## #fullname=@fullname, mit_affil = u.mit_year,
1131 ## fmodtime="now", fmodby=@who, fmodwith=@entity,
1132 ## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1133 ## where u.#login = @login
1135 return(SMS_SUCCESS);
1139 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1140 * type in argv[1]. Then completes the upcall to the user.
1142 * argv[2] is of the form "123:234" where the first integer is the machine
1143 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1144 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1148 followup_gpob(q, sq, v, action, actarg, cl)
1149 register struct query *q;
1150 register struct save_queue *sq;
1151 register struct validate *v;
1152 register int (*action)();
1156 char **argv, *index();
1158 ## char box[129], *name;
1159 ## int mid, sid, rowcount;
1162 while (sq_get_data(sq, &argv)) {
1163 sms_trim_args(2, argv);
1165 p = index(argv[2], ':');
1167 mid = atoi(argv[2]);
1171 if (!strcmp(ptype, "POP")) {
1172 ## repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1173 ## inquire_equel(rowcount = "rowcount")
1175 return(SMS_MACHINE);
1176 } else if (!strcmp(ptype, "SMTP")) {
1177 ## repeat retrieve (box=strings.string) where strings.string_id=@sid
1178 ## inquire_equel(rowcount = "rowcount")
1181 } else /* ptype == "NONE" */ {
1185 if (!strcmp(q->shortname, "gpob")) {
1186 sid = atoi(argv[4]);
1188 argv[4] = malloc(9);
1190 ## repeat retrieve (name = users.login) where users.users_id = @sid
1191 ## inquire_equel(rowcount = "rowcount")
1193 sprintf(name, "#%d", sid);
1197 (*action)(q->vcnt, argv, actarg);
1199 /* free saved data */
1206 return (SMS_SUCCESS);
1210 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1211 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1212 * proper name based on the type, and repace that string in the argv.
1213 * Also fixes the modby field by called followup_fix_modby.
1216 followup_glin(q, sq, v, action, actarg, cl)
1217 register struct query *q;
1218 register struct save_queue *sq;
1219 register struct validate *v;
1220 register int (*action)();
1224 char **argv, *malloc(), *realloc(), *type;
1226 ## int id, rowcount;
1230 if (!strcmp(q->shortname, "gsin"))
1233 while (sq_get_data(sq, &argv)) {
1234 sms_trim_args(q->vcnt, argv);
1236 id = atoi(argv[i = q->vcnt - 2]);
1238 name = argv[i] = malloc(9);
1239 ## repeat retrieve (name = users.login) where users.users_id = @id
1240 ## inquire_equel(rowcount = "rowcount")
1242 sprintf(argv[i], "#%d", id);
1244 id = atoi(argv[idx]);
1245 type = argv[idx - 1];
1246 if ((name = malloc(33)) == NULL)
1249 if (!strcmp(type, "LIST")) {
1250 ## repeat retrieve (name = list.#name) where list.list_id = @id
1251 ## inquire_equel(rowcount = "rowcount")
1253 strcpy(name, "???");
1254 } else if (!strcmp(type, "USER")) {
1255 ## repeat retrieve (name = users.login) where users.users_id = @id
1256 ## inquire_equel(rowcount = "rowcount")
1258 strcpy(name, "???");
1259 } else if (!strcmp(type, "NONE")) {
1260 strcpy(name, "NONE");
1262 strcpy(name, "???");
1266 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1267 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1268 strcpy(argv[6], UNIQUE_GID);
1272 (*action)(q->vcnt, argv, actarg);
1274 /* free saved data */
1275 for (i = 0; i < q->vcnt; i++)
1281 return (SMS_SUCCESS);
1285 /** followup_amtl - followup for amtl and dmfl; when adding a list
1286 ** member to a maillist, make member list a maillist also
1287 ** unless list is a user-group.
1288 ** Then set_list_modtime_by_id.
1291 ** argv[0] - list_id
1292 ** argv[1] - member_type
1293 ** argv[2] - member_id
1297 followup_amtl(q, argv, cl)
1307 list_id = *(int *)argv[0];
1308 entity = cl->entity;
1311 ## range of l is list
1312 ## repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1313 ## where l.#list_id = @list_id
1315 /* if query is not amtl or if member_type is not LIST then return */
1316 if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4))
1317 return(SMS_SUCCESS);
1319 member_id = *(int *)argv[2];
1321 /* is parent list a mailing list? */
1322 ## repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1324 return(SMS_SUCCESS);
1326 /* list is not a user-group; add list to maillist table */
1327 ## repeat replace l (maillist = 1) where l.#list_id = @member_id
1328 return(SMS_SUCCESS);
1332 /* followup_anfq: Add allocation to nfsphys after creating quota.
1333 * argv[0] = filsys_id
1334 * argv[2] = ascii(quota)
1337 followup_anfq(q, argv, cl)
1342 ## int quota, user, fs, who;
1345 fs = *(int *)argv[0];
1346 user = *(int *)argv[1];
1347 quota = atoi(argv[2]);
1349 entity = cl->entity;
1351 ## repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1352 ## where nq.filsys_id = @fs and nq.users_id = @user
1353 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1354 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1355 return(SMS_SUCCESS);
1362 followup_gzcl(q, sq, v, action, actarg, cl)
1363 register struct query *q;
1364 register struct save_queue *sq;
1365 register struct validate *v;
1366 register int (*action)();
1371 ## int rowcount, id;
1375 while (sq_get_data(sq, &argv)) {
1376 sms_trim_args(q->vcnt, argv);
1378 id = atoi(argv[i = q->vcnt - 2]);
1380 name = argv[i] = malloc(9);
1381 ## repeat retrieve (name = users.login) where users.users_id = @id
1382 ## inquire_equel(rowcount = "rowcount")
1384 sprintf(argv[i], "#%d", id);
1386 for (i = 1; i < 8; i+=2) {
1387 id = atoi(argv[i+1]);
1389 if ((name = argv[i+1] = malloc(33)) == NULL)
1391 if (!strcmp(argv[i], "LIST")) {
1392 ## repeat retrieve (name = list.#name) where list.list_id = @id
1393 ## inquire_equel(rowcount = "rowcount")
1395 strcpy(name, "???");
1396 } else if (!strcmp(argv[i], "USER")) {
1397 ## repeat retrieve (name = users.login) where users.users_id = @id
1398 ## inquire_equel(rowcount = "rowcount")
1400 strcpy(name, "???");
1401 } else if (!strcmp(argv[i], "NONE")) {
1402 strcpy(name, "NONE");
1404 strcpy(name, "???");
1409 (*action)(q->vcnt, argv, actarg);
1411 /* free saved data */
1412 for (i = 0; i < q->vcnt; i++)
1417 return(SMS_SUCCESS);
1424 followup_gsha(q, sq, v, action, actarg, cl)
1425 register struct query *q;
1426 register struct save_queue *sq;
1427 register struct validate *v;
1428 register int (*action)();
1433 ## int rowcount, id;
1437 while (sq_get_data(sq, &argv)) {
1438 sms_trim_args(q->vcnt, argv);
1442 name = argv[4] = malloc(9);
1443 ## repeat retrieve (name = users.login) where users.users_id = @id
1444 ## inquire_equel(rowcount = "rowcount")
1446 sprintf(argv[4], "#%d", id);
1450 if ((name = argv[2] = malloc(33)) == NULL)
1452 if (!strcmp(argv[1], "LIST")) {
1453 ## repeat retrieve (name = list.#name) where list.list_id = @id
1454 ## inquire_equel(rowcount = "rowcount")
1456 strcpy(name, "???");
1457 } else if (!strcmp(argv[1], "USER")) {
1458 ## repeat retrieve (name = users.login) where users.users_id = @id
1459 ## inquire_equel(rowcount = "rowcount")
1461 strcpy(name, "???");
1462 } else if (!strcmp(argv[1], "NONE")) {
1463 strcpy(name, "NONE");
1465 strcpy(name, "???");
1469 (*action)(q->vcnt, argv, actarg);
1471 /* free saved data */
1472 for (i = 0; i < q->vcnt; i++)
1477 return(SMS_SUCCESS);
1482 /* Special query routines */
1484 /* set_pobox - this does all of the real work.
1485 * argv = user_id, type, box
1486 * if type is POP, then box should be a machine, and its ID should be put in
1487 * pop_id. If type is SMTP, then box should be a string and its ID should
1488 * be put in box_id. If type is NONE, then box doesn't matter.
1491 int set_pobox(q, argv, cl)
1496 ## int user, id, rowcount;
1497 ## char *box, potype[9];
1500 user = *(int *)argv[0];
1502 ## repeat retrieve (id = users.pop_id, potype = users.#potype)
1503 ## where users.users_id = @user
1504 if (!strcmp(strtrim(potype), "POP"))
1505 set_pop_usage(id, -1);
1507 if (!strcmp(argv[1], "POP")) {
1508 ## repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1509 ## inquire_equel(rowcount = "rowcount")
1511 return(SMS_MACHINE);
1512 ## repeat replace users (#potype = "POP", pop_id = @id)
1513 ## where users.users_id = @user
1514 set_pop_usage(id, 1);
1515 } else if (!strcmp(argv[1], "SMTP")) {
1516 ## range of s is strings
1517 ## repeat retrieve (id = s.string_id) where s.string = @box
1518 ## inquire_equel (rowcount = "rowcount")
1519 if (rowcount == 0) {
1520 ## range of v is values
1521 ## repeat retrieve (id = v.value) where v.name = "strings_id"
1523 ## repeat replace v (value = @id) where v.name = "strings_id"
1524 ## append to strings (string_id = id, string = box)
1526 ## repeat replace users (#potype = "SMTP", box_id = @id)
1527 ## where users.users_id = @user
1528 } else /* argv[1] == "NONE" */ {
1529 ## repeat replace users (#potype = "NONE") where users.users_id = @user
1532 set_pobox_modtime(q, argv, cl);
1533 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1534 ## where tblstats.#table = "users"
1535 return(SMS_SUCCESS);
1539 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1540 * each list. This is tricky: first build a queue of all requested
1541 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1544 get_list_info(q, aargv, cl, action, actarg)
1545 register struct query *q;
1548 register int (*action)();
1551 char *argv[13], *malloc(), *realloc();
1552 ## char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1553 ## char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1554 ## char modby[9], modwith[9];
1555 ## int id, rowcount, acl_id, hid, modby_id;
1557 struct save_queue *sq, *sq_create();
1559 returned = rowcount = 0;
1563 ## range of l is list
1564 ## repeat retrieve (id = l.list_id) where l.#name = @name {
1565 sq_save_data(sq, id);
1569 return(SMS_NO_MATCH);
1571 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1572 argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1573 argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1576 while (sq_get_data(sq, &id)) {
1580 ## repeat retrieve (listname = l.#name, active = text(l.#active),
1581 ## public = text(l.#public), hidden = text(l.#hidden),
1582 ## hid = l.#hidden, maillist = text(l.#maillist),
1583 ## group = text(l.#group), gid = text(l.#gid),
1584 ## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1585 ## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1586 ## modwith =l.#modwith)
1587 ## where l.list_id = @id
1589 if (atoi(gid) == -1)
1590 argv[6] = UNIQUE_GID;
1592 if (!strcmp(acl_type, "LIST")) {
1593 ## repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1594 ## inquire_equel(rowcount = "rowcount")
1596 strcpy(acl_name, "???");
1597 } else if (!strcmp(acl_type, "USER")) {
1598 ## repeat retrieve (acl_name = users.#login)
1599 ## where users.users_id = @acl_id
1600 ## inquire_equel(rowcount = "rowcount")
1602 strcpy(acl_name, "???");
1603 } else if (!strcmp(acl_type, "NONE")) {
1604 strcpy(acl_name, "NONE");
1606 strcpy(acl_name, "???");
1608 ## repeat retrieve (modby = users.login) where users.users_id = @modby_id
1609 ## inquire_equel(rowcount = "rowcount")
1611 sprintf(modby, "#%d", id);
1613 sms_trim_args(q->vcnt, argv);
1615 (*action)(q->vcnt, argv, actarg);
1619 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1620 ## where tblstats.#table = "list"
1622 return (SMS_SUCCESS);
1626 /* get_ace_use - given a type and a name, return a type and a name.
1627 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1628 * and argv[1] will contain the ID of the entity in question. The R*
1629 * types mean to recursively look at every containing list, not just
1630 * when the object in question is a direct member. On return, the
1631 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1634 int get_ace_use(q, argv, cl, action, actarg)
1643 ## int aid, listid, id;
1644 struct save_queue *sq, *sq_create();
1647 aid = *(int *)argv[1];
1648 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER")) {
1649 return(get_ace_internal(atype, aid, action, actarg));
1653 if (!strcmp(atype, "RLIST")) {
1654 sq_save_data(sq, aid);
1655 /* get all the list_id's of containing lists */
1656 ## range of m is members
1657 while (sq_get_data(sq, &id)) {
1658 ## repeat retrieve (listid = m.list_id)
1659 ## where m.member_type = "LIST" and m.member_id = @id {
1660 sq_save_unique_data(sq, listid);
1663 /* now process each one */
1664 while (sq_get_data(sq, &id)) {
1665 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1670 if (!strcmp(atype, "RUSER")) {
1671 ## range of m is members
1672 ## repeat retrieve (listid = m.list_id)
1673 ## where m.member_type = "USER" and m.member_id = @aid {
1674 sq_save_data(sq, listid);
1676 /* get all the list_id's of containing lists */
1677 while (sq_get_data(sq, &id)) {
1678 ## repeat retrieve (listid = m.list_id)
1679 ## where m.member_type = "LIST" and m.member_id = @id {
1680 sq_save_unique_data(sq, listid);
1683 /* now process each one */
1684 while (sq_get_data(sq, &id)) {
1685 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1688 if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1693 if (!found) return(SMS_NO_MATCH);
1694 return(SMS_SUCCESS);
1698 /* This looks up a single list or user for ace use. atype must be "USER"
1699 * or "LIST", and aid is the ID of the corresponding object. This is used
1700 * by get_ace_use above.
1703 ##get_ace_internal(atype, aid, action, actarg)
1714 if (!strcmp(atype, "LIST")) {
1715 rargv[0] = "FILESYS";
1716 ## repeat retrieve (name = filesys.label)
1717 ## where filesys.owners = @aid {
1718 (*action)(2, rargv, actarg);
1723 ## repeat retrieve (name = capacls.capability)
1724 ## where capacls.list_id = @aid {
1725 (*action)(2, rargv, actarg);
1728 } else if (!strcmp(atype, "USER")) {
1729 rargv[0] = "FILESYS";
1730 ## repeat retrieve (name = filesys.label)
1731 ## where filesys.owner = @aid {
1732 (*action)(2, rargv, actarg);
1738 ## repeat retrieve (name = list.#name)
1739 ## where list.acl_type = @atype and list.acl_id = @aid {
1740 (*action)(2, rargv, actarg);
1744 rargv[0] = "SERVICE";
1745 ## repeat retrieve (name = servers.#name)
1746 ## where servers.acl_type = @atype and servers.acl_id = @aid {
1747 (*action)(2, rargv, actarg);
1751 rargv[0] = "HOSTACCESS";
1752 ## repeat retrieve (name = machine.#name)
1753 ## where machine.mach_id = hostaccess.mach_id and
1754 ## hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1755 (*action)(2, rargv, actarg);
1758 rargv[0] = "ZEPHYR";
1759 ## repeat retrieve (name = zephyr.class)
1760 ## where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
1761 ## zephyr.sub_type = @atype and zephyr.sub_id = @aid or
1762 ## zephyr.iws_type = @atype and zephyr.iws_id = @aid or
1763 ## zephyr.iui_type = @atype and zephyr.iui_id = @aid {
1764 (*action)(2, rargv, actarg);
1768 if (!found) return(SMS_NO_MATCH);
1769 return(SMS_SUCCESS);
1773 /* get_lists_of_member - given a type and a name, return the name and flags
1774 * of all of the lists of the given member. The member_type is one of
1775 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1776 * and argv[1] will contain the ID of the entity in question. The R*
1777 * types mean to recursively look at every containing list, not just
1778 * when the object in question is a direct member.
1781 int get_lists_of_member(q, argv, cl, action, actarg)
1790 ## int aid, listid, id;
1791 struct save_queue *sq, *sq_create();
1794 aid = *(int *)argv[1];
1795 if (!strcmp(atype, "LIST") ||
1796 !strcmp(atype, "USER") ||
1797 !strcmp(atype, "STRING")) {
1798 return(glom_internal(atype, aid, action, actarg));
1802 if (!strcmp(atype, "RLIST")) {
1803 sq_save_data(sq, aid);
1804 /* get all the list_id's of containing lists */
1805 ## range of m is members
1806 while (sq_get_data(sq, &id)) {
1807 ## repeat retrieve (listid = m.list_id)
1808 ## where m.member_type = "LIST" and m.member_id = @id {
1809 sq_save_unique_data(sq, listid);
1812 /* now process each one */
1813 while (sq_get_data(sq, &id)) {
1814 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1819 if (!strcmp(atype, "RUSER")) {
1820 ## range of m is members
1821 ## repeat retrieve (listid = m.list_id)
1822 ## where m.member_type = "USER" and m.member_id = @aid {
1823 sq_save_data(sq, listid);
1825 /* get all the list_id's of containing lists */
1826 while (sq_get_data(sq, &id)) {
1827 ## repeat retrieve (listid = m.list_id)
1828 ## where m.member_type = "LIST" and m.member_id = @id {
1829 sq_save_unique_data(sq, listid);
1832 /* now process each one */
1833 while (sq_get_data(sq, &id)) {
1834 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1837 if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1841 if (!strcmp(atype, "RSTRING")) {
1842 ## range of m is members
1843 ## repeat retrieve (listid = m.list_id)
1844 ## where m.member_type = "STRING" and m.member_id = @aid {
1845 sq_save_data(sq, listid);
1847 /* get all the list_id's of containing lists */
1848 while (sq_get_data(sq, &id)) {
1849 ## repeat retrieve (listid = m.list_id)
1850 ## where m.member_type = "LIST" and m.member_id = @id {
1851 sq_save_unique_data(sq, listid);
1854 /* now process each one */
1855 while (sq_get_data(sq, &id)) {
1856 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1859 if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
1863 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1864 ## where tblstats.#table = "members"
1866 if (!found) return(SMS_NO_MATCH);
1867 return(SMS_SUCCESS);
1871 /* This looks up a single list, user, or string as a member. atype must be
1872 * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
1873 * This is used by get_lists_of_members above.
1876 ##glom_internal(atype, aid, action, actarg)
1884 ## char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
1890 rargv[4] = maillist;
1892 ## repeat retrieve (name = list.#name, active = text(list.#active),
1893 ## public = text(list.#public), hidden = text(list.#hidden),
1894 ## maillist = text(list.#maillist), group = text(list.#group))
1895 ## where list.list_id = m.list_id and
1896 ## m.member_type = @atype and m.member_id = @aid {
1897 (*action)(6, rargv, actarg);
1901 if (!found) return(SMS_NO_MATCH);
1902 return(SMS_SUCCESS);
1906 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1907 * the five flags associated with each list. It will return the name of
1908 * each list that meets the quailifications. It does this by building a
1909 * where clause based on the arguments, then doing a retrieve.
1912 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
1914 int qualified_get_lists(q, argv, cl, action, actarg)
1921 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
1922 "l", "name", lflags));
1926 /** get_members_of_list - optimized query for retrieval of list members
1929 ** argv[0] - list_id
1932 ** - retrieve USER members, then LIST members, then STRING members
1935 get_members_of_list(q, argv, cl, action, actarg)
1943 ## char member_name[129];
1946 list_id = *(int *)argv[0];
1948 targv[1] = member_name;
1950 ## range of m is members
1951 ## repeat retrieve (member_name = users.login)
1952 ## where m.#list_id = @list_id and m.member_type = "USER"
1953 ## and m.member_id = users.users_id
1954 ## sort by #member_name
1956 (*action)(2, targv, actarg);
1960 ## repeat retrieve (member_name = list.name)
1961 ## where m.#list_id = @list_id and m.member_type = "LIST"
1962 ## and m.member_id = list.#list_id
1963 ## sort by #member_name
1965 (*action)(2, targv, actarg);
1968 targv[0] = "STRING";
1969 ## repeat retrieve (member_name = strings.string)
1970 ## where m.#list_id = @list_id and m.member_type = "STRING"
1971 ## and m.member_id = strings.string_id
1972 ## sort by #member_name
1974 (*action)(2, targv, actarg);
1977 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1978 ## where tblstats.#table = "members"
1979 return(SMS_SUCCESS);
1983 /* count_members_of_list: this is a simple query, but it cannot be done
1984 * through the dispatch table.
1987 int count_members_of_list(q, argv, cl, action, actarg)
1994 ## int list, ct = 0;
1995 char *rargv[1], countbuf[5];
1997 list = *(int *)argv[0];
1998 rargv[0] = countbuf;
1999 ## repeat retrieve (ct = count(members.list_id where members.list_id = @list))
2000 sprintf(countbuf, "%d", ct);
2001 (*action)(1, rargv, actarg);
2002 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2003 ## where tblstats.#table = "members"
2004 return(SMS_SUCCESS);
2008 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2009 * the three flags associated with each service. It will return the name of
2010 * each service that meets the quailifications. It does this by building a
2011 * where clause based on the arguments, then doing a retrieve.
2014 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2016 int qualified_get_server(q, argv, cl, action, actarg)
2023 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2024 "s", "name", sflags));
2028 /* generic qualified get routine, used by qualified_get_lists,
2029 * qualified_get_server, and qualified_get_serverhost.
2031 * start - a simple where clause, must not be empty
2032 * range - the name of the range variable
2033 * field - the field to return
2034 * flags - an array of strings, names of the flag variables
2037 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2047 ## char name[33], qual[256], *rvar, *rtbl, *rfield;
2048 char *rargv[1], buf[32];
2051 strcpy(qual, start);
2052 for (i = 0; i < q->argc; i++) {
2053 if (!strcmp(argv[i], "TRUE")) {
2054 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2055 (void) strcat(qual, buf);
2056 } else if (!strcmp(argv[i], "FALSE")) {
2057 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2058 (void) strcat(qual, buf);
2066 ## range of rvar is rtbl
2067 ## retrieve (name = rvar.rfield) where qual {
2068 (*action)(1, rargv, actarg);
2070 ## inquire_equel(rowcount = "rowcount")
2071 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2072 ## where tblstats.#table = @rtbl
2074 return(SMS_NO_MATCH);
2075 return(SMS_SUCCESS);
2079 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2080 * the five flags associated with each serverhost. It will return the name of
2081 * each service and host that meets the quailifications. It does this by
2082 * building a where clause based on the arguments, then doing a retrieve.
2085 static char *shflags[6] = { "service", "enable", "override", "success",
2086 "inprogress", "hosterror" };
2088 int qualified_get_serverhost(q, argv, cl, action, actarg)
2095 ## char sname[33], mname[33], qual[256];
2096 char *rargv[2], buf[32];
2099 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2101 for (i = 1; i < q->argc; i++) {
2102 if (!strcmp(argv[i], "TRUE")) {
2103 sprintf(buf, " and sh.%s != 0", shflags[i]);
2105 } else if (!strcmp(argv[i], "FALSE")) {
2106 sprintf(buf, " and sh.%s = 0", shflags[i]);
2113 ## range of sh is serverhosts
2114 ## retrieve (sname = sh.service, mname = machine.name) where qual {
2115 (*action)(2, rargv, actarg);
2117 ## inquire_equel(rowcount = "rowcount")
2118 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2119 ## where tblstats.#table = "serverhosts"
2121 return(SMS_NO_MATCH);
2122 return(SMS_SUCCESS);
2126 /* register_user - change user's login name and allocate a pobox, group,
2127 * filesystem, and quota for them. The user's status must start out as 0,
2128 * and is left as 2. Arguments are: user's UID, new login name, and user's
2129 * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY,
2130 * SMS_FS_STAFF, SMS_FS_MISC).
2133 register_user(q, argv, cl)
2138 ## char *login, dir[65], *entity, *directory, machname[33];
2139 ## int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2140 ## int size, alloc, pid, m_id;
2143 entity = cl->entity;
2146 uid = atoi(argv[0]);
2148 utype = atoi(argv[2]);
2150 ## range of u is users
2151 ## range of l is list
2152 ## range of sh is serverhosts
2153 ## range of n is nfsphys
2154 ## range of m is machine
2157 ## repeat retrieve (users_id = u.#users_id)
2158 ## where u.#uid = @uid and u.status = 0
2159 ## inquire_equel(rowcount = "rowcount");
2161 return(SMS_NO_MATCH);
2163 return(SMS_NOT_UNIQUE);
2165 /* check new login name */
2166 ## repeat retrieve (flag = any(u.#login where u.#login = @login))
2169 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2172 ## repeat retrieve (flag = any(filesys.#name where filesys.#name = @login))
2175 if (ingres_errno != 0) return(ingres_errno);
2176 com_err(whoami, 0, "new login name OK");
2178 /* choose place for pobox, put in mid */
2179 ## repeat retrieve (mid = sh.mach_id, machname = m.name)
2180 ## where sh.service = "POP" and m.mach_id = sh.mach_id and
2181 ## sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2182 ## inquire_equel(rowcount = "rowcount");
2183 if (ingres_errno != 0) return(ingres_errno);
2185 return(SMS_NO_POBOX);
2187 /* change login name, set pobox */
2188 ## repeat replace u (#login = @login, status = 2, modtime = "now",
2189 ## modby = @who, modwith = @entity, potype="POP",
2190 ## pop_id = @mid, pmodtime="now", pmodby=@who,
2191 ## pmodwith=@entity)
2192 ## where u.#users_id = @users_id
2193 ## inquire_equel(rowcount = "rowcount");
2194 if (ingres_errno != 0) return(ingres_errno);
2196 return(SMS_INTERNAL);
2197 set_pop_usage(mid, 1);
2198 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2201 /* create group list */
2202 if (set_next_object_id("gid", "list"))
2204 if (set_next_object_id("list_id", "list"))
2206 ## repeat retrieve (list_id = values.value) where values.name = "list_id"
2207 ## inquire_equel(rowcount = "rowcount");
2208 if (ingres_errno != 0) return(ingres_errno);
2210 return(SMS_INTERNAL);
2211 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2212 ## public = 0, hidden = 0, maillist = 0, group = 1,
2213 ## #gid = values.value, desc = "User Group",
2214 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2215 ## modby = @who, modwith = @entity)
2216 ## where values.name = "gid"
2217 ## inquire_equel(rowcount = "rowcount");
2218 if (ingres_errno != 0) return(ingres_errno);
2220 return(SMS_INTERNAL);
2221 ## repeat append members (#list_id = @list_id, member_type = "USER",
2222 ## member_id = @users_id)
2223 ## inquire_equel(rowcount = "rowcount");
2224 if (ingres_errno != 0) return(ingres_errno);
2226 return(SMS_INTERNAL);
2227 com_err(whoami, 0, "group list created");
2229 /* decide where to put filesystem */
2232 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2233 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2234 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2235 maxsize = size - alloc;
2238 directory = strsave(dir);
2243 if (ingres_errno != 0) return(ingres_errno);
2245 return(SMS_NO_FILESYS);
2247 /* create filesystem */
2248 if (set_next_object_id("filsys_id", "filesys"))
2250 ## repeat append filesys (filsys_id = values.value, phys_id = @pid,
2251 ## label = @login, type = "NFS", mach_id = @m_id,
2252 ## name = @directory + "/" + @login,
2253 ## mount = "/mit/" + @login,
2254 ## access = "w", comments = "User Locker",
2255 ## owner = @users_id, owners = @list_id, createflg = 1,
2256 ## lockertype = "HOMEDIR", modtime = "now",
2257 ## modby = @who, modwith = @entity)
2258 ## where values.name = "filsys_id"
2259 ## inquire_equel(rowcount = "rowcount");
2260 if (ingres_errno != 0) return(ingres_errno);
2262 return(SMS_INTERNAL);
2263 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2267 ## repeat retrieve (quota = values.value) where values.name = "def_quota"
2268 ## inquire_equel(rowcount = "rowcount");
2269 if (ingres_errno != 0) return(ingres_errno);
2271 return(SMS_NO_QUOTA);
2272 ## repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2273 ## #quota = @quota, phys_id = @pid, modtime = "now",
2274 ## modby = @who, modwith = @entity)
2275 ## where values.name = "filsys_id"
2276 ## inquire_equel(rowcount = "rowcount");
2277 if (ingres_errno != 0) return(ingres_errno);
2279 return(SMS_INTERNAL);
2280 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2281 ## where nfsphys.nfsphys_id = filesys.#phys_id and
2282 ## filesys.filsys_id = values.value and values.name = "filsys_id"
2283 ## inquire_equel(rowcount = "rowcount");
2284 if (ingres_errno != 0) return(ingres_errno);
2286 return(SMS_INTERNAL);
2287 com_err(whoami, 0, "quota of %d assigned", quota);
2289 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2290 ## where tblstats.table = "users"
2291 if (ingres_errno != 0) return(ingres_errno);
2292 ## repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2293 ## where tblstats.table = "list" or tblstats.table = "filesys" or
2294 ## tblstats.table = "nfsquota"
2295 if (ingres_errno != 0) return(ingres_errno);
2296 return(SMS_SUCCESS);
2301 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2305 ** delta (will be +/- 1)
2308 ** - incr/decr value field in serverhosts table for pop/mach_id
2312 static int set_pop_usage(id, count)
2316 ## int mach_id = id;
2319 ## range of sh is serverhosts
2320 ## repeat replace sh (value1 = sh.value1 + @n)
2321 ## where sh.service = "POP" and sh.#mach_id = @mach_id
2323 return(SMS_SUCCESS);
2328 /* Validation Routines */
2330 validate_row(q, argv, v)
2331 register struct query *q;
2333 register struct validate *v;
2341 /* build where clause */
2342 build_qual(v->qual, v->argc, argv, qual);
2344 /* setup ingres variables */
2349 if (log_flags & LOG_VALID)
2350 /* tell the logfile what we're doing */
2351 com_err(whoami, 0, "validating row: %s", qual);
2353 /* look for the record */
2354 ## range of rvar is table
2355 ## retrieve (rowcount = count(rvar.name where qual))
2356 if (rowcount == 0) return(SMS_NO_MATCH);
2357 if (rowcount > 1) return(SMS_NOT_UNIQUE);
2361 validate_fields(q, argv, vo, n)
2363 register char *argv[];
2364 register struct valobj *vo;
2367 register int status;
2372 if (log_flags & LOG_VALID)
2373 com_err(whoami, 0, "validating %s in %s: %s",
2374 vo->namefield, vo->table, argv[vo->index]);
2375 status = validate_name(argv, vo);
2379 if (log_flags & LOG_VALID)
2380 com_err(whoami, 0, "validating %s in %s: %s",
2381 vo->idfield, vo->table, argv[vo->index]);
2382 status = validate_id(argv, vo);
2386 if (log_flags & LOG_VALID)
2387 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2388 status = validate_date(argv, vo);
2392 if (log_flags & LOG_VALID)
2393 com_err(whoami, 0, "validating %s type: %s",
2394 vo->table, argv[vo->index]);
2395 status = validate_type(argv, vo);
2399 if (log_flags & LOG_VALID)
2400 com_err(whoami, 0, "validating typed data (%s): %s",
2401 argv[vo->index - 1], argv[vo->index]);
2402 status = validate_typedata(q, argv, vo);
2406 if (log_flags & LOG_VALID)
2407 com_err(whoami, 0, "validating rename %s in %s",
2408 argv[vo->index], vo->table);
2409 status = validate_rename(argv, vo);
2413 if (log_flags & LOG_VALID)
2414 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2415 status = validate_chars(argv[vo->index]);
2419 status = SMS_EXISTS;
2424 if (status != SMS_EXISTS) return(status);
2428 return(SMS_SUCCESS);
2432 /* validate_chars: verify that there are no illegal characters in
2433 * the string. Legal characters are printing chars other than
2434 * ", *, ?, \, [ and ].
2436 static int illegalchars[] = {
2437 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2438 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2439 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2440 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2441 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2444 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2445 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2446 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2447 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2448 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2449 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2450 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2451 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2452 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2459 if (illegalchars[*s++])
2460 return(SMS_BAD_CHAR);
2465 validate_id(argv, vo)
2467 register struct valobj *vo;
2477 name = argv[vo->index];
2479 /* minor kludge to upcasify machine names */
2480 if (!strcmp(table, "machine"))
2481 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2482 namefield = vo->namefield;
2483 idfield = vo->idfield;
2484 if (!strcmp(namefield, "uid")) {
2485 ## retrieve (id = table.idfield) where table.namefield = int4(name)
2486 ## inquire_equel (rowcount = "rowcount")
2488 ## retrieve (id = table.idfield) where table.namefield = name
2489 ## inquire_equel (rowcount = "rowcount")
2491 if (rowcount != 1) return(vo->error);
2492 *(int *)argv[vo->index] = id;
2496 validate_name(argv, vo)
2498 register struct valobj *vo;
2506 name = argv[vo->index];
2508 namefield = vo->namefield;
2509 if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2510 for (c = name; *c; c++)
2514 ## retrieve (rowcount = countu(table.namefield
2515 ## where table.namefield = name))
2516 return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2519 validate_date(argv, vo)
2527 idate = argv[vo->index];
2529 ## retrieve (dd = interval("years", date(idate) - date("today")))
2530 ## inquire_equel (errorno = "errorno")
2531 if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2536 validate_rename(argv, vo)
2540 ## char *name, *table, *namefield, *idfield;
2544 c = name = argv[vo->index];
2546 if (illegalchars[*c++])
2547 return(SMS_BAD_CHAR);
2549 /* minor kludge to upcasify machine names */
2550 if (!strcmp(table, "machine"))
2551 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2552 namefield = vo->namefield;
2553 idfield = vo->idfield;
2556 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2558 ## retrieve (id = any(table.namefield where table.namefield = name))
2564 ## retrieve (id = table.idfield) where table.namefield = name
2565 if (id == -1 || id == *(int *)argv[vo->index - 1])
2572 validate_type(argv, vo)
2574 register struct valobj *vo;
2581 typename = vo->table;
2582 c = value = argv[vo->index];
2584 if (illegalchars[*c++])
2585 return(SMS_BAD_CHAR);
2587 /* uppercase type fields */
2588 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2590 ## range of a is alias
2591 ## repeat retrieve (exists = any(a.trans where a.name = @typename and
2592 ## a.type = "TYPE" and
2593 ## a.trans = @value))
2594 return (exists ? SMS_EXISTS : vo->error);
2597 /* validate member or type-specific data field */
2599 validate_typedata(q, argv, vo)
2600 register struct query *q;
2601 register char *argv[];
2602 register struct valobj *vo;
2605 ## char *field_type;
2606 ## char data_type[129];
2612 /* get named object */
2613 name = argv[vo->index];
2615 /* get field type string (known to be at index-1) */
2616 field_type = argv[vo->index-1];
2618 /* get corresponding data type associated with field type name */
2619 ## repeat retrieve (data_type = alias.trans)
2620 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
2621 ## inquire_equel (rowcount = "rowcount")
2622 if (rowcount != 1) return(SMS_TYPE);
2624 /* now retrieve the record id corresponding to the named object */
2625 if (index(data_type, ' '))
2626 *index(data_type, ' ') = 0;
2627 if (!strcmp(data_type, "user")) {
2629 ## repeat retrieve (id = users.users_id) where users.login = @name
2630 ## inquire_equel (rowcount = "rowcount")
2631 if (rowcount != 1) return(SMS_USER);
2633 } else if (!strcmp(data_type, "list")) {
2635 ## repeat retrieve (id = list.list_id) where list.#name = @name
2636 ## inquire_equel (rowcount = "rowcount")
2637 if (rowcount != 1) {
2638 /* if idfield is non-zero, then if argv[0] matches the string
2639 * that we're trying to resolve, we should get the value of
2640 * values.[idfield] for the id.
2642 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2643 set_next_object_id(q->validate->object_id, q->rtable);
2645 ## repeat retrieve (id = values.value) where values.#name = @name
2646 ## inquire_equel(rowcount = "rowcount")
2647 if (rowcount != 1) return(SMS_LIST);
2651 } else if (!strcmp(data_type, "machine")) {
2653 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2654 ## repeat retrieve (id = machine.mach_id) where machine.#name = @name
2655 ## inquire_equel (rowcount = "rowcount")
2656 if (rowcount != 1) return(SMS_MACHINE);
2658 } else if (!strcmp(data_type, "string")) {
2660 ## range of s is strings
2661 ## repeat retrieve (id = s.string_id) where s.string = @name
2662 ## inquire_equel (rowcount = "rowcount")
2663 if (rowcount == 0) {
2664 if (q->type != APPEND) return(SMS_STRING);
2665 ## range of v is values
2666 ## retrieve (id = v.value) where v.#name = "strings_id"
2668 ## replace v (value = id) where v.#name = "strings_id"
2669 ## append to strings (string_id = id, string = name)
2671 } else if (!strcmp(data_type, "none")) {
2677 /* now set value in argv */
2678 *(int *)argv[vo->index] = id;
2680 return (SMS_EXISTS);
2684 /* This looks up a login name and returns the SMS internal ID. It is used
2685 * by authenticate to put the users_id in the client structure.
2688 int get_users_id(name)
2691 ## int id, rowcount;
2696 ## range of u is users
2697 ## repeat retrieve (id = u.#users_id) where u.#login = @login
2698 ## inquire_equel (rowcount = "rowcount")
2707 /* Check the database at startup time. For now this just resets the
2708 * inprogress flags that the DCM uses.
2711 sanity_check_database()