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 /* Like set_modtime, but uppercases the name first.
897 set_uppercase_modtime(q, argv, cl)
902 ## char *name, *entity, *table;
910 ## replace table (modtime = "now", modby = who, modwith = entity)
911 ## where table.#name = uppercase(name)
916 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
917 * is necessary for add_machine_to_cluster becuase the table that query
918 * operates on is "mcm", not "machine".
921 set_mach_modtime_by_id(q, argv, cl)
932 id = *(int *)argv[0];
933 ## range of m is machine
934 ## repeat replace m (modtime = "now", modby = @who, modwith = @entity)
935 ## where m.mach_id = @id
940 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
941 * is necessary for add_cluster_data and delete_cluster_data becuase the
942 * table that query operates on is "svc", not "cluster".
945 set_cluster_modtime_by_id(q, argv, cl)
956 id = *(int *)argv[0];
957 ## range of c is cluster
958 ## repeat replace c (modtime = "now", modby = @who, modwith = @entity)
959 ## where c.clu_id = @id
964 /* sets the modtime on the serverhost where the service name is in argv[0]
965 * and the mach_id is in argv[1].
968 set_serverhost_modtime(q, argv, cl)
973 ## char *entity, *serv;
980 id = *(int *)argv[1];
981 ## repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
982 ## where sh.service = uppercase(@serv) and sh.mach_id = @id
987 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
988 * directory name is in argv[1].
991 set_nfsphys_modtime(q, argv, cl)
996 ## char *entity, *dir;
1002 id = *(int *)argv[0];
1004 ## repeat replace np (modtime = "now", modby = @who, modwith = @entity)
1005 ## where np.#dir = @dir and np.mach_id = @id
1006 return(SMS_SUCCESS);
1010 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1014 set_filesys_modtime(q, argv, cl)
1019 ## char *label, *entity;
1022 entity = cl->entity;
1026 if (!strcmp(q->shortname, "ufil"))
1029 ## repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1030 ## #phys_id = @var_phys_id) where fs.#label = @label
1031 return(SMS_SUCCESS);
1035 /* sets the modtime on a zephyr class, where argv[0] contains the class
1039 set_zephyr_modtime(q, argv, cl)
1044 ## char *class, *entity;
1047 entity = cl->entity;
1052 ## repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1053 ## where z.#class = @class
1054 return(SMS_SUCCESS);
1058 /* fixes the modby field. This will be the second to last thing in the
1059 * argv, the argv length is determined from the query structure. It is
1060 * passed as a pointer to an integer. This will either turn it into a
1061 * username, or # + the users_id.
1063 followup_fix_modby(q, sq, v, action, actarg, cl)
1065 register struct save_queue *sq;
1067 register int (*action)();
1068 register int actarg;
1072 char **argv, *malloc();
1073 ## int id, rowcount;
1077 while (sq_get_data(sq, &argv)) {
1080 argv[i] = malloc(9);
1082 ## repeat retrieve (name = users.login) where users.users_id = @id
1083 ## inquire_equel(rowcount = "rowcount")
1084 if (rowcount != 1) {
1085 sprintf(argv[i], "#%d", id);
1087 (*action)(q->vcnt, argv, actarg);
1088 for (j = 0; j < q->vcnt; j++)
1093 return(SMS_SUCCESS);
1098 ** followup_ausr - add finger and pobox entries, set_user_modtime
1101 ** argv[0] - login (add_user)
1102 ** argv[3] - last name
1103 ** argv[4] - first name
1104 ** argv[5] - middle name
1108 followup_ausr(q, argv, cl)
1114 ## char *login, *entity;
1115 ## char fullname[129];
1119 entity = cl->entity;
1121 /* build fullname */
1122 if (strlen(argv[4]) && strlen(argv[5]))
1123 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1124 else if (strlen(argv[4]))
1125 sprintf(fullname, "%s %s", argv[4], argv[3]);
1127 sprintf(fullname, "%s", argv[3]);
1129 /* create finger entry, pobox & set modtime on user */
1130 ## repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1131 ## #fullname=@fullname, mit_affil = u.mit_year,
1132 ## fmodtime="now", fmodby=@who, fmodwith=@entity,
1133 ## potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1134 ## where u.#login = @login
1136 return(SMS_SUCCESS);
1140 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1141 * type in argv[1]. Then completes the upcall to the user.
1143 * argv[2] is of the form "123:234" where the first integer is the machine
1144 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1145 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1149 followup_gpob(q, sq, v, action, actarg, cl)
1150 register struct query *q;
1151 register struct save_queue *sq;
1152 register struct validate *v;
1153 register int (*action)();
1157 char **argv, *index();
1159 ## char box[129], *name;
1160 ## int mid, sid, rowcount;
1163 while (sq_get_data(sq, &argv)) {
1164 sms_trim_args(2, argv);
1166 p = index(argv[2], ':');
1168 mid = atoi(argv[2]);
1172 if (!strcmp(ptype, "POP")) {
1173 ## repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1174 ## inquire_equel(rowcount = "rowcount")
1176 return(SMS_MACHINE);
1177 } else if (!strcmp(ptype, "SMTP")) {
1178 ## repeat retrieve (box=strings.string) where strings.string_id=@sid
1179 ## inquire_equel(rowcount = "rowcount")
1182 } else /* ptype == "NONE" */ {
1186 if (!strcmp(q->shortname, "gpob")) {
1187 sid = atoi(argv[4]);
1189 argv[4] = malloc(9);
1191 ## repeat retrieve (name = users.login) where users.users_id = @sid
1192 ## inquire_equel(rowcount = "rowcount")
1194 sprintf(name, "#%d", sid);
1198 (*action)(q->vcnt, argv, actarg);
1200 /* free saved data */
1207 return (SMS_SUCCESS);
1211 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1212 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1213 * proper name based on the type, and repace that string in the argv.
1214 * Also fixes the modby field by called followup_fix_modby.
1217 followup_glin(q, sq, v, action, actarg, cl)
1218 register struct query *q;
1219 register struct save_queue *sq;
1220 register struct validate *v;
1221 register int (*action)();
1225 char **argv, *malloc(), *realloc(), *type;
1227 ## int id, rowcount;
1231 if (!strcmp(q->shortname, "gsin"))
1234 while (sq_get_data(sq, &argv)) {
1235 sms_trim_args(q->vcnt, argv);
1237 id = atoi(argv[i = q->vcnt - 2]);
1239 name = argv[i] = malloc(9);
1240 ## repeat retrieve (name = users.login) where users.users_id = @id
1241 ## inquire_equel(rowcount = "rowcount")
1243 sprintf(argv[i], "#%d", id);
1245 id = atoi(argv[idx]);
1246 type = argv[idx - 1];
1247 if ((name = malloc(33)) == NULL)
1250 if (!strcmp(type, "LIST")) {
1251 ## repeat retrieve (name = list.#name) where list.list_id = @id
1252 ## inquire_equel(rowcount = "rowcount")
1254 strcpy(name, "???");
1255 } else if (!strcmp(type, "USER")) {
1256 ## repeat retrieve (name = users.login) where users.users_id = @id
1257 ## inquire_equel(rowcount = "rowcount")
1259 strcpy(name, "???");
1260 } else if (!strcmp(type, "NONE")) {
1261 strcpy(name, "NONE");
1263 strcpy(name, "???");
1267 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1268 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1269 strcpy(argv[6], UNIQUE_GID);
1273 (*action)(q->vcnt, argv, actarg);
1275 /* free saved data */
1276 for (i = 0; i < q->vcnt; i++)
1282 return (SMS_SUCCESS);
1286 /** followup_amtl - followup for amtl and dmfl; when adding a list
1287 ** member to a maillist, make member list a maillist also
1288 ** unless list is a user-group.
1289 ** Then set_list_modtime_by_id.
1292 ** argv[0] - list_id
1293 ** argv[1] - member_type
1294 ** argv[2] - member_id
1298 followup_amtl(q, argv, cl)
1308 list_id = *(int *)argv[0];
1309 entity = cl->entity;
1312 ## range of l is list
1313 ## repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1314 ## where l.#list_id = @list_id
1316 /* if query is not amtl or if member_type is not LIST then return */
1317 if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4))
1318 return(SMS_SUCCESS);
1320 member_id = *(int *)argv[2];
1322 /* is parent list a mailing list? */
1323 ## repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1325 return(SMS_SUCCESS);
1327 /* list is not a user-group; add list to maillist table */
1328 ## repeat replace l (maillist = 1) where l.#list_id = @member_id
1329 return(SMS_SUCCESS);
1333 /* followup_anfq: Add allocation to nfsphys after creating quota.
1334 * argv[0] = filsys_id
1335 * argv[2] = ascii(quota)
1338 followup_anfq(q, argv, cl)
1343 ## int quota, user, fs, who;
1346 fs = *(int *)argv[0];
1347 user = *(int *)argv[1];
1348 quota = atoi(argv[2]);
1350 entity = cl->entity;
1352 ## repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1353 ## where nq.filsys_id = @fs and nq.users_id = @user
1354 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1355 ## where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1356 return(SMS_SUCCESS);
1363 followup_gzcl(q, sq, v, action, actarg, cl)
1364 register struct query *q;
1365 register struct save_queue *sq;
1366 register struct validate *v;
1367 register int (*action)();
1372 ## int rowcount, id;
1376 while (sq_get_data(sq, &argv)) {
1377 sms_trim_args(q->vcnt, argv);
1379 id = atoi(argv[i = q->vcnt - 2]);
1381 name = argv[i] = malloc(9);
1382 ## repeat retrieve (name = users.login) where users.users_id = @id
1383 ## inquire_equel(rowcount = "rowcount")
1385 sprintf(argv[i], "#%d", id);
1387 for (i = 1; i < 8; i+=2) {
1388 id = atoi(argv[i+1]);
1390 if ((name = argv[i+1] = malloc(33)) == NULL)
1392 if (!strcmp(argv[i], "LIST")) {
1393 ## repeat retrieve (name = list.#name) where list.list_id = @id
1394 ## inquire_equel(rowcount = "rowcount")
1396 strcpy(name, "???");
1397 } else if (!strcmp(argv[i], "USER")) {
1398 ## repeat retrieve (name = users.login) where users.users_id = @id
1399 ## inquire_equel(rowcount = "rowcount")
1401 strcpy(name, "???");
1402 } else if (!strcmp(argv[i], "NONE")) {
1403 strcpy(name, "NONE");
1405 strcpy(name, "???");
1410 (*action)(q->vcnt, argv, actarg);
1412 /* free saved data */
1413 for (i = 0; i < q->vcnt; i++)
1418 return(SMS_SUCCESS);
1425 followup_gsha(q, sq, v, action, actarg, cl)
1426 register struct query *q;
1427 register struct save_queue *sq;
1428 register struct validate *v;
1429 register int (*action)();
1434 ## int rowcount, id;
1438 while (sq_get_data(sq, &argv)) {
1439 sms_trim_args(q->vcnt, argv);
1443 name = argv[4] = malloc(9);
1444 ## repeat retrieve (name = users.login) where users.users_id = @id
1445 ## inquire_equel(rowcount = "rowcount")
1447 sprintf(argv[4], "#%d", id);
1451 if ((name = argv[2] = malloc(33)) == NULL)
1453 if (!strcmp(argv[1], "LIST")) {
1454 ## repeat retrieve (name = list.#name) where list.list_id = @id
1455 ## inquire_equel(rowcount = "rowcount")
1457 strcpy(name, "???");
1458 } else if (!strcmp(argv[1], "USER")) {
1459 ## repeat retrieve (name = users.login) where users.users_id = @id
1460 ## inquire_equel(rowcount = "rowcount")
1462 strcpy(name, "???");
1463 } else if (!strcmp(argv[1], "NONE")) {
1464 strcpy(name, "NONE");
1466 strcpy(name, "???");
1470 (*action)(q->vcnt, argv, actarg);
1472 /* free saved data */
1473 for (i = 0; i < q->vcnt; i++)
1478 return(SMS_SUCCESS);
1483 /* Special query routines */
1485 /* set_pobox - this does all of the real work.
1486 * argv = user_id, type, box
1487 * if type is POP, then box should be a machine, and its ID should be put in
1488 * pop_id. If type is SMTP, then box should be a string and its ID should
1489 * be put in box_id. If type is NONE, then box doesn't matter.
1492 int set_pobox(q, argv, cl)
1497 ## int user, id, rowcount;
1498 ## char *box, potype[9];
1501 user = *(int *)argv[0];
1503 ## repeat retrieve (id = users.pop_id, potype = users.#potype)
1504 ## where users.users_id = @user
1505 if (!strcmp(strtrim(potype), "POP"))
1506 set_pop_usage(id, -1);
1508 if (!strcmp(argv[1], "POP")) {
1509 ## repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1510 ## inquire_equel(rowcount = "rowcount")
1512 return(SMS_MACHINE);
1513 ## repeat replace users (#potype = "POP", pop_id = @id)
1514 ## where users.users_id = @user
1515 set_pop_usage(id, 1);
1516 } else if (!strcmp(argv[1], "SMTP")) {
1517 ## range of s is strings
1518 ## repeat retrieve (id = s.string_id) where s.string = @box
1519 ## inquire_equel (rowcount = "rowcount")
1520 if (rowcount == 0) {
1521 ## range of v is values
1522 ## repeat retrieve (id = v.value) where v.name = "strings_id"
1524 ## repeat replace v (value = @id) where v.name = "strings_id"
1525 ## append to strings (string_id = id, string = box)
1527 ## repeat replace users (#potype = "SMTP", box_id = @id)
1528 ## where users.users_id = @user
1529 } else /* argv[1] == "NONE" */ {
1530 ## repeat replace users (#potype = "NONE") where users.users_id = @user
1533 set_pobox_modtime(q, argv, cl);
1534 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1535 ## where tblstats.#table = "users"
1536 return(SMS_SUCCESS);
1540 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1541 * each list. This is tricky: first build a queue of all requested
1542 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1545 get_list_info(q, aargv, cl, action, actarg)
1546 register struct query *q;
1549 register int (*action)();
1552 char *argv[13], *malloc(), *realloc();
1553 ## char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1554 ## char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1555 ## char modby[9], modwith[9];
1556 ## int id, rowcount, acl_id, hid, modby_id;
1558 struct save_queue *sq, *sq_create();
1560 returned = rowcount = 0;
1564 ## range of l is list
1565 ## repeat retrieve (id = l.list_id) where l.#name = @name {
1566 sq_save_data(sq, id);
1570 return(SMS_NO_MATCH);
1572 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1573 argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1574 argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1577 while (sq_get_data(sq, &id)) {
1581 ## repeat retrieve (listname = l.#name, active = text(l.#active),
1582 ## public = text(l.#public), hidden = text(l.#hidden),
1583 ## hid = l.#hidden, maillist = text(l.#maillist),
1584 ## group = text(l.#group), gid = text(l.#gid),
1585 ## acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1586 ## desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1587 ## modwith =l.#modwith)
1588 ## where l.list_id = @id
1590 if (atoi(gid) == -1)
1591 argv[6] = UNIQUE_GID;
1593 if (!strcmp(acl_type, "LIST")) {
1594 ## repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1595 ## inquire_equel(rowcount = "rowcount")
1597 strcpy(acl_name, "???");
1598 } else if (!strcmp(acl_type, "USER")) {
1599 ## repeat retrieve (acl_name = users.#login)
1600 ## where users.users_id = @acl_id
1601 ## inquire_equel(rowcount = "rowcount")
1603 strcpy(acl_name, "???");
1604 } else if (!strcmp(acl_type, "NONE")) {
1605 strcpy(acl_name, "NONE");
1607 strcpy(acl_name, "???");
1609 ## repeat retrieve (modby = users.login) where users.users_id = @modby_id
1610 ## inquire_equel(rowcount = "rowcount")
1612 sprintf(modby, "#%d", id);
1614 sms_trim_args(q->vcnt, argv);
1616 (*action)(q->vcnt, argv, actarg);
1620 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1621 ## where tblstats.#table = "list"
1623 return (SMS_SUCCESS);
1627 /* get_ace_use - given a type and a name, return a type and a name.
1628 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1629 * and argv[1] will contain the ID of the entity in question. The R*
1630 * types mean to recursively look at every containing list, not just
1631 * when the object in question is a direct member. On return, the
1632 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1635 int get_ace_use(q, argv, cl, action, actarg)
1644 ## int aid, listid, id;
1645 struct save_queue *sq, *sq_create();
1648 aid = *(int *)argv[1];
1649 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER")) {
1650 return(get_ace_internal(atype, aid, action, actarg));
1654 if (!strcmp(atype, "RLIST")) {
1655 sq_save_data(sq, aid);
1656 /* get all the list_id's of containing lists */
1657 ## range of m is members
1658 while (sq_get_data(sq, &id)) {
1659 ## repeat retrieve (listid = m.list_id)
1660 ## where m.member_type = "LIST" and m.member_id = @id {
1661 sq_save_unique_data(sq, listid);
1664 /* now process each one */
1665 while (sq_get_data(sq, &id)) {
1666 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1671 if (!strcmp(atype, "RUSER")) {
1672 ## range of m is members
1673 ## repeat retrieve (listid = m.list_id)
1674 ## where m.member_type = "USER" and m.member_id = @aid {
1675 sq_save_data(sq, listid);
1677 /* get all the list_id's of containing lists */
1678 while (sq_get_data(sq, &id)) {
1679 ## repeat retrieve (listid = m.list_id)
1680 ## where m.member_type = "LIST" and m.member_id = @id {
1681 sq_save_unique_data(sq, listid);
1684 /* now process each one */
1685 while (sq_get_data(sq, &id)) {
1686 if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1689 if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1694 if (!found) return(SMS_NO_MATCH);
1695 return(SMS_SUCCESS);
1699 /* This looks up a single list or user for ace use. atype must be "USER"
1700 * or "LIST", and aid is the ID of the corresponding object. This is used
1701 * by get_ace_use above.
1704 ##get_ace_internal(atype, aid, action, actarg)
1715 if (!strcmp(atype, "LIST")) {
1716 rargv[0] = "FILESYS";
1717 ## repeat retrieve (name = filesys.label)
1718 ## where filesys.owners = @aid {
1719 (*action)(2, rargv, actarg);
1724 ## repeat retrieve (name = capacls.capability)
1725 ## where capacls.list_id = @aid {
1726 (*action)(2, rargv, actarg);
1729 } else if (!strcmp(atype, "USER")) {
1730 rargv[0] = "FILESYS";
1731 ## repeat retrieve (name = filesys.label)
1732 ## where filesys.owner = @aid {
1733 (*action)(2, rargv, actarg);
1739 ## repeat retrieve (name = list.#name)
1740 ## where list.acl_type = @atype and list.acl_id = @aid {
1741 (*action)(2, rargv, actarg);
1745 rargv[0] = "SERVICE";
1746 ## repeat retrieve (name = servers.#name)
1747 ## where servers.acl_type = @atype and servers.acl_id = @aid {
1748 (*action)(2, rargv, actarg);
1752 rargv[0] = "HOSTACCESS";
1753 ## repeat retrieve (name = machine.#name)
1754 ## where machine.mach_id = hostaccess.mach_id and
1755 ## hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1756 (*action)(2, rargv, actarg);
1759 rargv[0] = "ZEPHYR";
1760 ## repeat retrieve (name = zephyr.class)
1761 ## where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
1762 ## zephyr.sub_type = @atype and zephyr.sub_id = @aid or
1763 ## zephyr.iws_type = @atype and zephyr.iws_id = @aid or
1764 ## zephyr.iui_type = @atype and zephyr.iui_id = @aid {
1765 (*action)(2, rargv, actarg);
1769 if (!found) return(SMS_NO_MATCH);
1770 return(SMS_SUCCESS);
1774 /* get_lists_of_member - given a type and a name, return the name and flags
1775 * of all of the lists of the given member. The member_type is one of
1776 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1777 * and argv[1] will contain the ID of the entity in question. The R*
1778 * types mean to recursively look at every containing list, not just
1779 * when the object in question is a direct member.
1782 int get_lists_of_member(q, argv, cl, action, actarg)
1791 ## int aid, listid, id;
1792 struct save_queue *sq, *sq_create();
1795 aid = *(int *)argv[1];
1796 if (!strcmp(atype, "LIST") ||
1797 !strcmp(atype, "USER") ||
1798 !strcmp(atype, "STRING")) {
1799 return(glom_internal(atype, aid, action, actarg));
1803 if (!strcmp(atype, "RLIST")) {
1804 sq_save_data(sq, aid);
1805 /* get all the list_id's of containing lists */
1806 ## range of m is members
1807 while (sq_get_data(sq, &id)) {
1808 ## repeat retrieve (listid = m.list_id)
1809 ## where m.member_type = "LIST" and m.member_id = @id {
1810 sq_save_unique_data(sq, listid);
1813 /* now process each one */
1814 while (sq_get_data(sq, &id)) {
1815 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1820 if (!strcmp(atype, "RUSER")) {
1821 ## range of m is members
1822 ## repeat retrieve (listid = m.list_id)
1823 ## where m.member_type = "USER" and m.member_id = @aid {
1824 sq_save_data(sq, listid);
1826 /* get all the list_id's of containing lists */
1827 while (sq_get_data(sq, &id)) {
1828 ## repeat retrieve (listid = m.list_id)
1829 ## where m.member_type = "LIST" and m.member_id = @id {
1830 sq_save_unique_data(sq, listid);
1833 /* now process each one */
1834 while (sq_get_data(sq, &id)) {
1835 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1838 if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1842 if (!strcmp(atype, "RSTRING")) {
1843 ## range of m is members
1844 ## repeat retrieve (listid = m.list_id)
1845 ## where m.member_type = "STRING" and m.member_id = @aid {
1846 sq_save_data(sq, listid);
1848 /* get all the list_id's of containing lists */
1849 while (sq_get_data(sq, &id)) {
1850 ## repeat retrieve (listid = m.list_id)
1851 ## where m.member_type = "LIST" and m.member_id = @id {
1852 sq_save_unique_data(sq, listid);
1855 /* now process each one */
1856 while (sq_get_data(sq, &id)) {
1857 if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1860 if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
1864 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1865 ## where tblstats.#table = "members"
1867 if (!found) return(SMS_NO_MATCH);
1868 return(SMS_SUCCESS);
1872 /* This looks up a single list, user, or string as a member. atype must be
1873 * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
1874 * This is used by get_lists_of_members above.
1877 ##glom_internal(atype, aid, action, actarg)
1885 ## char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
1891 rargv[4] = maillist;
1893 ## repeat retrieve (name = list.#name, active = text(list.#active),
1894 ## public = text(list.#public), hidden = text(list.#hidden),
1895 ## maillist = text(list.#maillist), group = text(list.#group))
1896 ## where list.list_id = m.list_id and
1897 ## m.member_type = @atype and m.member_id = @aid {
1898 (*action)(6, rargv, actarg);
1902 if (!found) return(SMS_NO_MATCH);
1903 return(SMS_SUCCESS);
1907 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1908 * the five flags associated with each list. It will return the name of
1909 * each list that meets the quailifications. It does this by building a
1910 * where clause based on the arguments, then doing a retrieve.
1913 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
1915 int qualified_get_lists(q, argv, cl, action, actarg)
1922 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
1923 "l", "name", lflags));
1927 /** get_members_of_list - optimized query for retrieval of list members
1930 ** argv[0] - list_id
1933 ** - retrieve USER members, then LIST members, then STRING members
1936 get_members_of_list(q, argv, cl, action, actarg)
1944 ## char member_name[129];
1947 list_id = *(int *)argv[0];
1949 targv[1] = member_name;
1951 ## range of m is members
1952 ## repeat retrieve (member_name = users.login)
1953 ## where m.#list_id = @list_id and m.member_type = "USER"
1954 ## and m.member_id = users.users_id
1955 ## sort by #member_name
1957 (*action)(2, targv, actarg);
1961 ## repeat retrieve (member_name = list.name)
1962 ## where m.#list_id = @list_id and m.member_type = "LIST"
1963 ## and m.member_id = list.#list_id
1964 ## sort by #member_name
1966 (*action)(2, targv, actarg);
1969 targv[0] = "STRING";
1970 ## repeat retrieve (member_name = strings.string)
1971 ## where m.#list_id = @list_id and m.member_type = "STRING"
1972 ## and m.member_id = strings.string_id
1973 ## sort by #member_name
1975 (*action)(2, targv, actarg);
1978 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1979 ## where tblstats.#table = "members"
1980 return(SMS_SUCCESS);
1984 /* count_members_of_list: this is a simple query, but it cannot be done
1985 * through the dispatch table.
1988 int count_members_of_list(q, argv, cl, action, actarg)
1995 ## int list, ct = 0;
1996 char *rargv[1], countbuf[5];
1998 list = *(int *)argv[0];
1999 rargv[0] = countbuf;
2000 ## repeat retrieve (ct = count(members.list_id where members.list_id = @list))
2001 sprintf(countbuf, "%d", ct);
2002 (*action)(1, rargv, actarg);
2003 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2004 ## where tblstats.#table = "members"
2005 return(SMS_SUCCESS);
2009 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2010 * the three flags associated with each service. It will return the name of
2011 * each service that meets the quailifications. It does this by building a
2012 * where clause based on the arguments, then doing a retrieve.
2015 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2017 int qualified_get_server(q, argv, cl, action, actarg)
2024 return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2025 "s", "name", sflags));
2029 /* generic qualified get routine, used by qualified_get_lists,
2030 * qualified_get_server, and qualified_get_serverhost.
2032 * start - a simple where clause, must not be empty
2033 * range - the name of the range variable
2034 * field - the field to return
2035 * flags - an array of strings, names of the flag variables
2038 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2048 ## char name[33], qual[256], *rvar, *rtbl, *rfield;
2049 char *rargv[1], buf[32];
2052 strcpy(qual, start);
2053 for (i = 0; i < q->argc; i++) {
2054 if (!strcmp(argv[i], "TRUE")) {
2055 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2056 (void) strcat(qual, buf);
2057 } else if (!strcmp(argv[i], "FALSE")) {
2058 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2059 (void) strcat(qual, buf);
2067 ## range of rvar is rtbl
2068 ## retrieve (name = rvar.rfield) where qual {
2069 (*action)(1, rargv, actarg);
2071 ## inquire_equel(rowcount = "rowcount")
2072 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2073 ## where tblstats.#table = @rtbl
2075 return(SMS_NO_MATCH);
2076 return(SMS_SUCCESS);
2080 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2081 * the five flags associated with each serverhost. It will return the name of
2082 * each service and host that meets the quailifications. It does this by
2083 * building a where clause based on the arguments, then doing a retrieve.
2086 static char *shflags[6] = { "service", "enable", "override", "success",
2087 "inprogress", "hosterror" };
2089 int qualified_get_serverhost(q, argv, cl, action, actarg)
2096 ## char sname[33], mname[33], qual[256];
2097 char *rargv[2], buf[32];
2100 sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2102 for (i = 1; i < q->argc; i++) {
2103 if (!strcmp(argv[i], "TRUE")) {
2104 sprintf(buf, " and sh.%s != 0", shflags[i]);
2106 } else if (!strcmp(argv[i], "FALSE")) {
2107 sprintf(buf, " and sh.%s = 0", shflags[i]);
2114 ## range of sh is serverhosts
2115 ## retrieve (sname = sh.service, mname = machine.name) where qual {
2116 (*action)(2, rargv, actarg);
2118 ## inquire_equel(rowcount = "rowcount")
2119 ## repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2120 ## where tblstats.#table = "serverhosts"
2122 return(SMS_NO_MATCH);
2123 return(SMS_SUCCESS);
2127 /* register_user - change user's login name and allocate a pobox, group,
2128 * filesystem, and quota for them. The user's status must start out as 0,
2129 * and is left as 2. Arguments are: user's UID, new login name, and user's
2130 * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY,
2131 * SMS_FS_STAFF, SMS_FS_MISC).
2134 register_user(q, argv, cl)
2139 ## char *login, dir[65], *entity, *directory, machname[33];
2140 ## int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2141 ## int size, alloc, pid, m_id;
2144 entity = cl->entity;
2147 uid = atoi(argv[0]);
2149 utype = atoi(argv[2]);
2151 ## range of u is users
2152 ## range of l is list
2153 ## range of sh is serverhosts
2154 ## range of n is nfsphys
2155 ## range of m is machine
2158 ## repeat retrieve (users_id = u.#users_id)
2159 ## where u.#uid = @uid and u.status = 0
2160 ## inquire_equel(rowcount = "rowcount");
2162 return(SMS_NO_MATCH);
2164 return(SMS_NOT_UNIQUE);
2166 /* check new login name */
2167 ## repeat retrieve (flag = any(u.#login where u.#login = @login))
2170 ## repeat retrieve (flag = any(l.#name where l.#name = @login))
2173 ## repeat retrieve (flag = any(filesys.#name where filesys.#name = @login))
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");
2184 return(SMS_NO_POBOX);
2186 /* change login name, set pobox */
2187 ## repeat replace u (#login = @login, status = 2, modtime = "now",
2188 ## modby = @who, modwith = @entity, potype="POP",
2189 ## pop_id = @mid, pmodtime="now", pmodby=@who,
2190 ## pmodwith=@entity)
2191 ## where u.#users_id = @users_id
2192 ## inquire_equel(rowcount = "rowcount");
2194 return(SMS_INTERNAL);
2195 set_pop_usage(mid, 1);
2196 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2199 /* create group list */
2200 if (set_next_object_id("gid", "list"))
2202 if (set_next_object_id("list_id", "list"))
2204 ## repeat retrieve (list_id = values.value) where values.name = "list_id"
2205 ## inquire_equel(rowcount = "rowcount");
2207 return(SMS_INTERNAL);
2208 ## repeat append list (name = @login, #list_id = @list_id, active = 1,
2209 ## public = 0, hidden = 0, maillist = 0, group = 1,
2210 ## #gid = values.value, desc = "User Group",
2211 ## acl_type = "USER", acl_id = @users_id, modtime = "now",
2212 ## modby = @who, modwith = @entity)
2213 ## where values.name = "gid"
2214 ## inquire_equel(rowcount = "rowcount");
2216 return(SMS_INTERNAL);
2217 ## repeat append members (#list_id = @list_id, member_type = "USER",
2218 ## member_id = @users_id)
2219 ## inquire_equel(rowcount = "rowcount");
2221 return(SMS_INTERNAL);
2222 com_err(whoami, 0, "group list created");
2224 /* decide where to put filesystem */
2227 ## repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2228 ## flag = n.status, size = n.#size, alloc = n.allocated) {
2229 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2230 maxsize = size - alloc;
2233 directory = strsave(dir);
2239 return(SMS_NO_FILESYS);
2241 /* create filesystem */
2242 if (set_next_object_id("filsys_id", "filesys"))
2244 ## repeat append filesys (filsys_id = values.value, phys_id = @pid,
2245 ## label = @login, type = "NFS", mach_id = @m_id,
2246 ## name = @directory + "/" + @login,
2247 ## mount = "/mit/" + @login,
2248 ## access = "w", comments = "User Locker",
2249 ## owner = @users_id, owners = @list_id, createflg = 1,
2250 ## lockertype = "HOMEDIR", modtime = "now",
2251 ## modby = @who, modwith = @entity)
2252 ## where values.name = "filsys_id"
2253 ## inquire_equel(rowcount = "rowcount");
2255 return(SMS_INTERNAL);
2256 com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2260 ## repeat retrieve (quota = values.value) where values.name = "def_quota"
2261 ## inquire_equel(rowcount = "rowcount");
2263 return(SMS_NO_QUOTA);
2264 ## repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2265 ## #quota = @quota, phys_id = @pid, modtime = "now",
2266 ## modby = @who, modwith = @entity)
2267 ## where values.name = "filsys_id"
2268 ## inquire_equel(rowcount = "rowcount");
2270 return(SMS_INTERNAL);
2271 ## repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2272 ## where nfsphys.nfsphys_id = filesys.#phys_id and
2273 ## filesys.filsys_id = values.value and values.name = "filsys_id"
2274 ## inquire_equel(rowcount = "rowcount");
2276 return(SMS_INTERNAL);
2277 com_err(whoami, 0, "quota of %d assigned", quota);
2279 ## repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2280 ## where tblstats.table = "users"
2281 ## repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2282 ## where tblstats.table = "list" or tblstats.table = "filesys" or
2283 ## tblstats.table = "nfsquota"
2284 return(SMS_SUCCESS);
2289 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2293 ** delta (will be +/- 1)
2296 ** - incr/decr value field in serverhosts table for pop/mach_id
2300 static int set_pop_usage(id, count)
2304 ## int mach_id = id;
2307 ## range of sh is serverhosts
2308 ## repeat replace sh (value1 = sh.value1 + @n)
2309 ## where sh.service = "POP" and sh.#mach_id = @mach_id
2311 return(SMS_SUCCESS);
2316 /* Validation Routines */
2318 validate_row(q, argv, v)
2319 register struct query *q;
2321 register struct validate *v;
2329 /* build where clause */
2330 build_qual(v->qual, v->argc, argv, qual);
2332 /* setup ingres variables */
2337 if (log_flags & LOG_VALID)
2338 /* tell the logfile what we're doing */
2339 com_err(whoami, 0, "validating row: %s", qual);
2341 /* look for the record */
2342 ## range of rvar is table
2343 ## retrieve (rowcount = count(rvar.name where qual))
2344 if (rowcount == 0) return(SMS_NO_MATCH);
2345 if (rowcount > 1) return(SMS_NOT_UNIQUE);
2349 validate_fields(q, argv, vo, n)
2351 register char *argv[];
2352 register struct valobj *vo;
2355 register int status;
2360 if (log_flags & LOG_VALID)
2361 com_err(whoami, 0, "validating %s in %s: %s",
2362 vo->namefield, vo->table, argv[vo->index]);
2363 status = validate_name(argv, vo);
2367 if (log_flags & LOG_VALID)
2368 com_err(whoami, 0, "validating %s in %s: %s",
2369 vo->idfield, vo->table, argv[vo->index]);
2370 status = validate_id(argv, vo);
2374 if (log_flags & LOG_VALID)
2375 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2376 status = validate_date(argv, vo);
2380 if (log_flags & LOG_VALID)
2381 com_err(whoami, 0, "validating %s type: %s",
2382 vo->table, argv[vo->index]);
2383 status = validate_type(argv, vo);
2387 if (log_flags & LOG_VALID)
2388 com_err(whoami, 0, "validating typed data (%s): %s",
2389 argv[vo->index - 1], argv[vo->index]);
2390 status = validate_typedata(q, argv, vo);
2394 if (log_flags & LOG_VALID)
2395 com_err(whoami, 0, "validating rename %s in %s",
2396 argv[vo->index], vo->table);
2397 status = validate_rename(argv, vo);
2401 if (log_flags & LOG_VALID)
2402 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2403 status = validate_chars(argv[vo->index]);
2407 status = SMS_EXISTS;
2412 if (status != SMS_EXISTS) return(status);
2416 return(SMS_SUCCESS);
2420 /* validate_chars: verify that there are no illegal characters in
2421 * the string. Legal characters are printing chars other than
2422 * ", *, ?, \, [ and ].
2424 static int illegalchars[] = {
2425 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2426 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2427 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2428 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2429 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2430 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2431 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2432 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2433 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2434 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2435 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2436 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2437 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2438 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
2447 if (illegalchars[*s++])
2448 return(SMS_BAD_CHAR);
2453 validate_id(argv, vo)
2455 register struct valobj *vo;
2465 name = argv[vo->index];
2467 /* minor kludge to upcasify machine names */
2468 if (!strcmp(table, "machine"))
2469 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2470 namefield = vo->namefield;
2471 idfield = vo->idfield;
2472 if (!strcmp(namefield, "uid")) {
2473 ## retrieve (id = table.idfield) where table.namefield = int4(name)
2474 ## inquire_equel (rowcount = "rowcount")
2476 ## retrieve (id = table.idfield) where table.namefield = name
2477 ## inquire_equel (rowcount = "rowcount")
2479 if (rowcount != 1) return(vo->error);
2480 *(int *)argv[vo->index] = id;
2484 validate_name(argv, vo)
2486 register struct valobj *vo;
2494 name = argv[vo->index];
2496 namefield = vo->namefield;
2497 if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2498 for (c = name; *c; c++)
2502 ## retrieve (rowcount = countu(table.namefield
2503 ## where table.namefield = name))
2504 return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2507 validate_date(argv, vo)
2515 idate = argv[vo->index];
2517 ## retrieve (dd = interval("years", date(idate) - date("today")))
2518 ## inquire_equel (errorno = "errorno")
2519 if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2524 validate_rename(argv, vo)
2528 ## char *name, *table, *namefield, *idfield;
2532 c = name = argv[vo->index];
2534 if (illegalchars[*c++])
2535 return(SMS_BAD_CHAR);
2537 /* minor kludge to upcasify machine names */
2538 if (!strcmp(table, "machine"))
2539 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2540 namefield = vo->namefield;
2541 idfield = vo->idfield;
2544 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2546 ## retrieve (id = any(table.namefield where table.namefield = name))
2552 ## retrieve (id = table.idfield) where table.namefield = name
2553 if (id == -1 || id == *(int *)argv[vo->index - 1])
2560 validate_type(argv, vo)
2562 register struct valobj *vo;
2569 typename = vo->table;
2570 c = value = argv[vo->index];
2572 if (illegalchars[*c++])
2573 return(SMS_BAD_CHAR);
2575 /* uppercase type fields */
2576 for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2578 ## range of a is alias
2579 ## repeat retrieve (exists = any(a.trans where a.name = @typename and
2580 ## a.type = "TYPE" and
2581 ## a.trans = @value))
2582 return (exists ? SMS_EXISTS : vo->error);
2585 /* validate member or type-specific data field */
2587 validate_typedata(q, argv, vo)
2588 register struct query *q;
2589 register char *argv[];
2590 register struct valobj *vo;
2593 ## char *field_type;
2594 ## char data_type[129];
2600 /* get named object */
2601 name = argv[vo->index];
2603 /* get field type string (known to be at index-1) */
2604 field_type = argv[vo->index-1];
2606 /* get corresponding data type associated with field type name */
2607 ## repeat retrieve (data_type = alias.trans)
2608 ## where alias.#name = @field_type and alias.type = "TYPEDATA"
2609 ## inquire_equel (rowcount = "rowcount")
2610 if (rowcount != 1) return(SMS_TYPE);
2612 /* now retrieve the record id corresponding to the named object */
2613 if (index(data_type, ' '))
2614 *index(data_type, ' ') = 0;
2615 if (!strcmp(data_type, "user")) {
2617 ## repeat retrieve (id = users.users_id) where users.login = @name
2618 ## inquire_equel (rowcount = "rowcount")
2619 if (rowcount != 1) return(SMS_USER);
2621 } else if (!strcmp(data_type, "list")) {
2623 ## repeat retrieve (id = list.list_id) where list.#name = @name
2624 ## inquire_equel (rowcount = "rowcount")
2625 if (rowcount != 1) {
2626 /* if idfield is non-zero, then if argv[0] matches the string
2627 * that we're trying to resolve, we should get the value of
2628 * values.[idfield] for the id.
2630 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2631 set_next_object_id(q->validate->object_id, q->rtable);
2633 ## repeat retrieve (id = values.value) where values.#name = @name
2634 ## inquire_equel(rowcount = "rowcount")
2635 if (rowcount != 1) return(SMS_LIST);
2639 } else if (!strcmp(data_type, "machine")) {
2641 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2642 ## repeat retrieve (id = machine.mach_id) where machine.#name = @name
2643 ## inquire_equel (rowcount = "rowcount")
2644 if (rowcount != 1) return(SMS_MACHINE);
2646 } else if (!strcmp(data_type, "string")) {
2648 ## range of s is strings
2649 ## repeat retrieve (id = s.string_id) where s.string = @name
2650 ## inquire_equel (rowcount = "rowcount")
2651 if (rowcount == 0) {
2652 if (q->type != APPEND) return(SMS_STRING);
2653 ## range of v is values
2654 ## retrieve (id = v.value) where v.#name = "strings_id"
2656 ## replace v (value = id) where v.#name = "strings_id"
2657 ## append to strings (string_id = id, string = name)
2659 } else if (!strcmp(data_type, "none")) {
2665 /* now set value in argv */
2666 *(int *)argv[vo->index] = id;
2668 return (SMS_EXISTS);
2672 /* This looks up a login name and returns the SMS internal ID. It is used
2673 * by authenticate to put the users_id in the client structure.
2676 int get_users_id(name)
2679 ## int id, rowcount;
2684 ## range of u is users
2685 ## repeat retrieve (id = u.#users_id) where u.#login = @login
2686 ## inquire_equel (rowcount = "rowcount")
2695 /* Check the database at startup time. For now this just resets the
2696 * inprogress flags that the DCM uses.
2699 sanity_check_database()