6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
13 static char *rcsid_qsupport_qc = "$Header$";
16 #include <mit-copyright.h>
18 #include "sms_server.h"
22 extern char *whoami, *strsave();
25 /* Specialized Access Routines */
27 /* access_user - verify that client name equals specified login name
29 * - since field validation routines are called first, a users_id is
30 * now in argv[0] instead of the login name.
33 access_user(q, argv, cl)
38 if (cl->users_id != *(int *)argv[0])
46 /* access_login - verify that client name equals specified login name
48 * argv[0...n] contain search info. q->
51 access_login(q, argv, cl)
59 build_qual(q->qual, q->argc, argv, qual);
60 ## retrieve (id = u.users_id) where qual
61 ## inquire_equel(rowcount = "rowcount")
62 if (rowcount != 1 || id != cl->users_id)
70 /* access_list - check access for most list operations
72 * Inputs: argv[0] - list_id
74 * argv[2] - member ID (only for queries "amtl" and "dmfl")
75 * argv[7] - group IID (only for query "ulis")
78 * - check that client is a member of the access control list
79 * - OR, if the query is add_member_to_list or delete_member_from_list
80 * and the list is public, allow access if client = member
83 access_list(q, argv, cl)
88 ## int list_id, acl_id, flags, rowcount, gid;
91 int client_id, status;
93 list_id = *(int *)argv[0];
94 ## repeat retrieve (acl_id = list.#acl_id, acl_type = list.#acl_type,
95 ## gid = list.#gid, flags = list.#public)
96 ## where list.#list_id = @list_id
97 ## inquire_equel(rowcount = "rowcount")
101 /* parse client structure */
102 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
105 /* if amtl or dmfl and list is public allow client to add or delete self */
106 if ((!strcmp("amtl", q->shortname) || !strcmp("dmfl", q->shortname)) &&
107 (flags && !strcmp("USER", argv[1]))) {
108 if (*(int *)argv[2] == client_id) return(SMS_SUCCESS);
109 /* if update_list, don't allow them to change the GID */
110 } else if (!strcmp("ulis", q->shortname)) {
111 if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
112 (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
116 /* check for client in access control list */
117 status = find_member(acl_type, acl_id, client_type, client_id, 0);
118 if (!status) return(SMS_PERM);
124 /* access_visible_list - allow access to list only if it is not hidden,
125 * or if the client is on the ACL
127 * Inputs: argv[0] - list_id
128 * cl - client identifier
131 access_visible_list(q, argv, cl)
136 ## int list_id, acl_id, flags, rowcount;
139 int client_id, status;
141 list_id = *(int *)argv[0];
142 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
143 ## acl_type = list.#acl_type) where list.#list_id = @list_id
144 ## inquire_equel(rowcount = "rowcount")
146 return(SMS_INTERNAL);
150 /* parse client structure */
151 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
154 /* check for client in access control list */
155 status = find_member(acl_type, acl_id, client_type, client_id, 0);
163 /* access_vis_list_by_name - allow access to list only if it is not hidden,
164 * or if the client is on the ACL
166 * Inputs: argv[0] - list name
167 * cl - client identifier
170 access_vis_list_by_name(q, argv, cl)
175 ## int acl_id, flags, rowcount;
176 ## char acl_type[9], *listname;
178 int client_id, status;
181 ## repeat retrieve (flags = list.hidden, acl_id = list.#acl_id,
182 ## acl_type = list.#acl_type) where list.#name = @listname
183 ## inquire_equel(rowcount = "rowcount");
185 return(SMS_WILDCARD);
187 return(SMS_NO_MATCH);
191 /* parse client structure */
192 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
195 /* check for client in access control list */
196 status = find_member(acl_type, acl_id, client_type, client_id, 0);
204 /* access_member - allow user to access member of type "USER" and name matches
205 * username, or to access member of type "LIST" and list is one that user is
206 * on the acl of, or the list is visible.
209 access_member(q, argv, cl)
214 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
215 return(access_visible_list(q, &argv[1], cl));
217 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
218 if (cl->users_id == *(int *)argv[1])
226 /* access_qgli - special access routine for Qualified_get_lists. Allows
227 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
230 access_qgli(q, argv, cl)
235 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
241 /* access_service - allow access if user is on ACL of service. Don't
242 * allow access if a wildcard is used.
245 access_service(q, argv, cl)
250 ## int acl_id, rowcount;
251 ## char *name, acl_type[9];
252 int client_id, status;
256 ## repeat retrieve (acl_id = servers.#acl_id, acl_type = servers.#acl_type)
257 ## where servers.#name = uppercase(@name)
258 ## inquire_equel(rowcount = "rowcount")
262 /* parse client structure */
263 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
266 /* check for client in access control list */
267 status = find_member(acl_type, acl_id, client_type, client_id, 0);
268 if (!status) return(SMS_PERM);
275 /* access_filesys - verify that client is owner or on owners list of filesystem
279 access_filesys(q, argv, cl)
284 ## int rowcount, users_id, list_id;
286 int status, client_id;
290 ## repeat retrieve (users_id = filesys.owner, list_id = filesys.owners)
291 ## where filesys.label = @name
292 ## inquire_equel(rowcount = "rowcount")
296 if (users_id == cl->users_id)
298 if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
300 status = find_member("LIST", list_id, client_type, client_id, 0);
310 /* Setup routine for add_user
312 * Inputs: argv[0] - login
317 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
318 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
321 setup_ausr(q, argv, cl)
323 register char *argv[];
326 ## int nuid, rowcount;
328 if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
329 if (set_next_object_id("uid", "users"))
330 return(SMS_INGRES_ERR);
331 ## repeat retrieve (nuid = values.value) where values.name = "uid"
332 ## inquire_equel(rowcount = "rowcount")
334 return(SMS_INTERNAL);
335 sprintf(argv[1], "%d", nuid);
338 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
339 sprintf(argv[0], "#%s", argv[1]);
346 /* setup_dusr - verify that the user is no longer being referenced
347 * and may safely be deleted.
350 int setup_dusr(q, argv)
356 id = *(int *)argv[0];
358 /* For now, only allow users to be deleted if their status is 0 */
359 ## repeat retrieve (flag = u.status) where u.users_id = @id
363 ## repeat delete nfsquota where nfsquota.users_id = @id
364 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
365 ## and members.member_type = "USER"))
368 ## repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
371 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
372 ## list.acl_type = "USER"))
375 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
376 ## servers.acl_type = "USER"))
379 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
380 ## hostaccess.acl_type = "USER"))
388 /* setup_spop: verify that there is already a valid POP machine_id in the
389 * pop_id field. Also take care of keeping track of the post office usage.
391 int setup_spop(q, argv)
395 ## int id, mid, flag;
398 id = *(int *)argv[0];
399 ## repeat retrieve (type = u.potype, mid = u.pop_id,
400 ## flag = any(machine.name where machine.mach_id = u.pop_id
401 ## and u.pop_id != 0 and u.users_id = @id))
402 ## where u.users_id = @id
405 if (strcmp(strtrim(type), "POP"))
406 set_pop_usage(mid, 1);
411 /* setup_dpob: Take care of keeping track of the post office usage.
413 int setup_dpob(q, argv)
420 user = *(int *)argv[0];
421 ## repeat retrieve (type = u.potype, id = u.pop_id)
422 ## where u.users_id = @user
424 if (!strcmp(strtrim(type), "POP"))
425 set_pop_usage(id, -1);
430 /* setup_dmac - verify that the machine is no longer being referenced
431 * and may safely be deleted.
434 int setup_dmac(q, argv)
440 id = *(int *)argv[0];
441 ## repeat retrieve (flag = any(users.login where users.potype = "POP"
442 ## and users.pop_id=@id))
445 ## repeat retrieve (flag = any(serverhosts.mach_id
446 ## where serverhosts.mach_id=@id))
449 ## repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
452 ## repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
455 ## repeat retrieve (flag = any(printcap.mach_id where printcap.mach_id=@id))
459 ## repeat delete mcmap where mcmap.mach_id = @id
464 /* setup_dclu - verify that the cluster is no longer being referenced
465 * and may safely be deleted.
468 int setup_dclu(q, argv)
474 id = *(int *)argv[0];
475 ## repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
478 ## repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
486 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
487 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
488 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
489 * a -1 there. Remember that this is also used for ulis, with the indexes
493 int setup_alis(q, argv)
501 if (!strcmp(q->shortname, "alis"))
503 else if (!strcmp(q->shortname, "ulis"))
506 if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
507 if (atoi(argv[idx - 1])) {
508 if (set_next_object_id("gid", "list"))
509 return(SMS_INGRES_ERR);
510 ## repeat retrieve (ngid = values.value) where values.name = "gid"
511 sprintf(argv[idx], "%d", ngid);
513 strcpy(argv[idx], "-1");
521 /* setup_dlist - verify that the list is no longer being referenced
522 * and may safely be deleted.
525 int setup_dlis(q, argv)
531 id = *(int *)argv[0];
532 ## repeat retrieve (flag = any(members.member_id where members.member_id=@id
533 ## and members.member_type = "LIST"))
536 ## repeat retrieve (flag = any(members.member_id where members.list_id=@id))
539 ## repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
542 ## repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
545 ## repeat retrieve (flag = any(list.name where list.acl_id=@id and
546 ## list.acl_type = "LIST" and list.list_id != @id))
549 ## repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
550 ## servers.acl_type = "LIST"))
553 ## repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
554 ## hostaccess.acl_type = "LIST"))
557 ## repeat retrieve (flag = any(zephyr.class
558 ## where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
559 ## zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
560 ## zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
561 ## zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
569 /* setup_dsin - verify that the service is no longer being referenced
570 * and may safely be deleted.
573 int setup_dsin(q, argv)
581 ## repeat retrieve (flag = any(serverhosts.service
582 ## where serverhosts.service=uppercase(@name)))
585 ## repeat retrieve (flag = servers.inprogress) where servers.#name = @name
593 /* setup_dshi - verify that the service-host is no longer being referenced
594 * and may safely be deleted.
597 int setup_dshi(q, argv)
605 id = *(int *)argv[1];
606 ## repeat retrieve (flag=serverhosts.inprogress)
607 ## where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
616 ** setup_add_filesys - verify existance of referenced file systems
628 ** * extract directory prefix from name
629 ** * verify mach_id/dir in nfsphys
630 ** * verify access in {r, w, R, W}
632 ** Side effect: sets variable var_phys_id to the ID of the physical
633 ** filesystem (nfsphys_id for NFS, 0 for RVD)
636 ** SMS_NFS - specified directory not exported
637 ** SMS_FILESYS_ACCESS - invalid filesys access
641 ##static int var_phys_id;
653 mach_id = *(int *)argv[2];
658 if (!strcmp(type, "NFS"))
659 return (check_nfs(mach_id, name, access));
665 /* Verify the arguments, depending on the FStype. Also, if this is an
666 * NFS filesystem, then update any quotas for that filesystem to reflect
675 char *type, *name, *access;
679 mach_id = *(int *)argv[3];
684 if (!strcmp(type, "NFS")) {
685 status = check_nfs(mach_id, name, access);
686 fid = *(int *)argv[0];
687 ## replace nfsquota (phys_id = var_phys_id) where nfsquota.filsys_id = fid
694 /* Find the NFS physical partition that the named directory is on.
695 * This is done by comparing the dir against the mount point of the
696 * partition. To make sure we get the correct match when there is
697 * more than one, we sort the query in reverse order by dir name.
700 ##check_nfs(mach_id, name, access)
711 caccess = (isupper(*access)) ? tolower(*access) : *access;
712 if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
715 ## range of np is nfsphys
716 ## repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
717 ## where np.#mach_id = @mach_id sort by #dir:d {
721 if (*cp1++ != *cp2) break;
725 status = SMS_SUCCESS;
734 /* setup_dfil: free any quota records associated with a filesystem
735 * when it is deleted.
738 setup_dfil(q, argv, cl)
745 id = *(int *)argv[0];
746 ## range of q is nfsquota
747 ## range of fs is filesys
748 ## range of n is nfsphys
749 ## repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
750 ## where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
752 ## repeat delete q where q.filsys_id = @id
757 /* setup_dnfp: check to see that the nfs physical partition does not have
758 * any filesystems assigned to it before allowing it to be deleted.
761 setup_dnfp(q, argv, cl)
768 id = *(int *)argv[0];
769 ## repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
776 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
777 * argv[0] = filsys_id
781 setup_dnfq(q, argv, cl)
786 ## int quota, fs, user;
788 fs = *(int *)argv[0];
789 user = *(int *)argv[1];
791 ## range of q is nfsquota
792 ## repeat retrieve (quota = q.#quota) where q.users_id = @user and
794 ## repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
795 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
801 /* FOLLOWUP ROUTINES */
803 /* generic set_modtime routine. This takes the table name from the query,
804 * and will update the modtime, modby, and modwho fields in the entry in
805 * the table whose name field matches argv[0].
808 set_modtime(q, argv, cl)
813 ## char *name, *entity, *table;
821 ## replace table (modtime = "now", modby = who, modwith = entity)
822 ## where table.#name = name
826 /* generic set_modtime_by_id routine. This takes the table name from
827 * the query, and the id name from the validate record,
828 * and will update the modtime, modby, and modwho fields in the entry in
829 * the table whose id matches argv[0].
832 set_modtime_by_id(q, argv, cl)
837 ## char *entity, *table, *id_name;
843 id_name = q->validate->object_id;
845 id = *(int *)argv[0];
846 ## replace table (modtime = "now", modby = who, modwith = entity)
847 ## where table.id_name = id
852 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
855 set_finger_modtime(q, argv, cl)
860 ## int users_id, who;
865 users_id = *(int *)argv[0];
867 ## repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
868 ## where u.#users_id = @users_id
873 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
876 set_pobox_modtime(q, argv, cl)
881 ## int users_id, who;
886 users_id = *(int *)argv[0];
888 ## repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
889 ## where users.#users_id = @users_id
894 /* Sets the modtime on a machine record. The machine name is in argv[0].
895 * This routine is different from the generic set_modtime in that the
896 * name is uppercased first.
899 set_mach_modtime(q, argv, cl)
904 ## char *host, *entity;
911 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
912 ## where m.name = uppercase(@host)
917 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
918 * is necessary for add_machine_to_cluster becuase the table that query
919 * operates on is "mcm", not "machine".
922 set_mach_modtime_by_id(q, argv, cl)
933 id = *(int *)argv[0];
934 ## range of m is machine
935 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
936 ## where m.mach_id = @id
941 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
942 * is necessary for add_cluster_data and delete_cluster_data becuase the
943 * table that query operates on is "svc", not "cluster".
946 set_cluster_modtime_by_id(q, argv, cl)
957 id = *(int *)argv[0];
958 ## range of c is cluster
959 ## repeat replace c (modtime = "now", modby = @who, modwith = @entity)
960 ## where c.clu_id = @id
965 /* sets the modtime on the serverhost where the service name is in argv[0]
966 * and the mach_id is in argv[1].
969 set_serverhost_modtime(q, argv, cl)
974 ## char *entity, *serv;
981 id = *(int *)argv[1];
982 ## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
983 ## where sh.service = uppercase(@serv) and sh.mach_id = @id
988 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
989 * directory name is in argv[1].
992 set_nfsphys_modtime(q, argv, cl)
997 ## char *entity, *dir;
1000 entity = cl->entity;
1003 id = *(int *)argv[0];
1005 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1006 ## where np.#dir = @dir and np.mach_id = @id
1007 return(SMS_SUCCESS);
1011 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1015 set_filesys_modtime(q, argv, cl)
1020 ## char *label, *entity;
1023 entity = cl->entity;
1027 if (!strcmp(q->shortname, "ufil"))
1030 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1031 ## #phys_id = @var_phys_id) where fs.#label = @label
1032 return(SMS_SUCCESS);
1036 /* sets the modtime on a zephyr class, where argv[0] contains the class
1040 set_zephyr_modtime(q, argv, cl)
1045 ## char *class, *entity;
1048 entity = cl->entity;
1053 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1054 ## where z.#class = @class
1055 return(SMS_SUCCESS);
1059 /* fixes the modby field. This will be the second to last thing in the
1060 * argv, the argv length is determined from the query structure. It is
1061 * passed as a pointer to an integer. This will either turn it into a
1062 * username, or # + the users_id.
1064 followup_fix_modby(q, sq, v, action, actarg, cl)
1066 register struct save_queue *sq;
1068 register int (*action)();
1069 register int actarg;
1073 char **argv, *malloc();
1074 ## int id, rowcount;
1078 while (sq_get_data(sq, &argv)) {
1081 argv[i] = malloc(9);
1083 ## repeat retrieve (name = users.login) where users.users_id = @id
1084 ## inquire_equel(rowcount = "rowcount")
1085 if (rowcount != 1) {
1086 sprintf(argv[i], "#%d", id);
1088 (*action)(q->vcnt, argv, actarg);
1089 for (j = 0; j < q->vcnt; j++)
1094 return(SMS_SUCCESS);
1099 ** followup_ausr - add finger and pobox entries, set_user_modtime
1102 ** argv[0] - login (add_user)
1103 ** argv[3] - last name
1104 ** argv[4] - first name
1105 ** argv[5] - middle name
1109 followup_ausr(q, argv, cl)
1115 ## char *login, *entity;
1116 ## char fullname[129];
1120 entity = cl->entity;
1122 /* build fullname */
1123 if (strlen(argv[4]) && strlen(argv[5]))
1124 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1125 else if (strlen(argv[4]))
1126 sprintf(fullname, "%s %s", argv[4], argv[3]);
1128 sprintf(fullname, "%s", argv[3]);
1130 /* create finger entry, pobox & set modtime on user */
1131 ## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1132 ## #fullname=@fullname, mit_affil = u.mit_year,
1133 ## fmodtime="now", fmodby=@who, fmodwith=@entity,
1134 ## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1135 ## where u.#login = @login
1137 return(SMS_SUCCESS);
1141 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1142 * type in argv[1]. Then completes the upcall to the user.
1144 * argv[2] is of the form "123:234" where the first integer is the machine
1145 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1146 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1150 followup_gpob(q, sq, v, action, actarg, cl)
1151 register struct query *q;
1152 register struct save_queue *sq;
1153 register struct validate *v;
1154 register int (*action)();
1158 char **argv, *index();
1160 ## char box[129], *name;
1161 ## int mid, sid, rowcount;
1164 while (sq_get_data(sq, &argv)) {
1165 sms_trim_args(2, argv);
1167 p = index(argv[2], ':');
1169 mid = atoi(argv[2]);
1173 if (!strcmp(ptype, "POP")) {
1174 ## repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1175 ## inquire_equel(rowcount = "rowcount")
1177 return(SMS_MACHINE);
1178 } else if (!strcmp(ptype, "SMTP")) {
1179 ## repeat retrieve (box=strings.string) where strings.string_id=@sid
1180 ## inquire_equel(rowcount = "rowcount")
1183 } else /* ptype == "NONE" */ {
1187 if (!strcmp(q->shortname, "gpob")) {
1188 sid = atoi(argv[4]);
1190 argv[4] = malloc(9);
1192 ## repeat retrieve (name = users.login) where users.users_id = @sid
1193 ## inquire_equel(rowcount = "rowcount")
1195 sprintf(name, "#%d", sid);
1199 (*action)(q->vcnt, argv, actarg);
1201 /* free saved data */
1208 return (SMS_SUCCESS);
1212 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1213 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1214 * proper name based on the type, and repace that string in the argv.
1215 * Also fixes the modby field by called followup_fix_modby.
1218 followup_glin(q, sq, v, action, actarg, cl)
1219 register struct query *q;
1220 register struct save_queue *sq;
1221 register struct validate *v;
1222 register int (*action)();
1226 char **argv, *malloc(), *realloc(), *type;
1228 ## int id, rowcount;
1232 if (!strcmp(q->shortname, "gsin"))
1235 while (sq_get_data(sq, &argv)) {
1236 sms_trim_args(q->vcnt, argv);
1238 id = atoi(argv[i = q->vcnt - 2]);
1240 name = argv[i] = malloc(9);
1241 ## repeat retrieve (name = users.login) where users.users_id = @id
1242 ## inquire_equel(rowcount = "rowcount")
1244 sprintf(argv[i], "#%d", id);
1246 id = atoi(argv[idx]);
1247 type = argv[idx - 1];
1248 if ((name = malloc(33)) == NULL)
1251 if (!strcmp(type, "LIST")) {
1252 ## repeat retrieve (name = list.#name) where list.list_id = @id
1253 ## inquire_equel(rowcount = "rowcount")
1255 strcpy(name, "???");
1256 } else if (!strcmp(type, "USER")) {
1257 ## repeat retrieve (name = users.login) where users.users_id = @id
1258 ## inquire_equel(rowcount = "rowcount")
1260 strcpy(name, "???");
1261 } else if (!strcmp(type, "NONE")) {
1262 strcpy(name, "NONE");
1264 strcpy(name, "???");
1268 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1269 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1270 strcpy(argv[6], UNIQUE_GID);
1274 (*action)(q->vcnt, argv, actarg);
1276 /* free saved data */
1277 for (i = 0; i < q->vcnt; i++)
1283 return (SMS_SUCCESS);
1287 /** followup_amtl - followup for amtl and dmfl; when adding a list
1288 ** member to a maillist, make member list a maillist also
1289 ** unless list is a user-group.
1290 ** Then set_list_modtime_by_id.
1293 ** argv[0] - list_id
1294 ** argv[1] - member_type
1295 ** argv[2] - member_id
1299 followup_amtl(q, argv, cl)
1309 list_id = *(int *)argv[0];
1310 entity = cl->entity;
1313 ## range of l is list
1314 ## repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1315 ## where l.#list_id = @list_id
1317 /* if query is not amtl or if member_type is not LIST then return */
1318 if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4))
1319 return(SMS_SUCCESS);
1321 member_id = *(int *)argv[2];
1323 /* is parent list a mailing list? */
1324 ## repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1326 return(SMS_SUCCESS);
1328 /* list is not a user-group; add list to maillist table */
1329 ## repeat replace l (maillist = 1) where l.#list_id = @member_id
1330 return(SMS_SUCCESS);
1334 /* followup_anfq: Add allocation to nfsphys after creating quota.
1335 * argv[0] = filsys_id
1336 * argv[2] = ascii(quota)
1339 followup_anfq(q, argv, cl)
1344 ## int quota, user, fs, who;
1347 fs = *(int *)argv[0];
1348 user = *(int *)argv[1];
1349 quota = atoi(argv[2]);
1351 entity = cl->entity;
1353 ## repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1354 ## where nq.filsys_id = @fs and nq.users_id = @user
1355 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1356 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1357 return(SMS_SUCCESS);
1364 followup_gzcl(q, sq, v, action, actarg, cl)
1365 register struct query *q;
1366 register struct save_queue *sq;
1367 register struct validate *v;
1368 register int (*action)();
1373 ## int rowcount, id;
1377 while (sq_get_data(sq, &argv)) {
1378 sms_trim_args(q->vcnt, argv);
1380 id = atoi(argv[i = q->vcnt - 2]);
1382 name = argv[i] = malloc(9);
1383 ## repeat retrieve (name = users.login) where users.users_id = @id
1384 ## inquire_equel(rowcount = "rowcount")
1386 sprintf(argv[i], "#%d", id);
1388 for (i = 1; i < 8; i+=2) {
1389 id = atoi(argv[i+1]);
1391 if ((name = argv[i+1] = malloc(33)) == NULL)
1393 if (!strcmp(argv[i], "LIST")) {
1394 ## repeat retrieve (name = list.#name) where list.list_id = @id
1395 ## inquire_equel(rowcount = "rowcount")
1397 strcpy(name, "???");
1398 } else if (!strcmp(argv[i], "USER")) {
1399 ## repeat retrieve (name = users.login) where users.users_id = @id
1400 ## inquire_equel(rowcount = "rowcount")
1402 strcpy(name, "???");
1403 } else if (!strcmp(argv[i], "NONE")) {
1404 strcpy(name, "NONE");
1406 strcpy(name, "???");
1411 (*action)(q->vcnt, argv, actarg);
1413 /* free saved data */
1414 for (i = 0; i < q->vcnt; i++)
1419 return(SMS_SUCCESS);
1426 followup_gsha(q, sq, v, action, actarg, cl)
1427 register struct query *q;
1428 register struct save_queue *sq;
1429 register struct validate *v;
1430 register int (*action)();
1435 ## int rowcount, id;
1439 while (sq_get_data(sq, &argv)) {
1440 sms_trim_args(q->vcnt, argv);
1444 name = argv[4] = malloc(9);
1445 ## repeat retrieve (name = users.login) where users.users_id = @id
1446 ## inquire_equel(rowcount = "rowcount")
1448 sprintf(argv[4], "#%d", id);
1452 if ((name = argv[2] = malloc(33)) == NULL)
1454 if (!strcmp(argv[1], "LIST")) {
1455 ## repeat retrieve (name = list.#name) where list.list_id = @id
1456 ## inquire_equel(rowcount = "rowcount")
1458 strcpy(name, "???");
1459 } else if (!strcmp(argv[1], "USER")) {
1460 ## repeat retrieve (name = users.login) where users.users_id = @id
1461 ## inquire_equel(rowcount = "rowcount")
1463 strcpy(name, "???");
1464 } else if (!strcmp(argv[1], "NONE")) {
1465 strcpy(name, "NONE");
1467 strcpy(name, "???");
1471 (*action)(q->vcnt, argv, actarg);
1473 /* free saved data */
1474 for (i = 0; i < q->vcnt; i++)
1479 return(SMS_SUCCESS);
1484 /* Special query routines */
1486 /* set_pobox - this does all of the real work.
1487 * argv = user_id, type, box
1488 * if type is POP, then box should be a machine, and its ID should be put in
1489 * pop_id. If type is SMTP, then box should be a string and its ID should
1490 * be put in box_id. If type is NONE, then box doesn't matter.
1493 int set_pobox(q, argv, cl)
1498 ## int user, id, rowcount;
1499 ## char *box, potype[9];
1502 user = *(int *)argv[0];
1504 ## repeat retrieve (id = users.pop_id, potype = users.#potype)
1505 ## where users.users_id = @user
1506 if (!strcmp(strtrim(potype), "POP"))
1507 set_pop_usage(id, -1);
1509 if (!strcmp(argv[1], "POP")) {
1510 ## repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1511 ## inquire_equel(rowcount = "rowcount")
1513 return(SMS_MACHINE);
1514 ## repeat replace users (#potype = "POP", pop_id = @id)
1515 ## where users.users_id = @user
1516 set_pop_usage(id, 1);
1517 } else if (!strcmp(argv[1], "SMTP")) {
1518 ## range of s is strings
1519 ## repeat retrieve (id = s.string_id) where s.string = @box
1520 ## inquire_equel (rowcount = "rowcount")
1521 if (rowcount == 0) {
1522 ## range of v is values
1523 ## repeat retrieve (id = v.value) where v.name = "strings_id"
1525 ## repeat replace v (value = @id) where v.name = "strings_id"
1526 ## append to strings (string_id = id, string = box)
1528 ## repeat replace users (#potype = "SMTP", box_id = @id)
1529 ## where users.users_id = @user
1530 } else /* argv[1] == "NONE" */ {
1531 ## repeat replace users (#potype = "NONE") where users.users_id = @user
1534 set_pobox_modtime(q, argv, cl);
1535 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1536 ## where tblstats.#table = "users"
1537 return(SMS_SUCCESS);
1541 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1542 * each list. This is tricky: first build a queue of all requested
1543 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1546 get_list_info(q, aargv, cl, action, actarg)
1547 register struct query *q;
1550 register int (*action)();
1553 char *argv[13], *malloc(), *realloc();
1554 ## char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1555 ## char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1556 ## char modby[9], modwith[9];
1557 ## int id, rowcount, acl_id, hid, modby_id;
1559 struct save_queue *sq, *sq_create();
1561 returned = rowcount = 0;
1565 ## range of l is list
1566 ## repeat retrieve (id = l.list_id) where l.#name = @name {
1567 sq_save_data(sq, id);
1571 return(SMS_NO_MATCH);
1573 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1574 argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1575 argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1578 while (sq_get_data(sq, &id)) {
1582 ## repeat retrieve (listname = l.#name, active = text(l.#active),
1583 ## public = text(l.#public), hidden = text(l.#hidden),
1584 ## hid = l.#hidden, maillist = text(l.#maillist),
1585 ## group = text(l.#group), gid = text(l.#gid),
1586 ## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1587 ## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1588 ## modwith =l.#modwith)
1589 ## where l.list_id = @id
1591 if (atoi(gid) == -1)
1592 argv[6] = UNIQUE_GID;
1594 if (!strcmp(acl_type, "LIST")) {
1595 ## repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1596 ## inquire_equel(rowcount = "rowcount")
1598 strcpy(acl_name, "???");
1599 } else if (!strcmp(acl_type, "USER")) {
1600 ## repeat retrieve (acl_name = users.#login)
1601 ## where users.users_id = @acl_id
1602 ## inquire_equel(rowcount = "rowcount")
1604 strcpy(acl_name, "???");
1605 } else if (!strcmp(acl_type, "NONE")) {
1606 strcpy(acl_name, "NONE");
1608 strcpy(acl_name, "???");
1610 ## repeat retrieve (modby = users.login) where users.users_id = @modby_id
1611 ## inquire_equel(rowcount = "rowcount")
1613 sprintf(modby, "#%d", id);
1615 sms_trim_args(q->vcnt, argv);
1617 (*action)(q->vcnt, argv, actarg);
1621 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1622 ## where tblstats.#table = "list"
1624 return (SMS_SUCCESS);
1628 /* get_ace_use - given a type and a name, return a type and a name.
1629 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1630 * and argv[1] will contain the ID of the entity in question. The R*
1631 * types mean to recursively look at every containing list, not just
1632 * when the object in question is a direct member. On return, the
1633 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1636 int get_ace_use(q, argv, cl, action, actarg)
1645 ## int aid, listid, id;
1646 struct save_queue *sq, *sq_create();
1649 aid = *(int *)argv[1];
1650 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER")) {
1651 return(get_ace_internal(atype, aid, action, actarg));
1655 if (!strcmp(atype, "RLIST")) {
1656 sq_save_data(sq, aid);
1657 /* get all the list_id's of containing lists */
1658 ## range of m is members
1659 while (sq_get_data(sq, &id)) {
1660 ## repeat retrieve (listid = m.list_id)
1661 ## where m.member_type = "LIST" and m.member_id = @id {
1662 sq_save_unique_data(sq, listid);
1665 /* now process each one */
1666 while (sq_get_data(sq, &id)) {
1667 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1672 if (!strcmp(atype, "RUSER")) {
1673 ## range of m is members
1674 ## repeat retrieve (listid = m.list_id)
1675 ## where m.member_type = "USER" and m.member_id = @aid {
1676 sq_save_data(sq, listid);
1678 /* get all the list_id's of containing lists */
1679 while (sq_get_data(sq, &id)) {
1680 ## repeat retrieve (listid = m.list_id)
1681 ## where m.member_type = "LIST" and m.member_id = @id {
1682 sq_save_unique_data(sq, listid);
1685 /* now process each one */
1686 while (sq_get_data(sq, &id)) {
1687 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1690 if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1695 if (!found) return(SMS_NO_MATCH);
1696 return(SMS_SUCCESS);
1700 /* This looks up a single list or user for ace use. atype must be "USER"
1701 * or "LIST", and aid is the ID of the corresponding object. This is used
1702 * by get_ace_use above.
1705 ##get_ace_internal(atype, aid, action, actarg)
1716 if (!strcmp(atype, "LIST")) {
1717 rargv[0] = "FILESYS";
1718 ## repeat retrieve (name = filesys.label)
1719 ## where filesys.owners = @aid {
1720 (*action)(2, rargv, actarg);
1725 ## repeat retrieve (name = capacls.capability)
1726 ## where capacls.list_id = @aid {
1727 (*action)(2, rargv, actarg);
1730 } else if (!strcmp(atype, "USER")) {
1731 rargv[0] = "FILESYS";
1732 ## repeat retrieve (name = filesys.label)
1733 ## where filesys.owner = @aid {
1734 (*action)(2, rargv, actarg);
1740 ## repeat retrieve (name = list.#name)
1741 ## where list.acl_type = @atype and list.acl_id = @aid {
1742 (*action)(2, rargv, actarg);
1746 rargv[0] = "SERVICE";
1747 ## repeat retrieve (name = servers.#name)
1748 ## where servers.acl_type = @atype and servers.acl_id = @aid {
1749 (*action)(2, rargv, actarg);
1753 rargv[0] = "HOSTACCESS";
1754 ## repeat retrieve (name = machine.#name)
1755 ## where machine.mach_id = hostaccess.mach_id and
1756 ## hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1757 (*action)(2, rargv, actarg);
1760 rargv[0] = "ZEPHYR";
1761 ## repeat retrieve (name = zephyr.class)
1762 ## where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
1763 ## zephyr.sub_type = @atype and zephyr.sub_id = @aid or
1764 ## zephyr.iws_type = @atype and zephyr.iws_id = @aid or
1765 ## zephyr.iui_type = @atype and zephyr.iui_id = @aid {
1766 (*action)(2, rargv, actarg);
1770 if (!found) return(SMS_NO_MATCH);
1771 return(SMS_SUCCESS);
1775 /* get_lists_of_member - given a type and a name, return the name and flags
1776 * of all of the lists of the given member. The member_type is one of
1777 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1778 * and argv[1] will contain the ID of the entity in question. The R*
1779 * types mean to recursively look at every containing list, not just
1780 * when the object in question is a direct member.
1783 int get_lists_of_member(q, argv, cl, action, actarg)
1792 ## int aid, listid, id;
1793 struct save_queue *sq, *sq_create();
1796 aid = *(int *)argv[1];
1797 if (!strcmp(atype, "LIST") ||
1798 !strcmp(atype, "USER") ||
1799 !strcmp(atype, "STRING")) {
1800 return(glom_internal(atype, aid, action, actarg));
1804 if (!strcmp(atype, "RLIST")) {
1805 sq_save_data(sq, aid);
1806 /* get all the list_id's of containing lists */
1807 ## range of m is members
1808 while (sq_get_data(sq, &id)) {
1809 ## repeat retrieve (listid = m.list_id)
1810 ## where m.member_type = "LIST" and m.member_id = @id {
1811 sq_save_unique_data(sq, listid);
1814 /* now process each one */
1815 while (sq_get_data(sq, &id)) {
1816 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1821 if (!strcmp(atype, "RUSER")) {
1822 ## range of m is members
1823 ## repeat retrieve (listid = m.list_id)
1824 ## where m.member_type = "USER" and m.member_id = @aid {
1825 sq_save_data(sq, listid);
1827 /* get all the list_id's of containing lists */
1828 while (sq_get_data(sq, &id)) {
1829 ## repeat retrieve (listid = m.list_id)
1830 ## where m.member_type = "LIST" and m.member_id = @id {
1831 sq_save_unique_data(sq, listid);
1834 /* now process each one */
1835 while (sq_get_data(sq, &id)) {
1836 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1839 if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1843 if (!strcmp(atype, "RSTRING")) {
1844 ## range of m is members
1845 ## repeat retrieve (listid = m.list_id)
1846 ## where m.member_type = "STRING" and m.member_id = @aid {
1847 sq_save_data(sq, listid);
1849 /* get all the list_id's of containing lists */
1850 while (sq_get_data(sq, &id)) {
1851 ## repeat retrieve (listid = m.list_id)
1852 ## where m.member_type = "LIST" and m.member_id = @id {
1853 sq_save_unique_data(sq, listid);
1856 /* now process each one */
1857 while (sq_get_data(sq, &id)) {
1858 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1861 if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
1865 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1866 ## where tblstats.#table = "members"
1868 if (!found) return(SMS_NO_MATCH);
1869 return(SMS_SUCCESS);
1873 /* This looks up a single list, user, or string as a member. atype must be
1874 * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
1875 * This is used by get_lists_of_members above.
1878 ##glom_internal(atype, aid, action, actarg)
1886 ## char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
1892 rargv[4] = maillist;
1894 ## repeat retrieve (name = list.#name, active = text(list.#active),
1895 ## public = text(list.#public), hidden = text(list.#hidden),
1896 ## maillist = text(list.#maillist), group = text(list.#group))
1897 ## where list.list_id = m.list_id and
1898 ## m.member_type = @atype and m.member_id = @aid {
1899 (*action)(6, rargv, actarg);
1903 if (!found) return(SMS_NO_MATCH);
1904 return(SMS_SUCCESS);
1908 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1909 * the five flags associated with each list. It will return the name of
1910 * each list that meets the quailifications. It does this by building a
1911 * where clause based on the arguments, then doing a retrieve.
1914 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
1916 int qualified_get_lists(q, argv, cl, action, actarg)
1923 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
1924 "l", "name", lflags));
1928 /** get_members_of_list - optimized query for retrieval of list members
1931 ** argv[0] - list_id
1934 ** - retrieve USER members, then LIST members, then STRING members
1937 get_members_of_list(q, argv, cl, action, actarg)
1945 ## char member_name[129];
1948 list_id = *(int *)argv[0];
1950 targv[1] = member_name;
1952 ## range of m is members
1953 ## repeat retrieve (member_name = users.login)
1954 ## where m.#list_id = @list_id and m.member_type = "USER"
1955 ## and m.member_id = users.users_id
1956 ## sort by #member_name
1958 (*action)(2, targv, actarg);
1962 ## repeat retrieve (member_name = list.name)
1963 ## where m.#list_id = @list_id and m.member_type = "LIST"
1964 ## and m.member_id = list.#list_id
1965 ## sort by #member_name
1967 (*action)(2, targv, actarg);
1970 targv[0] = "STRING";
1971 ## repeat retrieve (member_name = strings.string)
1972 ## where m.#list_id = @list_id and m.member_type = "STRING"
1973 ## and m.member_id = strings.string_id
1974 ## sort by #member_name
1976 (*action)(2, targv, actarg);
1979 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1980 ## where tblstats.#table = "members"
1981 return(SMS_SUCCESS);
1985 /* count_members_of_list: this is a simple query, but it cannot be done
1986 * through the dispatch table.
1989 int count_members_of_list(q, argv, cl, action, actarg)
1996 ## int list, ct = 0;
1997 char *rargv[1], countbuf[5];
1999 list = *(int *)argv[0];
2000 rargv[0] = countbuf;
2001 ## repeat retrieve (ct = count(members.list_id where members.list_id = @list))
2002 sprintf(countbuf, "%d", ct);
2003 (*action)(1, rargv, actarg);
2004 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2005 ## where tblstats.#table = "members"
2006 return(SMS_SUCCESS);
2010 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2011 * the three flags associated with each service. It will return the name of
2012 * each service that meets the quailifications. It does this by building a
2013 * where clause based on the arguments, then doing a retrieve.
2016 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2018 int qualified_get_server(q, argv, cl, action, actarg)
2025 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2026 "s", "name", sflags));
2030 /* generic qualified get routine, used by qualified_get_lists,
2031 * qualified_get_server, and qualified_get_serverhost.
2033 * start - a simple where clause, must not be empty
2034 * range - the name of the range variable
2035 * field - the field to return
2036 * flags - an array of strings, names of the flag variables
2039 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2049 ## char name[33], qual[256], *rvar, *rtbl, *rfield;
2050 char *rargv[1], buf[32];
2053 strcpy(qual, start);
2054 for (i = 0; i < q->argc; i++) {
2055 if (!strcmp(argv[i], "TRUE")) {
2056 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2057 (void) strcat(qual, buf);
2058 } else if (!strcmp(argv[i], "FALSE")) {
2059 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2060 (void) strcat(qual, buf);
2068 ## range of rvar is rtbl
2069 ## retrieve (name = rvar.rfield) where qual {
2070 (*action)(1, rargv, actarg);
2072 ## inquire_equel(rowcount = "rowcount")
2073 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2074 ## where tblstats.#table = @rtbl
2076 return(SMS_NO_MATCH);
2077 return(SMS_SUCCESS);
2081 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2082 * the five flags associated with each serverhost. It will return the name of
2083 * each service and host that meets the quailifications. It does this by
2084 * building a where clause based on the arguments, then doing a retrieve.
2087 static char *shflags[6] = { "service", "enable", "override", "success",
2088 "inprogress", "hosterror" };
2090 int qualified_get_serverhost(q, argv, cl, action, actarg)
2097 ## char sname[33], mname[33], qual[256];
2098 char *rargv[2], buf[32];
2101 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2103 for (i = 1; i < q->argc; i++) {
2104 if (!strcmp(argv[i], "TRUE")) {
2105 sprintf(buf, " and sh.%s != 0", shflags[i]);
2107 } else if (!strcmp(argv[i], "FALSE")) {
2108 sprintf(buf, " and sh.%s = 0", shflags[i]);
2115 ## range of sh is serverhosts
2116 ## retrieve (sname = sh.service, mname = machine.name) where qual {
2117 (*action)(2, rargv, actarg);
2119 ## inquire_equel(rowcount = "rowcount")
2120 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2121 ## where tblstats.#table = "serverhosts"
2123 return(SMS_NO_MATCH);
2124 return(SMS_SUCCESS);
2128 /* register_user - change user's login name and allocate a pobox, group,
2129 * filesystem, and quota for them. The user's status must start out as 0,
2130 * and is left as 2. Arguments are: user's UID, new login name, and user's
2131 * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY,
2132 * SMS_FS_STAFF, SMS_FS_MISC).
2135 register_user(q, argv, cl)
2140 ## char *login, dir[65], *entity, *directory, machname[33];
2141 ## int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2142 ## int size, alloc, pid, m_id;
2145 entity = cl->entity;
2148 uid = atoi(argv[0]);
2150 utype = atoi(argv[2]);
2152 ## range of u is users
2153 ## range of l is list
2154 ## range of sh is serverhosts
2155 ## range of n is nfsphys
2156 ## range of m is machine
2159 ## repeat retrieve (users_id = u.#users_id)
2160 ## where u.#uid = @uid and u.status = 0
2161 ## inquire_equel(rowcount = "rowcount");
2163 return(SMS_NO_MATCH);
2165 return(SMS_NOT_UNIQUE);
2167 /* check new login name */
2168 ## repeat retrieve (flag = any(u.#login where u.#login = @login))
2171 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2174 ## repeat retrieve (flag = any(filesys.#name where filesys.#name = @login))
2177 com_err(whoami, 0, "new login name OK");
2179 /* choose place for pobox, put in mid */
2180 ## repeat retrieve (mid = sh.mach_id, machname = m.name)
2181 ## where sh.service = "POP" and m.mach_id = sh.mach_id and
2182 ## sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2183 ## inquire_equel(rowcount = "rowcount");
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");
2195 return(SMS_INTERNAL);
2196 set_pop_usage(mid, 1);
2197 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2200 /* create group list */
2201 if (set_next_object_id("gid", "list"))
2203 if (set_next_object_id("list_id", "list"))
2205 ## repeat retrieve (list_id = values.value) where values.name = "list_id"
2206 ## inquire_equel(rowcount = "rowcount");
2208 return(SMS_INTERNAL);
2209 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2210 ## public = 0, hidden = 0, maillist = 0, group = 1,
2211 ## #gid = values.value, desc = "User Group",
2212 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2213 ## modby = @who, modwith = @entity)
2214 ## where values.name = "gid"
2215 ## inquire_equel(rowcount = "rowcount");
2217 return(SMS_INTERNAL);
2218 ## repeat append members (#list_id = @list_id, member_type = "USER",
2219 ## member_id = @users_id)
2220 ## inquire_equel(rowcount = "rowcount");
2222 return(SMS_INTERNAL);
2223 com_err(whoami, 0, "group list created");
2225 /* decide where to put filesystem */
2228 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2229 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2230 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2231 maxsize = size - alloc;
2234 directory = strsave(dir);
2240 return(SMS_NO_FILESYS);
2242 /* create filesystem */
2243 if (set_next_object_id("filsys_id", "filesys"))
2245 ## repeat append filesys (filsys_id = values.value, phys_id = @pid,
2246 ## label = @login, type = "NFS", mach_id = @m_id,
2247 ## name = @directory + "/" + @login,
2248 ## mount = "/mit/" + @login,
2249 ## access = "w", comments = "User Locker",
2250 ## owner = @users_id, owners = @list_id, createflg = 1,
2251 ## lockertype = "HOMEDIR", modtime = "now",
2252 ## modby = @who, modwith = @entity)
2253 ## where values.name = "filsys_id"
2254 ## inquire_equel(rowcount = "rowcount");
2256 return(SMS_INTERNAL);
2257 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2261 ## repeat retrieve (quota = values.value) where values.name = "def_quota"
2262 ## inquire_equel(rowcount = "rowcount");
2264 return(SMS_NO_QUOTA);
2265 ## repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2266 ## #quota = @quota, phys_id = @pid, modtime = "now",
2267 ## modby = @who, modwith = @entity)
2268 ## where values.name = "filsys_id"
2269 ## inquire_equel(rowcount = "rowcount");
2271 return(SMS_INTERNAL);
2272 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2273 ## where nfsphys.nfsphys_id = filesys.#phys_id and
2274 ## filesys.filsys_id = values.value and values.name = "filsys_id"
2275 ## inquire_equel(rowcount = "rowcount");
2277 return(SMS_INTERNAL);
2278 com_err(whoami, 0, "quota of %d assigned", quota);
2280 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2281 ## where tblstats.table = "users"
2282 ## repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2283 ## where tblstats.table = "list" or tblstats.table = "filesys" or
2284 ## tblstats.table = "nfsquota"
2285 return(SMS_SUCCESS);
2290 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2294 ** delta (will be +/- 1)
2297 ** - incr/decr value field in serverhosts table for pop/mach_id
2301 static int set_pop_usage(id, count)
2305 ## int mach_id = id;
2308 ## range of sh is serverhosts
2309 ## repeat replace sh (value1 = sh.value1 + @n)
2310 ## where sh.service = "POP" and sh.#mach_id = @mach_id
2312 return(SMS_SUCCESS);
2317 /* Validation Routines */
2319 validate_row(q, argv, v)
2320 register struct query *q;
2322 register struct validate *v;
2330 /* build where clause */
2331 build_qual(v->qual, v->argc, argv, qual);
2333 /* setup ingres variables */
2338 if (log_flags & LOG_VALID)
2339 /* tell the logfile what we're doing */
2340 com_err(whoami, 0, "validating row: %s", qual);
2342 /* look for the record */
2343 ## range of rvar is table
2344 ## retrieve (rowcount = count(rvar.name where qual))
2345 if (rowcount == 0) return(SMS_NO_MATCH);
2346 if (rowcount > 1) return(SMS_NOT_UNIQUE);
2350 validate_fields(q, argv, vo, n)
2352 register char *argv[];
2353 register struct valobj *vo;
2356 register int status;
2361 if (log_flags & LOG_VALID)
2362 com_err(whoami, 0, "validating %s in %s: %s",
2363 vo->namefield, vo->table, argv[vo->index]);
2364 status = validate_name(argv, vo);
2368 if (log_flags & LOG_VALID)
2369 com_err(whoami, 0, "validating %s in %s: %s",
2370 vo->idfield, vo->table, argv[vo->index]);
2371 status = validate_id(argv, vo);
2375 if (log_flags & LOG_VALID)
2376 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2377 status = validate_date(argv, vo);
2381 if (log_flags & LOG_VALID)
2382 com_err(whoami, 0, "validating %s type: %s",
2383 vo->table, argv[vo->index]);
2384 status = validate_type(argv, vo);
2388 if (log_flags & LOG_VALID)
2389 com_err(whoami, 0, "validating typed data (%s): %s",
2390 argv[vo->index - 1], argv[vo->index]);
2391 status = validate_typedata(q, argv, vo);
2395 if (log_flags & LOG_VALID)
2396 com_err(whoami, 0, "validating rename %s in %s",
2397 argv[vo->index], vo->table);
2398 status = validate_rename(argv, vo);
2402 if (log_flags & LOG_VALID)
2403 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2404 status = validate_chars(argv[vo->index]);
2408 status = SMS_EXISTS;
2413 if (status != SMS_EXISTS) return(status);
2417 return(SMS_SUCCESS);
2421 /* validate_chars: verify that there are no illegal characters in
2422 * the string. Legal characters are printing chars other than
2423 * ", *, ?, \, [ and ].
2425 static int illegalchars[] = {
2426 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2427 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2428 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2429 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2430 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2431 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2433 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2434 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2435 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2436 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2437 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2438 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2439 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2440 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2441 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2448 if (illegalchars[*s++])
2449 return(SMS_BAD_CHAR);
2454 validate_id(argv, vo)
2456 register struct valobj *vo;
2466 name = argv[vo->index];
2468 /* minor kludge to upcasify machine names */
2469 if (!strcmp(table, "machine"))
2470 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2471 namefield = vo->namefield;
2472 idfield = vo->idfield;
2473 if (!strcmp(namefield, "uid")) {
2474 ## retrieve (id = table.idfield) where table.namefield = int4(name)
2475 ## inquire_equel (rowcount = "rowcount")
2477 ## retrieve (id = table.idfield) where table.namefield = name
2478 ## inquire_equel (rowcount = "rowcount")
2480 if (rowcount != 1) return(vo->error);
2481 *(int *)argv[vo->index] = id;
2485 validate_name(argv, vo)
2487 register struct valobj *vo;
2495 name = argv[vo->index];
2497 namefield = vo->namefield;
2498 if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2499 for (c = name; *c; c++)
2503 ## retrieve (rowcount = countu(table.namefield
2504 ## where table.namefield = name))
2505 return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2508 validate_date(argv, vo)
2516 idate = argv[vo->index];
2518 ## retrieve (dd = interval("years", date(idate) - date("today")))
2519 ## inquire_equel (errorno = "errorno")
2520 if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2525 validate_rename(argv, vo)
2529 ## char *name, *table, *namefield, *idfield;
2533 c = name = argv[vo->index];
2535 if (illegalchars[*c++])
2536 return(SMS_BAD_CHAR);
2538 /* minor kludge to upcasify machine names */
2539 if (!strcmp(table, "machine"))
2540 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2541 namefield = vo->namefield;
2542 idfield = vo->idfield;
2545 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2547 ## retrieve (id = any(table.namefield where table.namefield = name))
2553 ## retrieve (id = table.idfield) where table.namefield = name
2554 if (id == -1 || id == *(int *)argv[vo->index - 1])
2561 validate_type(argv, vo)
2563 register struct valobj *vo;
2570 typename = vo->table;
2571 c = value = argv[vo->index];
2573 if (illegalchars[*c++])
2574 return(SMS_BAD_CHAR);
2576 /* uppercase type fields */
2577 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2579 ## range of a is alias
2580 ## repeat retrieve (exists = any(a.trans where a.name = @typename and
2581 ## a.type = "TYPE" and
2582 ## a.trans = @value))
2583 return (exists ? SMS_EXISTS : vo->error);
2586 /* validate member or type-specific data field */
2588 validate_typedata(q, argv, vo)
2589 register struct query *q;
2590 register char *argv[];
2591 register struct valobj *vo;
2594 ## char *field_type;
2595 ## char data_type[129];
2601 /* get named object */
2602 name = argv[vo->index];
2604 /* get field type string (known to be at index-1) */
2605 field_type = argv[vo->index-1];
2607 /* get corresponding data type associated with field type name */
2608 ## repeat retrieve (data_type = alias.trans)
2609 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
2610 ## inquire_equel (rowcount = "rowcount")
2611 if (rowcount != 1) return(SMS_TYPE);
2613 /* now retrieve the record id corresponding to the named object */
2614 if (index(data_type, ' '))
2615 *index(data_type, ' ') = 0;
2616 if (!strcmp(data_type, "user")) {
2618 ## repeat retrieve (id = users.users_id) where users.login = @name
2619 ## inquire_equel (rowcount = "rowcount")
2620 if (rowcount != 1) return(SMS_USER);
2622 } else if (!strcmp(data_type, "list")) {
2624 ## repeat retrieve (id = list.list_id) where list.#name = @name
2625 ## inquire_equel (rowcount = "rowcount")
2626 if (rowcount != 1) {
2627 /* if idfield is non-zero, then if argv[0] matches the string
2628 * that we're trying to resolve, we should get the value of
2629 * values.[idfield] for the id.
2631 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2632 set_next_object_id(q->validate->object_id, q->rtable);
2634 ## repeat retrieve (id = values.value) where values.#name = @name
2635 ## inquire_equel(rowcount = "rowcount")
2636 if (rowcount != 1) return(SMS_LIST);
2640 } else if (!strcmp(data_type, "machine")) {
2642 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2643 ## repeat retrieve (id = machine.mach_id) where machine.#name = @name
2644 ## inquire_equel (rowcount = "rowcount")
2645 if (rowcount != 1) return(SMS_MACHINE);
2647 } else if (!strcmp(data_type, "string")) {
2649 ## range of s is strings
2650 ## repeat retrieve (id = s.string_id) where s.string = @name
2651 ## inquire_equel (rowcount = "rowcount")
2652 if (rowcount == 0) {
2653 if (q->type != APPEND) return(SMS_STRING);
2654 ## range of v is values
2655 ## retrieve (id = v.value) where v.#name = "strings_id"
2657 ## replace v (value = id) where v.#name = "strings_id"
2658 ## append to strings (string_id = id, string = name)
2660 } else if (!strcmp(data_type, "none")) {
2666 /* now set value in argv */
2667 *(int *)argv[vo->index] = id;
2669 return (SMS_EXISTS);
2673 /* This looks up a login name and returns the SMS internal ID. It is used
2674 * by authenticate to put the users_id in the client structure.
2677 int get_users_id(name)
2680 ## int id, rowcount;
2685 ## range of u is users
2686 ## repeat retrieve (id = u.#users_id) where u.#login = @login
2687 ## inquire_equel (rowcount = "rowcount")
2696 /* Check the database at startup time. For now this just resets the
2697 * inprogress flags that the DCM uses.
2700 sanity_check_database()