]> andersk Git - moira.git/blob - server/qsupport.qc
Uppercase service names; Missed some reasons not to delete a user;
[moira.git] / server / qsupport.qc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *
8  */
9
10 #ifndef lint
11 static char *rcsid_qsupport_qc = "$Header$";
12 #endif lint
13
14 #include "query.h"
15 #include "sms_server.h"
16 #include <ctype.h>
17
18
19 extern char *whoami, *strsave();
20
21
22 /* Specialized Access Routines */
23
24 /* access_user - verify that client name equals specified login name
25  *
26  *  - since field validation routines are called first, a users_id is
27  *    now in argv[0] instead of the login name.
28  */
29
30 access_user(q, argv, cl)
31     struct query *q;
32     char *argv[];
33     client *cl;
34 {
35     if (cl->users_id != *(int *)argv[0])
36         return(SMS_PERM);
37     else
38         return(SMS_SUCCESS);
39 }
40
41     
42
43 /* access_login - verify that client name equals specified login name
44  *
45  *   argv[0...n] contain search info.  q->
46  */
47
48 access_login(q, argv, cl)
49     struct query *q;
50     char *argv[];
51     client *cl;
52 ##{
53 ##  int rowcount, id;
54 ##  char qual[256];
55
56     build_qual(q->qual, q->argc, argv, qual);
57 ##  retrieve (id = u.users_id) where qual
58 ##  inquire_equel(rowcount = "rowcount")
59     if (rowcount != 1 || id != cl->users_id)
60         return(SMS_PERM);
61     else
62         return(SMS_SUCCESS);
63 ##}
64
65     
66
67 /* access_list - check access for most list operations
68  *
69  * Inputs: argv[0] - list_id
70  *          q - query name
71  *          argv[2] - member ID (only for queries "amtl" and  "dmfl")
72  *         cl - client name
73  *
74  * - check that client is a member of the access control list
75  * - OR, if the query is add_member_to_list or delete_member_from_list
76  *      and the list is public, allow access if client = member
77  */ 
78
79 access_list(q, argv, cl)
80     struct query *q;
81     char *argv[];
82     client *cl;
83 ##{
84 ##  int list_id, acl_id, flags, rowcount;
85 ##  char acl_type[9];
86     char *client_type;
87     int client_id, status;
88
89     list_id = *(int *)argv[0];
90 ##  repeat retrieve (acl_id = list.#acl_id, acl_type = list.#acl_type,
91 ##                   flags = list.#public) 
92 ##         where list.#list_id = @list_id
93 ##  inquire_equel(rowcount = "rowcount")
94     if (rowcount != 1)
95       return(SMS_INTERNAL);
96
97     /* parse client structure */
98     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
99         return(status);
100
101     /* if amtl or dmfl and list is public allow client to add or delete self */
102     if ((!strcmp("amtl", q->shortname) || !strcmp("dmfl", q->shortname)) &&
103         (flags && !strcmp("USER", argv[1]))) {
104         if (*(int *)argv[2] == client_id) return(SMS_SUCCESS);
105     }
106
107     /* check for client in access control list */
108     status = find_member(acl_type, acl_id, client_type, client_id, 0);
109     if (!status) return(SMS_PERM);
110
111     return(SMS_SUCCESS);
112 ##}
113
114
115 /* access_visible_list - allow access to list only if it is not hidden,
116  *      or if the client is on the ACL
117  *
118  * Inputs: argv[0] - list_id
119  *         cl - client identifier
120  */ 
121
122 access_visible_list(q, argv, cl)
123     struct query *q;
124     char *argv[];
125     client *cl;
126 ##{
127 ##  int list_id, acl_id, flags, rowcount;
128 ##  char acl_type[9];
129     char *client_type;
130     int client_id, status;
131
132     list_id = *(int *)argv[0];
133 ##  repeat retrieve (flags = list.hidden, acl_id = list.#acl_id, 
134 ##      acl_type = list.#acl_type) where list.#list_id = @list_id
135 ##  inquire_equel(rowcount = "rowcount")
136     if (rowcount != 1)
137       return(SMS_INTERNAL);
138     if (!flags)
139         return(SMS_SUCCESS);
140
141     /* parse client structure */
142     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
143         return(status);
144
145     /* check for client in access control list */
146     status = find_member(acl_type, acl_id, client_type, client_id, 0);
147     if (!status)
148         return(SMS_PERM);
149
150     return(SMS_SUCCESS);
151 ##}
152
153
154 /* access_vis_list_by_name - allow access to list only if it is not hidden,
155  *      or if the client is on the ACL
156  *
157  * Inputs: argv[0] - list name
158  *         cl - client identifier
159  */ 
160
161 access_vis_list_by_name(q, argv, cl)
162     struct query *q;
163     char *argv[];
164     client *cl;
165 ##{
166 ##  int acl_id, flags, rowcount;
167 ##  char acl_type[9], *listname;
168     char *client_type;
169     int client_id, status;
170
171     listname = argv[0];
172 ##  repeat retrieve (flags = list.hidden, acl_id = list.#acl_id, 
173 ##      acl_type = list.#acl_type) where list.#name = @listname
174 ##  inquire_equel(rowcount = "rowcount");
175     if (rowcount > 1)
176       return(SMS_WILDCARD);
177     if (rowcount == 0)
178       return(SMS_NO_MATCH);
179     if (!flags)
180         return(SMS_SUCCESS);
181
182     /* parse client structure */
183     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
184         return(status);
185
186     /* check for client in access control list */
187     status = find_member(acl_type, acl_id, client_type, client_id, 0);
188     if (!status)
189         return(SMS_PERM);
190
191     return(SMS_SUCCESS);
192 ##}
193
194
195 /* access_member - allow user to access member of type "USER" and name matches
196  * username, or to access member of type "LIST" and list is one that user is
197  * on the acl of, or the list is visible.
198  */
199
200 access_member(q, argv, cl)
201     struct query *q;
202     char *argv[];
203     client *cl;
204 {
205     if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
206       return(access_visible_list(q, &argv[1], cl));
207
208     if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
209         if (!strcmp(cl->kname.name, argv[1]))
210           return(SMS_SUCCESS);
211     }
212
213     return(SMS_PERM);
214 }
215
216
217 /* access_qgli - special access routine for Qualified_get_lists.  Allows
218  * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
219  */
220
221 access_qgli(q, argv, cl)
222     struct query *q;
223     char *argv[];
224     client *cl;
225 {
226     if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
227       return(SMS_SUCCESS);
228     return(SMS_PERM);
229 }
230
231
232 /* access_service - allow access if user is on ACL of service.  Don't
233  * allow access if a wildcard is used.
234  */
235
236 access_service(q, argv, cl)
237     struct query *q;
238     char *argv[];
239     client *cl;
240 ##{
241 ##  int acl_id, rowcount;
242 ##  char *name, acl_type[9];
243     int client_id, status;
244     char *client_type;
245
246     name = argv[0];
247 ##  repeat retrieve (acl_id = servers.#acl_id, acl_type = servers.#acl_type)
248 ##      where servers.#name = uppercase(@name)
249 ##  inquire_equel(rowcount = "rowcount")
250     if (rowcount > 1)
251       return(SMS_PERM);
252
253     /* parse client structure */
254     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
255         return(status);
256
257     /* check for client in access control list */
258     status = find_member(acl_type, acl_id, client_type, client_id, 0);
259     if (!status) return(SMS_PERM);
260
261     return(SMS_SUCCESS);
262 ##}
263
264
265
266 /* access_filesys - verify that client is owner or on owners list of filesystem
267  *      named by argv[0]
268  */
269
270 access_filesys(q, argv, cl)
271     struct query *q;
272     char *argv[];
273     client *cl;
274 ##{
275 ##  int rowcount, users_id, list_id;
276 ##  char *name;
277     int status, client_id;
278     char *client_type;
279
280     name = argv[0];
281 ##  repeat retrieve (users_id = filesys.owner, list_id = filesys.owners)
282 ##      where filesys.label = @name
283 ##  inquire_equel(rowcount = "rowcount")
284
285     if (rowcount != 1)
286       return(SMS_PERM);
287     if (users_id == cl->users_id)
288       return(SMS_SUCCESS);
289     if ((status = get_client(cl, &client_type, &client_id)) != SMS_SUCCESS)
290         return(status);
291     status = find_member("LIST", list_id, client_type, client_id, 0);
292     if (status)
293       return(SMS_SUCCESS);
294     return(SMS_PERM);
295 ##}
296
297     
298 \f
299 /* Setup Routines */
300
301 /* Setup routine for add_user
302  *
303  * Inputs: argv[0] - login
304  *         argv[1] - uid
305  *
306  * Description:
307  *
308  * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
309  * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
310  */
311
312 setup_ausr(q, argv, cl)
313     struct query *q;
314     register char *argv[];
315     client *cl;
316 ##{
317 ##  int nuid, rowcount;
318
319     if (!strcmp(argv[1], UNIQUE_UID) || atoi(argv[1]) == -1) {
320         if (set_next_object_id("uid", "users"))
321           return(SMS_INGRES_ERR);
322 ##      repeat retrieve (nuid = values.value) where values.name = "uid"
323 ##      inquire_equel(rowcount = "rowcount")
324         if (rowcount != 1)
325           return(SMS_INTERNAL);
326         sprintf(argv[1], "%d", nuid);
327     }
328
329     if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[1]) == -1) {
330         sprintf(argv[0], "#%s", argv[1]);
331     }
332
333     return(SMS_SUCCESS);
334 ##}
335
336
337 /* setup_dusr - verify that the user is no longer being referenced 
338  * and may safely be deleted.
339  */
340
341 int setup_dusr(q, argv)
342     struct query *q;
343     char **argv;
344 ##{
345 ##  int flag, id;
346
347     id = *(int *)argv[0];
348 ##  repeat delete nfsquota where nfsquota.users_id = @id
349 ##  repeat retrieve (flag = any(members.member_id where members.member_id=@id
350 ##                       and members.member_type = "USER"))
351     if (flag)
352         return(SMS_IN_USE);
353 ##  repeat retrieve (flag = any(filesys.label where filesys.owner=@id))
354     if (flag)
355         return(SMS_IN_USE);
356 ##  repeat retrieve (flag = any(list.name where list.acl_id=@id and
357 ##                      list.acl_type = "USER"))
358     if (flag)
359         return(SMS_IN_USE);
360 ##  repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
361 ##                      servers.acl_type = "USER"))
362     if (flag)
363         return(SMS_IN_USE);
364 ##  repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
365 ##                      hostaccess.acl_type = "USER"))
366     if (flag)
367         return(SMS_IN_USE);
368     else
369         return(SMS_SUCCESS);
370 ##}
371
372
373 /* setup_spop: verify that there is already a valid POP machine_id in the
374  * pop_id field.  Also take care of keeping track of the post office usage.
375  */
376 int setup_spop(q, argv)
377 struct query *q;
378 char **argv;
379 ##{
380 ##  int id, flag;
381 ##  char type[9];
382
383     id = *(int *)argv[0];
384 ##  repeat retrieve (type = u.potype, flag = any(machine.name
385 ##                                      where machine.mach_id = u.pop_id 
386 ##                                              and u.pop_id != 0
387 ##                                              and u.users_id = @id))
388     if (!flag)
389       return(SMS_MACHINE);
390     if (strcmp(type, "POP"))
391       set_pop_usage(id, 1);
392     return(SMS_SUCCESS);
393 ##}
394
395
396 /* setup_dpob:  Take care of keeping track of the post office usage.
397  */
398 int setup_dpob(q, argv)
399 struct query *q;
400 char **argv;
401 ##{
402 ##  int id, user;
403 ##  char type[9];
404
405     user = *(int *)argv[0];
406 ##  repeat retrieve (type = u.potype, id = u.pop_id)
407 ##              where u.users_id = @user
408
409     if (strcmp(type, "POP"))
410       set_pop_usage(id, -1);
411     return(SMS_SUCCESS);
412 ##}
413
414
415 /* setup_dmac - verify that the machine is no longer being referenced 
416  * and may safely be deleted.
417  */
418
419 int setup_dmac(q, argv)
420     struct query *q;
421     char **argv;
422 ##{
423 ##  int flag, id;
424
425     id = *(int *)argv[0];
426 ##  repeat retrieve (flag = any(users.login where users.potype = "POP" 
427 ##                                                and users.pop_id=@id))
428     if (flag)
429         return(SMS_IN_USE);
430 ##  repeat retrieve (flag = any(serverhosts.mach_id
431 ##                               where serverhosts.mach_id=@id))
432     if (flag)
433         return(SMS_IN_USE);
434 ##  repeat retrieve (flag = any(nfsphys.mach_id where nfsphys.mach_id=@id))
435     if (flag)
436         return(SMS_IN_USE);
437 ##  repeat retrieve (flag = any(hostaccess.mach_id where hostaccess.mach_id=@id))
438     if (flag)
439         return(SMS_IN_USE);
440
441 ##  repeat delete mcmap where mcmap.mach_id = @id
442     return(SMS_SUCCESS);
443 ##}
444
445
446 /* setup_dclu - verify that the cluster is no longer being referenced 
447  * and may safely be deleted.
448  */
449
450 int setup_dclu(q, argv)
451     struct query *q;
452     char **argv;
453 ##{
454 ##  int flag, id;
455
456     id = *(int *)argv[0];
457 ##  repeat retrieve (flag = any(mcmap.mach_id where mcmap.clu_id=@id))
458     if (flag)
459         return(SMS_IN_USE);
460 ##  repeat retrieve (flag = any(svc.clu_id where svc.clu_id=@id))
461     if (flag)
462         return(SMS_IN_USE);
463     else
464         return(SMS_SUCCESS);
465 ##}
466
467
468 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
469  * a new gid and put it in argv[6].  Otherwise if argv[6] is UNIQUE_ID but
470  * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
471  * a -1 there.  Remember that this is also used for ulis, with the indexes
472  * at 6 & 7.
473  */
474
475 int setup_alis(q, argv)
476 struct query *q;
477 char **argv;
478 ##{
479 ##  int ngid;
480     char *malloc();
481     int idx;
482
483     if (!strcmp(q->shortname, "alis"))
484       idx = 6;
485     else if (!strcmp(q->shortname, "ulis"))
486       idx = 7;
487
488     if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
489         if (atoi(argv[idx - 1])) {
490             if (set_next_object_id("gid", "list"))
491               return(SMS_INGRES_ERR);
492 ##          repeat retrieve (ngid = values.value) where values.name = "gid"
493             sprintf(argv[idx], "%d", ngid);
494         } else {
495             strcpy(argv[idx], "-1");
496         }
497     }
498
499     return(SMS_SUCCESS);
500 ##}
501
502
503 /* setup_dlist - verify that the list is no longer being referenced 
504  * and may safely be deleted.
505  */
506
507 int setup_dlis(q, argv)
508     struct query *q;
509     char **argv;
510 ##{
511 ##  int flag, id;
512
513     id = *(int *)argv[0];
514 ##  repeat retrieve (flag = any(members.member_id where members.member_id=@id
515 ##                       and members.member_type = "LIST"))
516     if (flag)
517         return(SMS_IN_USE);
518 ##  repeat retrieve (flag = any(members.member_id where members.list_id=@id))
519     if (flag)
520         return(SMS_IN_USE);
521 ##  repeat retrieve (flag = any(filesys.label where filesys.owners=@id))
522     if (flag)
523         return(SMS_IN_USE);
524 ##  repeat retrieve (flag = any(capacls.tag where capacls.list_id=@id))
525     if (flag)
526         return(SMS_IN_USE);
527 ##  repeat retrieve (flag = any(list.name where list.acl_id=@id and
528 ##                      list.acl_type = "LIST"))
529     if (flag)
530         return(SMS_IN_USE);
531 ##  repeat retrieve (flag = any(servers.name where servers.acl_id=@id and
532 ##                      servers.acl_type = "LIST"))
533     if (flag)
534         return(SMS_IN_USE);
535 ##  repeat retrieve (flag=any(hostaccess.acl_id where hostaccess.acl_id=@id and
536 ##                      hostaccess.acl_type = "LIST"))
537     if (flag)
538         return(SMS_IN_USE);
539 ##  repeat retrieve (flag = any(zephyr.class
540 ##              where zephyr.xmt_type = "LIST" and zephyr.xmt_id = @id or
541 ##                    zephyr.sub_type = "LIST" and zephyr.sub_id = @id or
542 ##                    zephyr.iws_type = "LIST" and zephyr.iws_id = @id or
543 ##                    zephyr.iui_type = "LIST" and zephyr.iui_id = @id))
544     if (flag)
545         return(SMS_IN_USE);
546     else
547         return(SMS_SUCCESS);
548 ##}
549
550
551 /* setup_dsin - verify that the service is no longer being referenced 
552  * and may safely be deleted.
553  */
554
555 int setup_dsin(q, argv)
556     struct query *q;
557     char **argv;
558 ##{
559 ##  int flag;
560 ##  char *name;
561
562     name = argv[0];
563 ##  repeat retrieve (flag = any(serverhosts.service 
564 ##                              where serverhosts.service=uppercase(@name)))
565     if (flag)
566         return(SMS_IN_USE);
567 ##  repeat retrieve (flag = servers.inprogress) where servers.#name = @name
568     if (flag)
569         return(SMS_IN_USE);
570     else
571         return(SMS_SUCCESS);
572 ##}
573
574
575 /* setup_dshi - verify that the service-host is no longer being referenced 
576  * and may safely be deleted.
577  */
578
579 int setup_dshi(q, argv)
580     struct query *q;
581     char **argv;
582 ##{
583 ##  int flag, id;
584 ##  char *name;
585
586     name = argv[0];
587     id = *(int *)argv[1];
588 ##  repeat retrieve (flag=serverhosts.inprogress) 
589 ##      where serverhosts.service=uppercase(@name) and serverhosts.mach_id=@id
590     if (flag)
591         return(SMS_IN_USE);
592     else
593         return(SMS_SUCCESS);
594 ##}
595
596
597 /**
598  ** setup_add_filesys - verify existance of referenced file systems
599  **
600  ** Inputs:     Add
601  **   argv[1] - type
602  **   argv[2] - mach_id
603  **   argv[3] - name
604  **   argv[5] - access
605  **
606  ** Description:
607  **   - for type = RVD:
608  **        * allow anything
609  **   - for type = NFS:
610  **        * extract directory prefix from name
611  **        * verify mach_id/dir in nfsphys
612  **        * verify access in {r, w, R, W}
613  **
614  **  Side effect: sets variable var_phys_id to the ID of the physical
615  **     filesystem (nfsphys_id for NFS, 0 for RVD)
616  **
617  ** Errors:
618  **   SMS_NFS - specified directory not exported
619  **   SMS_FILESYS_ACCESS - invalid filesys access
620  **
621  **/
622
623 ##static int var_phys_id;
624
625 setup_afil(q, argv)
626     struct query *q;
627     char *argv[];
628 {
629     char *type;
630     int mach_id;
631     char *name;
632     char *access;  
633
634     type = argv[1];
635     mach_id = *(int *)argv[2];
636     name = argv[3];
637     access = argv[5];
638     var_phys_id = 0;
639
640     if (!strcmp(type, "NFS"))
641         return (check_nfs(mach_id, name, access));
642     else
643         return(SMS_SUCCESS);
644 }
645
646
647 setup_ufil(q, argv)
648     struct query *q;
649     char *argv[];
650 {
651     char *type;
652     int mach_id;
653     char *name;
654     char *access;  
655
656     type = argv[2];
657     mach_id = *(int *)argv[3];
658     name = argv[4];
659     access = argv[6];
660     var_phys_id = 0;
661
662     if (!strcmp(type, "NFS"))
663         return (check_nfs(mach_id, name, access));
664     else
665         return(SMS_SUCCESS);
666 }
667
668
669 /* Find the NFS physical partition that the named directory is on.
670  * This is done by comparing the dir against the mount point of the
671  * partition.  To make sure we get the correct match when there is 
672  * more than one, we sort the query in reverse order by dir name.
673  */
674
675 ##check_nfs(mach_id, name, access)
676 ##  int mach_id;
677     char *name;
678     char *access;
679 ##{
680 ##  char dir[32];
681     char caccess;
682     register int status;
683     register char *cp1;
684     register char *cp2;
685
686     caccess = (isupper(*access)) ? tolower(*access) : *access;
687     if (caccess != 'r' && caccess != 'w') return(SMS_FILESYS_ACCESS);
688
689     status = SMS_NFS;
690 ##  range of np is nfsphys
691 ##  repeat retrieve (var_phys_id = np.#nfsphys_id, dir = trim(np.#dir))
692 ##      where np.#mach_id = @mach_id sort by #dir:d {
693          cp1 = name;
694          cp2 = dir;
695          while (*cp2) {
696              if (*cp1++ != *cp2) break;
697              cp2++;
698          }
699          if (*cp2 == 0) {
700              status = SMS_SUCCESS;
701 ##           endretrieve
702          }
703 ##  }
704
705     return(status);
706 ##}
707
708
709 /* setup_dfil: free any quota records associated with a filesystem
710  * when it is deleted.
711  */
712
713 setup_dfil(q, argv, cl)
714     struct query  *q;
715     char **argv;
716     client *cl;
717 ##{
718 ##  int id;
719
720     id = *(int *)argv[0];
721 ##  range of q is nfsquota
722 ##  range of fs is filesys
723 ##  range of n is nfsphys
724 ##  repeat replace n (allocated=n.allocated-sum(q.quota where q.filsys_id=@id))
725 ##      where n.nfsphys_id = fs.phys_id and fs.filsys_id = @id
726
727 ##  repeat delete q where q.filsys_id = @id
728     return(SMS_SUCCESS);
729 ##}
730
731
732 /* setup_dnfp: check to see that the nfs physical partition does not have
733  * any filesystems assigned to it before allowing it to be deleted.
734  */
735
736 setup_dnfp(q, argv, cl)
737     struct query  *q;
738     char **argv;
739     client *cl;
740 ##{
741 ##  int id, exists;
742
743     id = *(int *)argv[0];
744 ##  repeat retrieve (exists = any(filesys.label where filesys.phys_id = @id))
745     if (exists)
746       return(SMS_IN_USE);
747     return(SMS_SUCCESS);
748 ##}
749
750
751 /* setup_dnfq: Remove allocation from nfsphys before deleting quota.
752  *   argv[0] = filsys_id
753  *   argv[1] = users_id
754  */
755
756 setup_dnfq(q, argv, cl)
757     struct query  *q;
758     char **argv;
759     client *cl;
760 ##{
761 ##  int quota, fs, user;
762
763     fs = *(int *)argv[0];
764     user = *(int *)argv[1];
765
766 ##  range of q is nfsquota
767 ##  repeat retrieve (quota = q.#quota) where q.users_id = @user and
768 ##      q.filsys_id = @fs
769 ##  repeat replace nfsphys (allocated = nfsphys.allocated - @quota)
770 ##      where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
771     return(SMS_SUCCESS);
772 ##}
773
774
775 \f
776 /* FOLLOWUP ROUTINES */
777
778 /* generic set_modtime routine.  This takes the table name from the query,
779  * and will update the modtime, modby, and modwho fields in the entry in
780  * the table whose name field matches argv[0].
781  */
782
783 set_modtime(q, argv, cl)
784     struct query *q;
785     char *argv[];
786     client *cl;
787 ##{
788 ##  char *name, *entity, *table;
789 ##  int who;
790
791     entity = cl->entity;
792     who = cl->users_id;
793     table = q->rtable;
794     name = argv[0];
795
796 ##  replace table (modtime = "now", modby = who, modwith = entity)
797 ##       where table.#name = name
798     return(SMS_SUCCESS);
799 ##}
800
801 /* generic set_modtime_by_id routine.  This takes the table name from
802  * the query, and the id name from the validate record,
803  * and will update the modtime, modby, and modwho fields in the entry in
804  * the table whose id matches argv[0].
805  */
806
807 set_modtime_by_id(q, argv, cl)
808     struct query *q;
809     char **argv;
810     client *cl;
811 ##{
812 ##  char *entity, *table, *id_name;
813 ##  int who, id;
814
815     entity = cl->entity;
816     who = cl->users_id;
817     table = q->rtable;
818     id_name = q->validate->object_id;
819
820     id = *(int *)argv[0];
821 ##  replace table (modtime = "now", modby = who, modwith = entity)
822 ##       where table.id_name = id
823     return(SMS_SUCCESS);
824 ##}
825
826
827 /* Sets the finger modtime on a user record.  The users_id will be in argv[0].
828  */
829
830 set_finger_modtime(q, argv, cl)
831     struct query *q;
832     char *argv[];
833     client *cl;
834 ##{
835 ##  int users_id, who;
836 ##  char *entity;
837
838     entity = cl->entity;
839     who = cl->users_id;
840     users_id = *(int *)argv[0];
841
842 ##  repeat replace u (fmodtime = "now", fmodby = @who, fmodwith = @entity)
843 ##       where u.#users_id = @users_id
844     return(SMS_SUCCESS);
845 ##}
846
847
848 /* Sets the pobox modtime on a user record.  The users_id will be in argv[0].
849  */
850
851 set_pobox_modtime(q, argv, cl)
852     struct query *q;
853     char **argv;
854     client *cl;
855 ##{
856 ##  int users_id, who;
857 ##  char *entity;
858
859     entity = cl->entity;
860     who = cl->users_id;
861     users_id = *(int *)argv[0];
862
863 ##  repeat replace users (pmodtime = "now", pmodby = @who, pmodwith = @entity)
864 ##       where users.#users_id = @users_id
865     return(SMS_SUCCESS);
866 ##}
867
868
869 /* Sets the modtime on a machine record.  The machine name is in argv[0].
870  * This routine is different from the generic set_modtime in that the
871  * name is uppercased first.
872  */
873
874 set_mach_modtime(q, argv, cl)
875     struct query *q;
876     char **argv;
877     client *cl;
878 ##{
879 ##  char *host, *entity;
880 ##  int who;
881
882     entity = cl->entity;
883     who = cl->users_id;
884
885     host = argv[0];
886 ##  repeat replace m (modtime = "now", modby = @who, modwith = @entity)
887 ##       where m.name = uppercase(@host)
888     return(SMS_SUCCESS);
889 ##}
890
891
892 /* Sets the modtime on the machine whose mach_id is in argv[0].  This routine
893  * is necessary for add_machine_to_cluster becuase the table that query
894  * operates on is "mcm", not "machine".
895  */
896
897 set_mach_modtime_by_id(q, argv, cl)
898     struct query *q;
899     char **argv;
900     client *cl;
901 ##{
902 ##  char *entity;
903 ##  int who, id;
904
905     entity = cl->entity;
906     who = cl->users_id;
907
908     id = *(int *)argv[0];
909 ##  range of m is machine
910 ##  repeat replace m (modtime = "now", modby = @who, modwith = @entity)
911 ##       where m.mach_id = @id
912     return(SMS_SUCCESS);
913 ##}
914
915
916 /* Sets the modtime on the cluster whose mach_id is in argv[0].  This routine
917  * is necessary for add_cluster_data and delete_cluster_data becuase the
918  * table that query operates on is "svc", not "cluster".
919  */
920
921 set_cluster_modtime_by_id(q, argv, cl)
922     struct query *q;
923     char **argv;
924     client *cl;
925 ##{
926 ##  char *entity;
927 ##  int who, id;
928
929     entity = cl->entity;
930     who = cl->users_id;
931
932     id = *(int *)argv[0];
933 ##  range of c is cluster
934 ##  repeat replace c (modtime = "now", modby = @who, modwith = @entity)
935 ##       where c.clu_id = @id
936     return(SMS_SUCCESS);
937 ##}
938
939
940 /* sets the modtime on the serverhost where the service name is in argv[0]
941  * and the mach_id is in argv[1].
942  */
943
944 set_serverhost_modtime(q, argv, cl)
945     struct query *q;
946     char **argv;
947     client *cl;
948 ##{
949 ##  char *entity, *serv;
950 ##  int who, id;
951
952     entity = cl->entity;
953     who = cl->users_id;
954
955     serv = argv[0];
956     id = *(int *)argv[1];
957 ##  repeat replace sh (modtime = "now", modby = @who, modwith = @entity)
958 ##       where sh.service = uppercase(@serv) and sh.mach_id = @id
959     return(SMS_SUCCESS);
960 ##}
961
962
963 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
964  * directory name is in argv[1].
965  */
966
967 set_nfsphys_modtime(q, argv, cl)
968     struct query *q;
969     char **argv;
970     client *cl;
971 ##{
972 ##  char *entity, *dir;
973 ##  int who, id;
974
975     entity = cl->entity;
976     who = cl->users_id;
977
978     id = *(int *)argv[0];
979     dir = argv[1];
980 ##  repeat replace np (modtime = "now", modby = @who, modwith = @entity)
981 ##       where np.#dir = @dir and np.mach_id = @id
982     return(SMS_SUCCESS);
983 ##}
984
985
986 /* sets the modtime on a filesystem, where argv[0] contains the filesys
987  * label.
988  */
989
990 set_filesys_modtime(q, argv, cl)
991     struct query *q;
992     char *argv[];
993     client *cl;
994 ##{
995 ##  char *label, *entity;
996 ##  int who;
997
998     entity = cl->entity;
999     who = cl->users_id;
1000
1001     label = argv[0];
1002     if (!strcmp(q->shortname, "ufil"))
1003       label = argv[1];
1004
1005 ##  repeat replace fs (modtime = "now", modby = @who, modwith = @entity,
1006 ##                     #phys_id = @var_phys_id)  where fs.#label = @label
1007     return(SMS_SUCCESS);
1008 ##}
1009
1010
1011 /* sets the modtime on a zephyr class, where argv[0] contains the class
1012  * name.
1013  */
1014
1015 set_zephyr_modtime(q, argv, cl)
1016     struct query *q;
1017     char *argv[];
1018     client *cl;
1019 ##{
1020 ##  char *class, *entity;
1021 ##  int who;
1022
1023     entity = cl->entity;
1024     who = cl->users_id;
1025
1026     class = argv[0];
1027
1028 ##  repeat replace z (modtime = "now", modby = @who, modwith = @entity)
1029 ##                     where z.#class = @class
1030     return(SMS_SUCCESS);
1031 ##}
1032
1033
1034 /* fixes the modby field.  This will be the second to last thing in the
1035  * argv, the argv length is determined from the query structure.  It is
1036  * passed as a pointer to an integer.  This will either turn it into a
1037  * username, or # + the users_id.
1038  */
1039 followup_fix_modby(q, sq, v, action, actarg, cl)
1040     struct query *q;
1041     register struct save_queue *sq;
1042     struct validate *v;
1043     register int (*action)();
1044     register int actarg;
1045     client *cl;
1046 ##{
1047     register int i, j;
1048     char **argv, *malloc();
1049 ##  int id, rowcount;
1050 ##  char *name;
1051
1052     i = q->vcnt - 2;
1053     while (sq_get_data(sq, &argv)) {
1054         id = atoi(argv[i]);
1055         free(argv[i]);
1056         argv[i] = malloc(9);
1057         name = argv[i];
1058 ##      repeat retrieve (name = users.login) where users.users_id = @id
1059 ##      inquire_equel(rowcount = "rowcount")
1060         if (rowcount != 1) {
1061             sprintf(argv[i], "#%d", id);
1062         }
1063         (*action)(q->vcnt, argv, actarg);
1064         for (j = 0; j < q->vcnt; j++)
1065           free(argv[j]);
1066         free(argv);
1067     }
1068     sq_destroy(sq);
1069     return(SMS_SUCCESS);
1070 ##}
1071
1072
1073 /**
1074  ** followup_ausr - add finger and pobox entries, set_user_modtime
1075  **
1076  ** Inputs:
1077  **     argv[0] - login (add_user)
1078  **     argv[3] - last name
1079  **     argv[4] - first name
1080  **     argv[5] - middle name
1081  **
1082  **/
1083
1084 followup_ausr(q, argv, cl)
1085     struct query *q;
1086     char *argv[];
1087     client *cl;
1088 ##{
1089 ##  int who;
1090 ##  char *login, *entity;
1091 ##  char fullname[129];
1092
1093     login = argv[0];
1094     who = cl->users_id;
1095     entity = cl->entity;
1096
1097     /* build fullname */
1098     if (strlen(argv[4]) && strlen(argv[5]))
1099         sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1100     else if (strlen(argv[4]))
1101         sprintf(fullname, "%s %s", argv[4], argv[3]);
1102     else
1103         sprintf(fullname, "%s", argv[3]);
1104
1105     /* create finger entry, pobox & set modtime on user */
1106 ##  repeat replace u (modtime = "now", modby=@who, modwith=@entity,
1107 ##           #fullname=@fullname, mit_affil = u.mit_year,
1108 ##           fmodtime="now", fmodby=@who, fmodwith=@entity,
1109 ##           potype="NONE", pmodtime="now", pmodby=@who, pmodwith=@entity)
1110 ##      where u.#login = @login
1111
1112     return(SMS_SUCCESS);
1113 ##}
1114
1115
1116 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1117  * type in argv[1].  Then completes the upcall to the user.
1118  *
1119  * argv[2] is of the form "123:234" where the first integer is the machine
1120  * ID if it is a pop box, and the second is the string ID if it is an SMTP
1121  * box.  argv[1] should be "POP", "SMTP", or "NONE".  Boxes of type NONE
1122  * are skipped.
1123  */
1124
1125 followup_gpob(q, sq, v, action, actarg, cl)
1126     register struct query *q;
1127     register struct save_queue *sq;
1128     register struct validate *v;
1129     register int (*action)();
1130     int actarg;
1131     client *cl;
1132 ##{
1133     char **argv, *index();
1134     char *ptype, *p;
1135 ##  char box[129], *name;
1136 ##  int mid, sid, rowcount;
1137
1138     /* for each row */
1139     while (sq_get_data(sq, &argv)) {
1140         sms_trim_args(2, argv);
1141         ptype = argv[1];
1142         p = index(argv[2], ':');
1143         *p++ = 0;
1144         mid = atoi(argv[2]);
1145         sid = atoi(p);
1146         free(argv[2]);
1147
1148         if (!strcmp(ptype, "POP")) {
1149 ##          repeat retrieve (box=machine.#name) where machine.mach_id=@mid
1150 ##          inquire_equel(rowcount = "rowcount")
1151             if (rowcount != 1)
1152               return(SMS_MACHINE);
1153         } else if (!strcmp(ptype, "SMTP")) {
1154 ##          repeat retrieve (box=strings.string) where strings.string_id=@sid
1155 ##          inquire_equel(rowcount = "rowcount")
1156             if (rowcount != 1)
1157               return(SMS_STRING);
1158         } else /* ptype == "NONE" */ {
1159             goto skip;
1160         }
1161
1162         if (!strcmp(q->shortname, "gpob")) {
1163             sid = atoi(argv[4]);
1164             free(argv[4]);
1165             argv[4] = malloc(9);
1166             name = argv[4];
1167 ##          repeat retrieve (name = users.login) where users.users_id = @sid
1168 ##          inquire_equel(rowcount = "rowcount")
1169             if (rowcount != 1)
1170               sprintf(name, "#%d", sid);
1171         }
1172
1173         argv[2] = box;
1174         (*action)(q->vcnt, argv, actarg);
1175     skip:
1176         /* free saved data */
1177         free(argv[0]);
1178         free(argv[1]);
1179         free(argv);
1180     }
1181
1182     sq_destroy(sq);
1183     return (SMS_SUCCESS);
1184 ##}
1185
1186
1187 /* followup_glin: fix the ace_name in argv[8].  argv[7] will contain the
1188  * ace_type: "LIST", "USER", or "NONE".  Decode the id in argv[8] into the
1189  * proper name based on the type, and repace that string in the argv.
1190  * Also fixes the modby field by called followup_fix_modby.
1191  */
1192
1193 followup_glin(q, sq, v, action, actarg, cl)
1194     register struct query *q;
1195     register struct save_queue *sq;
1196     register struct validate *v;
1197     register int (*action)();
1198     int actarg;
1199     client *cl;
1200 ##{
1201     char **argv, *malloc(), *realloc(), *type;
1202 ##  char *name;
1203 ##  int id, rowcount;
1204     int i, idx;
1205
1206     idx = 8;
1207     if (!strcmp(q->shortname, "gsin"))
1208       idx = 11;
1209
1210     while (sq_get_data(sq, &argv)) {
1211         sms_trim_args(q->vcnt, argv);
1212
1213         id = atoi(argv[i = q->vcnt - 2]);
1214         free(argv[i]);
1215         name = argv[i] = malloc(9);
1216 ##      repeat retrieve (name = users.login) where users.users_id = @id
1217 ##      inquire_equel(rowcount = "rowcount")
1218         if (rowcount != 1)
1219           sprintf(argv[i], "#%d", id);
1220
1221         id = atoi(argv[idx]);
1222         type = argv[idx - 1];
1223         if ((name = malloc(33)) == NULL)
1224             return(SMS_NO_MEM);
1225
1226         if (!strcmp(type, "LIST")) {
1227 ##          repeat retrieve (name = list.#name) where list.list_id = @id
1228 ##          inquire_equel(rowcount = "rowcount")
1229             if (rowcount != 1)
1230                 strcpy(name, "???");
1231         } else if (!strcmp(type, "USER")) {
1232 ##          repeat retrieve (name = users.login) where users.users_id = @id
1233 ##          inquire_equel(rowcount = "rowcount")
1234             if (rowcount != 1)
1235                 strcpy(name, "???");
1236         } else if (!strcmp(type, "NONE")) {
1237             strcpy(name, "NONE");
1238         } else
1239           strcpy(name, "???");
1240         free(argv[idx]);
1241         argv[idx] = name;
1242
1243         if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1244             argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1245             strcpy(argv[6], UNIQUE_GID);
1246         }
1247
1248         /* send the data */
1249         (*action)(q->vcnt, argv, actarg);
1250
1251         /* free saved data */
1252         for (i = 0; i < q->vcnt; i++) 
1253             free(argv[i]);
1254         free(argv);
1255     }
1256
1257     sq_destroy(sq);
1258     return (SMS_SUCCESS);
1259 ##}
1260
1261
1262 /** followup_amtl - followup for amtl and dmfl; when adding a list 
1263  **                 member to a maillist, make member list a maillist also
1264  **                 unless list is a user-group.
1265  **                 Then set_list_modtime_by_id.
1266  **
1267  ** Inputs:
1268  **   argv[0] - list_id
1269  **   argv[1] - member_type
1270  **   argv[2] - member_id
1271  **
1272  **/
1273
1274 followup_amtl(q, argv, cl)
1275     struct query *q;
1276     char *argv[];
1277     client *cl;
1278 ##{
1279 ##  int list_id;
1280 ##  int member_id;
1281 ##  int exists, who;
1282 ##  char *entity;
1283
1284     list_id = *(int *)argv[0];
1285     entity = cl->entity;
1286     who = cl->users_id;
1287
1288 ##  range of l is list
1289 ##  repeat replace l (modtime = "now", modby = @who, modwith = @entity)
1290 ##       where l.#list_id = @list_id
1291
1292     /* if query is not amtl or if member_type is not LIST then return */
1293     if (bcmp(q->shortname, "amtl", 4) || bcmp(argv[1], "LIST", 4)) 
1294         return(SMS_SUCCESS);
1295
1296     member_id = *(int *)argv[2];
1297
1298     /* is parent list a mailing list? */
1299 ##  repeat retrieve (exists = l.maillist) where l.#list_id=@list_id
1300     if (!exists)
1301         return(SMS_SUCCESS);
1302
1303     /* list is not a user-group; add list to maillist table */
1304 ##  repeat replace l (maillist = 1) where l.#list_id = @member_id
1305     return(SMS_SUCCESS);
1306 ##}
1307
1308
1309 /* followup_anfq: Add allocation to nfsphys after creating quota.
1310  *   argv[0] = filsys_id
1311  *   argv[2] = ascii(quota)
1312  */
1313
1314 followup_anfq(q, argv, cl)
1315     struct query  *q;
1316     char **argv;
1317     client *cl;
1318 ##{
1319 ##  int quota, user, fs, who;
1320 ##  char *entity;
1321
1322     fs = *(int *)argv[0];
1323     user = *(int *)argv[1];
1324     quota = atoi(argv[2]);
1325     who = cl->users_id;
1326     entity = cl->entity;
1327
1328 ##  repeat replace nq (modtime = "now", modby = @who, modwith = @entity)
1329 ##      where nq.filsys_id = @fs and nq.users_id = @user
1330 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
1331 ##      where nfsphys.nfsphys_id = filesys.#phys_id and filesys.filsys_id = @fs
1332     return(SMS_SUCCESS);
1333 ##}
1334
1335
1336 /* followup_gzcl:
1337  */
1338
1339 followup_gzcl(q, sq, v, action, actarg, cl)
1340     register struct query *q;
1341     register struct save_queue *sq;
1342     register struct validate *v;
1343     register int (*action)();
1344     int actarg;
1345     client *cl;
1346 ##{
1347 ##  char *name;
1348 ##  int rowcount, id;
1349     char **argv;
1350     int i;
1351
1352     while (sq_get_data(sq, &argv)) {
1353         sms_trim_args(q->vcnt, argv);
1354
1355         id = atoi(argv[i = q->vcnt - 2]);
1356         free(argv[i]);
1357         name = argv[i] = malloc(9);
1358 ##      repeat retrieve (name = users.login) where users.users_id = @id
1359 ##      inquire_equel(rowcount = "rowcount")
1360         if (rowcount != 1)
1361           sprintf(argv[i], "#%d", id);
1362
1363         for (i = 1; i < 8; i+=2) {
1364             id = atoi(argv[i+1]);
1365             free(argv[i+1]);
1366             if ((name = argv[i+1] = malloc(33)) == NULL)
1367               return(SMS_NO_MEM);
1368             if (!strcmp(argv[i], "LIST")) {
1369 ##              repeat retrieve (name = list.#name) where list.list_id = @id
1370 ##              inquire_equel(rowcount = "rowcount")
1371                 if (rowcount != 1)
1372                   strcpy(name, "???");
1373             } else if (!strcmp(argv[i], "USER")) {
1374 ##              repeat retrieve (name = users.login) where users.users_id = @id
1375 ##              inquire_equel(rowcount = "rowcount")
1376                 if (rowcount != 1)
1377                   strcpy(name, "???");
1378             } else if (!strcmp(argv[i], "NONE")) {
1379                 strcpy(name, "NONE");
1380             } else {
1381                 strcpy(name, "???");
1382             }
1383         }
1384
1385         /* send the data */
1386         (*action)(q->vcnt, argv, actarg);
1387
1388         /* free saved data */
1389         for (i = 0; i < q->vcnt; i++) 
1390             free(argv[i]);
1391         free(argv);
1392     }
1393     sq_destroy(sq);
1394     return(SMS_SUCCESS);
1395 ##}
1396
1397
1398 /* followup_gsha:
1399  */
1400
1401 followup_gsha(q, sq, v, action, actarg, cl)
1402     register struct query *q;
1403     register struct save_queue *sq;
1404     register struct validate *v;
1405     register int (*action)();
1406     int actarg;
1407     client *cl;
1408 ##{
1409 ##  char *name;
1410 ##  int rowcount, id;
1411     char **argv;
1412     int i;
1413
1414     while (sq_get_data(sq, &argv)) {
1415         sms_trim_args(q->vcnt, argv);
1416
1417         id = atoi(argv[4]);
1418         free(argv[4]);
1419         name = argv[4] = malloc(9);
1420 ##      repeat retrieve (name = users.login) where users.users_id = @id
1421 ##      inquire_equel(rowcount = "rowcount")
1422         if (rowcount != 1)
1423           sprintf(argv[4], "#%d", id);
1424
1425         id = atoi(argv[2]);
1426         free(argv[2]);
1427         if ((name = argv[2] = malloc(33)) == NULL)
1428           return(SMS_NO_MEM);
1429         if (!strcmp(argv[1], "LIST")) {
1430 ##          repeat retrieve (name = list.#name) where list.list_id = @id
1431 ##          inquire_equel(rowcount = "rowcount")
1432             if (rowcount != 1)
1433               strcpy(name, "???");
1434         } else if (!strcmp(argv[1], "USER")) {
1435 ##          repeat retrieve (name = users.login) where users.users_id = @id
1436 ##          inquire_equel(rowcount = "rowcount")
1437             if (rowcount != 1)
1438               strcpy(name, "???");
1439         } else if (!strcmp(argv[1], "NONE")) {
1440             strcpy(name, "NONE");
1441         } else {
1442             strcpy(name, "???");
1443         }
1444
1445         /* send the data */
1446         (*action)(q->vcnt, argv, actarg);
1447
1448         /* free saved data */
1449         for (i = 0; i < q->vcnt; i++) 
1450             free(argv[i]);
1451         free(argv);
1452     }
1453     sq_destroy(sq);
1454     return(SMS_SUCCESS);
1455 ##}
1456
1457
1458 \f
1459 /* Special query routines */
1460
1461 /* set_pobox - this does all of the real work.
1462  *       argv = user_id, type, box
1463  * if type is POP, then box should be a machine, and its ID should be put in
1464  * pop_id.  If type is SMTP, then box should be a string and its ID should
1465  * be put in box_id.  If type is NONE, then box doesn't matter.
1466  */
1467
1468 int set_pobox(q, argv, cl)
1469     struct query *q;
1470     char **argv;
1471     client *cl;
1472 ##{
1473 ##  int user, id, rowcount;
1474 ##  char *box, potype[9];
1475
1476     box = argv[2];
1477     user = *(int *)argv[0];
1478
1479 ##  repeat retrieve (id = users.pop_id, potype = users.#potype)
1480 ##              where users.users_id = @user
1481     if (!strcmp(potype, "POP"))
1482       set_pop_usage(id, -1);
1483
1484     if (!strcmp(argv[1], "POP")) {
1485 ##      repeat retrieve (id=machine.mach_id) where machine.name=uppercase(@box)
1486 ##      inquire_equel(rowcount = "rowcount")
1487         if (rowcount != 1)
1488             return(SMS_MACHINE);
1489 ##      repeat replace users (#potype = "POP", pop_id = @id)
1490 ##              where users.users_id = @user
1491         set_pop_usage(id, 1);
1492     } else if (!strcmp(argv[1], "SMTP")) {
1493 ##      range of s is strings
1494 ##      repeat retrieve (id = s.string_id) where s.string = @box
1495 ##      inquire_equel (rowcount = "rowcount")
1496         if (rowcount == 0) {
1497 ##          range of v is values
1498 ##          repeat retrieve (id = v.value) where v.name = "strings_id"
1499             id++;
1500 ##          repeat replace v (value = @id) where v.name = "strings_id"
1501 ##          append to strings (string_id = id, string = box)
1502         }
1503 ##      repeat replace users (#potype = "SMTP", box_id = @id) 
1504 ##             where users.users_id = @user
1505     } else /* argv[1] == "NONE" */ {
1506 ##      repeat replace users (#potype = "NONE") where users.users_id = @user
1507     }
1508
1509     set_pobox_modtime(q, argv, cl);
1510 ##  repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1511 ##      where tblstats.#table = "users"
1512     return(SMS_SUCCESS);
1513 ##}
1514
1515
1516 /* get_list_info:  passed a wildcard list name, returns lots of stuff about
1517  * each list.  This is tricky:  first build a queue of all requested
1518  * data.  Rest of processing consists of fixing gid, ace_name, and modby.
1519  */
1520
1521 get_list_info(q, aargv, cl, action, actarg)
1522     register struct query *q;
1523     char **aargv;
1524     client *cl;
1525     register int (*action)();
1526     int actarg;
1527 ##{
1528     char *argv[13], *malloc(), *realloc();
1529 ##  char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1530 ##  char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1531 ##  char modby[9], modwith[9];
1532 ##  int id, rowcount, acl_id, hid, modby_id;
1533     int returned;
1534     struct save_queue *sq, *sq_create();
1535
1536     returned = rowcount = 0;
1537     name = aargv[0];
1538
1539     sq = sq_create();
1540 ##  range of l is list
1541 ##  repeat retrieve (id = l.list_id) where l.#name = @name {
1542         sq_save_data(sq, id);
1543         rowcount++;
1544 ##  }
1545     if (rowcount == 0)
1546       return(SMS_NO_MATCH);
1547
1548     argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1549     argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1550     argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1551     argv[12] = modwith;
1552
1553     while (sq_get_data(sq, &id)) {
1554         if (id == 0)
1555           continue;
1556         argv[6] = gid;
1557 ##      repeat retrieve (listname = l.#name, active = text(l.#active), 
1558 ##              public = text(l.#public), hidden = text(l.#hidden),
1559 ##              hid = l.#hidden, maillist = text(l.#maillist),
1560 ##              group = text(l.#group), gid = text(l.#gid),
1561 ##              acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1562 ##              desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1563 ##              modwith =l.#modwith)
1564 ##          where l.list_id = @id
1565
1566         if (atoi(gid) == -1)
1567             argv[6] = UNIQUE_GID;
1568
1569         if (!strcmp(acl_type, "LIST")) {
1570 ##          repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1571 ##          inquire_equel(rowcount = "rowcount")
1572             if (rowcount != 1)
1573                 strcpy(acl_name, "???");
1574         } else if (!strcmp(acl_type, "USER")) {
1575 ##          repeat retrieve (acl_name = users.#login)
1576 ##              where users.users_id = @acl_id
1577 ##          inquire_equel(rowcount = "rowcount")
1578             if (rowcount != 1)
1579                 strcpy(acl_name, "???");
1580         } else if (!strcmp(acl_type, "NONE")) {
1581             strcpy(acl_name, "NONE");
1582         } else
1583           strcpy(acl_name, "???");
1584
1585 ##      repeat retrieve (modby = users.login) where users.users_id = @modby_id
1586 ##      inquire_equel(rowcount = "rowcount")
1587         if (rowcount != 1)
1588           sprintf(modby, "#%d", id);
1589
1590         sms_trim_args(q->vcnt, argv);
1591         returned++;
1592         (*action)(q->vcnt, argv, actarg);
1593     }
1594
1595     sq_destroy(sq);
1596 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1597 ##      where tblstats.#table = "list"
1598
1599     return (SMS_SUCCESS);
1600 ##}
1601
1602
1603 /* get_ace_use - given a type and a name, return a type and a name.
1604  * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
1605  * and argv[1] will contain the ID of the entity in question.  The R*
1606  * types mean to recursively look at every containing list, not just
1607  * when the object in question is a direct member.  On return, the
1608  * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
1609  */
1610
1611 int get_ace_use(q, argv, cl, action, actarg)
1612     struct query *q;
1613     char *argv[];
1614     client *cl;
1615     int (*action)();
1616     int actarg;
1617 ##{
1618     int found = 0;
1619 ##  char *atype;
1620 ##  int aid, listid, id;
1621     struct save_queue *sq, *sq_create();
1622
1623     atype = argv[0];
1624     aid = *(int *)argv[1];
1625     if (!strcmp(atype, "LIST") || !strcmp(atype, "USER")) {
1626         return(get_ace_internal(atype, aid, action, actarg));
1627     }
1628
1629     sq = sq_create();
1630     if (!strcmp(atype, "RLIST")) {
1631         sq_save_data(sq, aid);
1632         /* get all the list_id's of containing lists */
1633 ##      range of m is members
1634         while (sq_get_data(sq, &id)) {
1635 ##          repeat retrieve (listid = m.list_id)
1636 ##              where m.member_type = "LIST" and m.member_id = @id {
1637               sq_save_unique_data(sq, listid);
1638 ##          }
1639           }
1640         /* now process each one */
1641         while (sq_get_data(sq, &id)) {
1642             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1643               found++;
1644         }
1645     }
1646
1647     if (!strcmp(atype, "RUSER")) {
1648 ##      range of m is members
1649 ##      repeat retrieve (listid = m.list_id)
1650 ##              where m.member_type = "USER" and m.member_id = @aid {
1651             sq_save_data(sq, listid);
1652 ##      }
1653         /* get all the list_id's of containing lists */
1654         while (sq_get_data(sq, &id)) {
1655 ##          repeat retrieve (listid = m.list_id)
1656 ##              where m.member_type = "LIST" and m.member_id = @id {
1657               sq_save_unique_data(sq, listid);
1658 ##          }
1659           }
1660         /* now process each one */
1661         while (sq_get_data(sq, &id)) {
1662             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1663               found++;
1664         }
1665         if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1666           found++;
1667     }
1668
1669     sq_destroy(sq);     
1670     if (!found) return(SMS_NO_MATCH);
1671     return(SMS_SUCCESS);
1672 ##}
1673
1674
1675 /* This looks up a single list or user for ace use.  atype must be "USER"
1676  * or "LIST", and aid is the ID of the corresponding object.  This is used
1677  * by get_ace_use above.
1678  */
1679
1680 ##get_ace_internal(atype, aid, action, actarg)
1681 ##  char *atype;
1682 ##  int aid;
1683     int (*action)();
1684     int actarg;
1685 ##{
1686     char *rargv[2];
1687     int found = 0;
1688 ##  char name[33];
1689
1690     rargv[1] = name;
1691     if (!strcmp(atype, "LIST")) {
1692         rargv[0] = "FILESYS";
1693 ##      repeat retrieve (name = filesys.label) 
1694 ##              where filesys.owners = @aid {
1695             (*action)(2, rargv, actarg);
1696             found++;
1697 ##      }
1698
1699         rargv[0] = "QUERY";
1700 ##      repeat retrieve (name = capacls.capability)
1701 ##              where capacls.list_id = @aid {
1702             (*action)(2, rargv, actarg);
1703             found++;
1704 ##      }
1705     } else if (!strcmp(atype, "USER")) {
1706         rargv[0] = "FILESYS";
1707 ##      repeat retrieve (name = filesys.label) 
1708 ##              where filesys.owner = @aid {
1709             (*action)(2, rargv, actarg);
1710             found++;
1711 ##      }
1712     }
1713
1714     rargv[0] = "LIST";
1715 ##  repeat retrieve (name = list.#name) 
1716 ##              where list.acl_type = @atype and list.acl_id = @aid {
1717          (*action)(2, rargv, actarg);
1718          found++;
1719 ##  }
1720
1721     rargv[0] = "SERVICE";
1722 ##  repeat retrieve (name = servers.#name) 
1723 ##              where servers.acl_type = @atype and servers.acl_id = @aid {
1724          (*action)(2, rargv, actarg);
1725          found++;
1726 ##  }
1727
1728     rargv[0] = "HOSTACCESS";
1729 ##  repeat retrieve (name = machine.#name)
1730 ##              where machine.mach_id = hostaccess.mach_id and 
1731 ##                   hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
1732         (*action)(2, rargv, actarg);
1733         found++;
1734 ##  }
1735     rargv[0] = "ZEPHYR";
1736 ##  repeat retrieve (name = zephyr.class) 
1737 ##              where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
1738 ##                    zephyr.sub_type = @atype and zephyr.sub_id = @aid or
1739 ##                    zephyr.iws_type = @atype and zephyr.iws_id = @aid or
1740 ##                    zephyr.iui_type = @atype and zephyr.iui_id = @aid {
1741          (*action)(2, rargv, actarg);
1742          found++;
1743 ##  }
1744
1745     if (!found) return(SMS_NO_MATCH);
1746     return(SMS_SUCCESS);
1747 ##}
1748
1749
1750 /* get_lists_of_member - given a type and a name, return the name and flags
1751  * of all of the lists of the given member.  The member_type is one of
1752  * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
1753  * and argv[1] will contain the ID of the entity in question.  The R*
1754  * types mean to recursively look at every containing list, not just
1755  * when the object in question is a direct member.
1756  */
1757
1758 int get_lists_of_member(q, argv, cl, action, actarg)
1759     struct query *q;
1760     char *argv[];
1761     client *cl;
1762     int (*action)();
1763     int actarg;
1764 ##{
1765     int found = 0;
1766 ##  char *atype;
1767 ##  int aid, listid, id;
1768     struct save_queue *sq, *sq_create();
1769
1770     atype = argv[0];
1771     aid = *(int *)argv[1];
1772     if (!strcmp(atype, "LIST") ||
1773         !strcmp(atype, "USER") ||
1774         !strcmp(atype, "STRING")) {
1775       return(glom_internal(atype, aid, action, actarg));
1776     }
1777
1778     sq = sq_create();
1779     if (!strcmp(atype, "RLIST")) {
1780         sq_save_data(sq, aid);
1781         /* get all the list_id's of containing lists */
1782 ##      range of m is members
1783         while (sq_get_data(sq, &id)) {
1784 ##          repeat retrieve (listid = m.list_id)
1785 ##              where m.member_type = "LIST" and m.member_id = @id {
1786               sq_save_unique_data(sq, listid);
1787 ##          }
1788           }
1789         /* now process each one */
1790         while (sq_get_data(sq, &id)) {
1791             if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1792               found++;
1793         }
1794     }
1795
1796     if (!strcmp(atype, "RUSER")) {
1797 ##      range of m is members
1798 ##      repeat retrieve (listid = m.list_id)
1799 ##              where m.member_type = "USER" and m.member_id = @aid {
1800             sq_save_data(sq, listid);
1801 ##      }
1802         /* get all the list_id's of containing lists */
1803         while (sq_get_data(sq, &id)) {
1804 ##          repeat retrieve (listid = m.list_id)
1805 ##              where m.member_type = "LIST" and m.member_id = @id {
1806               sq_save_unique_data(sq, listid);
1807 ##          }
1808           }
1809         /* now process each one */
1810         while (sq_get_data(sq, &id)) {
1811             if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1812               found++;
1813         }
1814         if (glom_internal("USER", aid, action, actarg) == SMS_SUCCESS)
1815           found++;
1816     }
1817
1818     if (!strcmp(atype, "RSTRING")) {
1819 ##      range of m is members
1820 ##      repeat retrieve (listid = m.list_id)
1821 ##              where m.member_type = "STRING" and m.member_id = @aid {
1822             sq_save_data(sq, listid);
1823 ##      }
1824         /* get all the list_id's of containing lists */
1825         while (sq_get_data(sq, &id)) {
1826 ##          repeat retrieve (listid = m.list_id)
1827 ##              where m.member_type = "LIST" and m.member_id = @id {
1828               sq_save_unique_data(sq, listid);
1829 ##          }
1830           }
1831         /* now process each one */
1832         while (sq_get_data(sq, &id)) {
1833             if (glom_internal("LIST", id, action, actarg) == SMS_SUCCESS)
1834               found++;
1835         }
1836         if (glom_internal("STRING", aid, action, actarg) == SMS_SUCCESS)
1837           found++;
1838     }
1839
1840 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1841 ##      where tblstats.#table = "members"
1842     sq_destroy(sq);     
1843     if (!found) return(SMS_NO_MATCH);
1844     return(SMS_SUCCESS);
1845 ##}
1846
1847
1848 /* This looks up a single list, user, or string as a member.  atype must be
1849  * "USER", "LIST", or "STRING" and aid is the ID of the corresponding object.
1850  * This is used by get_lists_of_members above.
1851  */
1852
1853 ##glom_internal(atype, aid, action, actarg)
1854 ##  char *atype;
1855 ##  int aid;
1856     int (*action)();
1857     int actarg;
1858 ##{
1859     char *rargv[6];
1860     int found = 0;
1861 ##  char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
1862
1863     rargv[0] = name;
1864     rargv[1] = active;
1865     rargv[2] = public;
1866     rargv[3] = hidden;
1867     rargv[4] = maillist;
1868     rargv[5] = group;
1869 ##  repeat retrieve (name = list.#name, active = text(list.#active), 
1870 ##                   public = text(list.#public), hidden = text(list.#hidden),
1871 ##                   maillist = text(list.#maillist), group = text(list.#group))
1872 ##              where list.list_id = m.list_id and
1873 ##                    m.member_type = @atype and m.member_id = @aid {
1874          (*action)(6, rargv, actarg);
1875          found++;
1876 ##  }
1877
1878     if (!found) return(SMS_NO_MATCH);
1879     return(SMS_SUCCESS);
1880 ##}
1881
1882
1883 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
1884  * the five flags associated with each list.  It will return the name of
1885  * each list that meets the quailifications.  It does this by building a
1886  * where clause based on the arguments, then doing a retrieve.
1887  */
1888
1889 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
1890
1891 int qualified_get_lists(q, argv, cl, action, actarg)
1892     struct query *q;
1893     char *argv[];
1894     client *cl;
1895     int (*action)();
1896     int actarg;
1897 {
1898     return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
1899                          "l", "name", lflags));
1900 }
1901
1902
1903 /** get_members_of_list - optimized query for retrieval of list members
1904  **
1905  ** Inputs:
1906  **   argv[0] - list_id
1907  **
1908  ** Description:
1909  **   - retrieve USER members, then LIST members, then STRING members
1910  **/
1911
1912 get_members_of_list(q, argv, cl, action, actarg)
1913     struct query *q;
1914     char *argv[];
1915     client *cl;
1916     int (*action)();
1917     int actarg;
1918 ##{
1919 ##  int list_id;
1920 ##  char member_name[129];
1921     char *targv[2];
1922
1923     list_id = *(int *)argv[0];
1924     targv[0] = "USER";
1925     targv[1] = member_name;
1926
1927 ##  range of m is members
1928 ##  repeat retrieve (member_name = users.login)
1929 ##             where m.#list_id = @list_id and m.member_type = "USER"
1930 ##                   and m.member_id = users.users_id
1931 ##             sort by #member_name
1932 ##  {
1933          (*action)(2, targv, actarg);
1934 ##  }
1935
1936     targv[0] = "LIST";
1937 ##  repeat retrieve (member_name = list.name)
1938 ##             where m.#list_id = @list_id and m.member_type = "LIST"
1939 ##                   and m.member_id = list.#list_id
1940 ##             sort by #member_name
1941 ##  {
1942          (*action)(2, targv, actarg);
1943 ##  }
1944
1945     targv[0] = "STRING";
1946 ##  repeat retrieve (member_name = strings.string)
1947 ##             where m.#list_id = @list_id and m.member_type = "STRING"
1948 ##                   and m.member_id = strings.string_id
1949 ##             sort by #member_name
1950 ##  {
1951          (*action)(2, targv, actarg);
1952 ##  }
1953
1954 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1955 ##      where tblstats.#table = "members"
1956     return(SMS_SUCCESS);
1957 ##}
1958
1959
1960 /* count_members_of_list: this is a simple query, but it cannot be done
1961  * through the dispatch table.
1962  */
1963
1964 int count_members_of_list(q, argv, cl, action, actarg)
1965     struct query *q;
1966     char *argv[];
1967     client *cl;
1968     int (*action)();
1969     int actarg;
1970 ##{
1971 ##  int  list, ct = 0;
1972     char *rargv[1], countbuf[5];
1973
1974     list = *(int *)argv[0];
1975     rargv[0] = countbuf;
1976 ##  repeat retrieve (ct = count(members.list_id where members.list_id = @list))
1977     sprintf(countbuf, "%d", ct);
1978     (*action)(1, rargv, actarg);
1979 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1980 ##      where tblstats.#table = "members"
1981     return(SMS_SUCCESS);
1982 ##}
1983
1984
1985 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
1986  * the three flags associated with each service.  It will return the name of
1987  * each service that meets the quailifications.  It does this by building a
1988  * where clause based on the arguments, then doing a retrieve.
1989  */
1990
1991 static char *sflags[3] = { "enable", "inprogress", "harderror" };
1992
1993 int qualified_get_server(q, argv, cl, action, actarg)
1994     struct query *q;
1995     char *argv[];
1996     client *cl;
1997     int (*action)();
1998     int actarg;
1999 {
2000     return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2001                          "s", "name", sflags));
2002 }
2003
2004
2005 /* generic qualified get routine, used by qualified_get_lists,
2006  * qualified_get_server, and qualified_get_serverhost.
2007  *   Args:
2008  *      start - a simple where clause, must not be empty
2009  *      range - the name of the range variable
2010  *      field - the field to return
2011  *      flags - an array of strings, names of the flag variables
2012  */
2013
2014 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2015     struct query *q;
2016     char *argv[];
2017     int (*action)();
2018     int actarg;
2019     char *start;
2020     char *range;
2021     char *field;
2022     char *flags[];
2023 ##{
2024 ##  char name[33], qual[256], *rvar, *rtbl, *rfield;
2025     char *rargv[1], buf[32];
2026 ##  int rowcount, i;
2027
2028     strcpy(qual, start);
2029     for (i = 0; i < q->argc; i++) {
2030         if (!strcmp(argv[i], "TRUE")) {
2031             sprintf(buf, " and %s.%s != 0", range, flags[i]);
2032             (void) strcat(qual, buf);
2033         } else if (!strcmp(argv[i], "FALSE")) {
2034             sprintf(buf, " and %s.%s = 0", range, flags[i]);
2035             (void) strcat(qual, buf);
2036         }
2037     }
2038       
2039     rargv[0] = name;
2040     rvar = range;
2041     rtbl = q->rtable;
2042     rfield = field;
2043 ##  range of rvar is rtbl
2044 ##  retrieve (name = rvar.rfield) where qual {
2045         (*action)(1, rargv, actarg);
2046 ##  }
2047 ##  inquire_equel(rowcount = "rowcount")
2048 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2049 ##      where tblstats.#table = @rtbl
2050     if (rowcount == 0)
2051       return(SMS_NO_MATCH);
2052     return(SMS_SUCCESS);
2053 ##}
2054
2055
2056 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2057  * the five flags associated with each serverhost.  It will return the name of
2058  * each service and host that meets the quailifications.  It does this by 
2059  * building a where clause based on the arguments, then doing a retrieve.
2060  */
2061
2062 static char *shflags[6] = { "service", "enable", "override", "success",
2063                             "inprogress", "hosterror" };
2064
2065 int qualified_get_serverhost(q, argv, cl, action, actarg)
2066     struct query *q;
2067     char *argv[];
2068     client *cl;
2069     int (*action)();
2070     int actarg;
2071 ##{
2072 ##  char sname[33], mname[33], qual[256];
2073     char *rargv[2], buf[32];
2074 ##  int rowcount, i;
2075
2076     sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2077             argv[0]);
2078     for (i = 1; i < q->argc; i++) {
2079         if (!strcmp(argv[i], "TRUE")) {
2080             sprintf(buf, " and sh.%s != 0", shflags[i]);
2081             strcat(qual, buf);
2082         } else if (!strcmp(argv[i], "FALSE")) {
2083             sprintf(buf, " and sh.%s = 0", shflags[i]);
2084             strcat(qual, buf);
2085         }
2086     }
2087       
2088     rargv[0] = sname;
2089     rargv[1] = mname;
2090 ##  range of sh is serverhosts
2091 ##  retrieve (sname = sh.service, mname = machine.name) where qual {
2092         (*action)(2, rargv, actarg);
2093 ##  }
2094 ##  inquire_equel(rowcount = "rowcount")
2095 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2096 ##      where tblstats.#table = "serverhosts"
2097     if (rowcount == 0)
2098       return(SMS_NO_MATCH);
2099     return(SMS_SUCCESS);
2100 ##}
2101
2102
2103 /* register_user - change user's login name and allocate a pobox, group,
2104  * filesystem, and quota for them.  The user's status must start out as 0,
2105  * and is left as 2.  Arguments are: user's UID, new login name, and user's
2106  * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY, 
2107  * SMS_FS_STAFF, SMS_FS_MISC).
2108  */
2109
2110 register_user(q, argv, cl)
2111     struct query *q;
2112     char **argv;
2113     client *cl;
2114 ##{
2115 ##  char *login, dir[65], *entity, *directory, machname[33];
2116 ##  int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2117 ##  int size, alloc, pid, m_id;
2118     int maxsize;
2119
2120     entity = cl->entity;
2121     who = cl->users_id;
2122
2123     uid = atoi(argv[0]);
2124     login = argv[1];
2125     utype = atoi(argv[2]);
2126
2127 ##  range of u is users
2128 ##  range of l is list
2129 ##  range of sh is serverhosts
2130 ##  range of n is nfsphys
2131 ##  range of m is machine
2132
2133     /* find user */
2134 ##  repeat retrieve (users_id = u.#users_id)
2135 ##      where u.#uid = @uid and u.status = 0
2136 ##  inquire_equel(rowcount = "rowcount");
2137     if (rowcount == 0)
2138       return(SMS_NO_MATCH);
2139     if (rowcount > 1)
2140       return(SMS_NOT_UNIQUE);
2141
2142     /* check new login name */
2143 ##  repeat retrieve (flag = any(u.#login where u.#login = @login))
2144     if (flag)
2145       return(SMS_IN_USE);
2146 ##  repeat retrieve (flag = any(l.name where l.name = @login))
2147     if (flag)
2148       return(SMS_IN_USE);
2149 ##  repeat retrieve (flag = any(filesys.#name where filesys.#name = @login))
2150     if (flag)
2151       return(SMS_IN_USE);
2152     com_err(whoami, 0, "new login name OK");
2153
2154     /* choose place for pobox, put in mid */
2155 ##  repeat retrieve (mid = sh.mach_id, machname = m.name)
2156 ##    where sh.service = "POP" and m.mach_id = sh.mach_id and
2157 ##      sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2158 ##  inquire_equel(rowcount = "rowcount");
2159     if (rowcount == 0)
2160       return(SMS_NO_POBOX);
2161
2162     /* change login name, set pobox */
2163 ##  repeat replace u (#login = @login, status = 2, modtime = "now",
2164 ##                    modby = @who, modwith = @entity, potype="POP",
2165 ##                    pop_id = @mid, pmodtime="now", pmodby=@who,
2166 ##                    pmodwith=@entity)
2167 ##      where u.#users_id = @users_id
2168 ##  inquire_equel(rowcount = "rowcount");
2169     if (rowcount != 1)
2170       return(SMS_INTERNAL);
2171     set_pop_usage(mid, 1);
2172     com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2173             trim(machname));
2174
2175     /* create group list */
2176     if (set_next_object_id("gid", "list"))
2177       return(SMS_NO_ID);
2178     if (set_next_object_id("list_id", "list"))
2179       return(SMS_NO_ID);
2180 ##  repeat retrieve (list_id = values.value) where values.name = "list_id"
2181 ##  inquire_equel(rowcount = "rowcount");
2182     if (rowcount != 1)
2183       return(SMS_INTERNAL);
2184 ##  repeat append list (name = @login, #list_id = @list_id, active = 1,
2185 ##                      public = 0, hidden = 0, maillist = 0, group = 1,
2186 ##                      #gid = values.value, desc = "User Group",
2187 ##                      acl_type = "USER", acl_id = @users_id, modtime = "now",
2188 ##                      modby = @who, modwith = @entity)
2189 ##      where values.name = "gid"
2190 ##  inquire_equel(rowcount = "rowcount");
2191     if (rowcount != 1)
2192       return(SMS_INTERNAL);
2193 ##  repeat append members (#list_id = @list_id, member_type = "USER",
2194 ##                         member_id = @users_id)
2195 ##  inquire_equel(rowcount = "rowcount");
2196     if (rowcount != 1)
2197       return(SMS_INTERNAL);
2198     com_err(whoami, 0, "group list created");
2199
2200     /* decide where to put filesystem */
2201     maxsize = 0;
2202     directory = NULL;
2203 ##  repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2204 ##                   flag = n.status, size = n.#size, alloc = n.allocated) {
2205         if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2206             maxsize = size - alloc;
2207             if (directory)
2208               free(directory);
2209             directory = strsave(dir);
2210             pid = nid;
2211             m_id = mid;
2212         }
2213 ##  }
2214     if (maxsize == 0)
2215       return(SMS_NO_FILESYS);
2216
2217     /* create filesystem */
2218     if (set_next_object_id("filsys_id", "filesys"))
2219       return(SMS_NO_ID);
2220 ##  repeat append filesys (filsys_id = values.value, phys_id = @pid,
2221 ##                         label = @login, type = "NFS", mach_id = @m_id,
2222 ##                         name = @directory + @login, mount = "/mit/" + @login,
2223 ##                         access = "w", comments = "User Locker",
2224 ##                         owner = @users_id, owners = @list_id, createflg = 1,
2225 ##                         lockertype = "HOMEDIR", modtime = "now",
2226 ##                         modby = @who, modwith = @entity)
2227 ##      where values.name = "filsys_id"
2228 ##  inquire_equel(rowcount = "rowcount");
2229     if (rowcount != 1)
2230       return(SMS_INTERNAL);
2231     com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2232             trim(directory), login);
2233
2234     /* set quota */
2235 ##  repeat retrieve (quota = values.value) where values.name = "def_quota"
2236 ##  inquire_equel(rowcount = "rowcount");
2237     if (rowcount != 1)
2238       return(SMS_NO_QUOTA);
2239 ##  repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2240 ##                          #quota = @quota, modtime = "now", modby = @who,
2241 ##                          modwith = @entity)
2242 ##      where values.name = "filsys_id"
2243 ##  inquire_equel(rowcount = "rowcount");
2244     if (rowcount != 1)
2245       return(SMS_INTERNAL);
2246 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2247 ##      where nfsphys.nfsphys_id = filesys.#phys_id and
2248 ##            filesys.filsys_id = values.value and values.name = "filsys_id"
2249 ##  inquire_equel(rowcount = "rowcount");
2250     if (rowcount != 1)
2251       return(SMS_INTERNAL);
2252     com_err(whoami, 0, "quota of %d assigned", quota);
2253
2254     return(SMS_SUCCESS);
2255 ##}
2256
2257
2258
2259 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2260  **
2261  ** Inputs:
2262  **   id of machine
2263  **   delta (will be +/- 1)
2264  **
2265  ** Description:
2266  **   - incr/decr value field in serverhosts table for pop/mach_id
2267  **
2268  **/
2269
2270 static int set_pop_usage(id, count)
2271 int id;
2272 int count;
2273 ##{
2274 ##  int mach_id = id;
2275 ##  int n = count;
2276
2277 ##  range of sh is serverhosts
2278 ##  repeat replace sh (value1 = sh.value1 + @n)
2279 ##         where sh.service = "POP" and sh.#mach_id = @mach_id
2280
2281     return(SMS_SUCCESS);
2282 ##}
2283
2284
2285 \f
2286 /* Validation Routines */
2287
2288 validate_row(q, argv, v)
2289     register struct query *q;
2290     char *argv[];
2291     register struct validate *v;
2292 ##{
2293 ##  char *rvar;
2294 ##  char *table;
2295 ##  char *name;
2296 ##  char qual[128];
2297 ##  int rowcount;
2298
2299     /* build where clause */
2300     build_qual(v->qual, v->argc, argv, qual);
2301
2302     /* setup ingres variables */
2303     rvar = q->rvar;
2304     table = q->rtable;
2305     name = v->field;
2306
2307     if (log_flags & LOG_RES)
2308         /* tell the logfile what we're doing */
2309         com_err(whoami, 0, "validating row: %s", qual);
2310     
2311     /* look for the record */
2312 ##  range of rvar is table
2313 ##  retrieve (rowcount = count(rvar.name where qual))
2314     if (rowcount == 0) return(SMS_NO_MATCH);
2315     if (rowcount > 1) return(SMS_NOT_UNIQUE);
2316     return(SMS_EXISTS);
2317 ##}
2318
2319 validate_fields(q, argv, vo, n)
2320     struct query *q;
2321     register char *argv[];
2322     register struct valobj *vo;
2323     register int n;
2324 {
2325     register int status;
2326
2327     while (--n >= 0) {
2328         switch (vo->type) {
2329         case V_NAME:
2330             if (log_flags & LOG_RES)
2331                 com_err(whoami, 0, "validating %s in %s: %s", 
2332                     vo->namefield, vo->table, argv[vo->index]);
2333             status = validate_name(argv, vo);
2334             break;
2335
2336         case V_ID:
2337             if (log_flags & LOG_RES)
2338                 com_err(whoami, 0, "validating %s in %s: %s", 
2339                     vo->idfield, vo->table, argv[vo->index]);
2340             status = validate_id(argv, vo);
2341             break;
2342
2343         case V_DATE:
2344             if (log_flags & LOG_RES)
2345                 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2346             status = validate_date(argv, vo);
2347             break;
2348
2349         case V_TYPE:
2350             if (log_flags & LOG_RES)
2351                 com_err(whoami, 0, "validating %s type: %s",
2352                     vo->table, argv[vo->index]);
2353             status = validate_type(argv, vo);
2354             break;
2355
2356         case V_TYPEDATA:
2357             if (log_flags & LOG_RES)
2358                 com_err(whoami, 0, "validating typed data (%s): %s",
2359                     argv[vo->index - 1], argv[vo->index]);
2360             status = validate_typedata(q, argv, vo);
2361             break;
2362
2363         case V_RENAME:
2364             if (log_flags & LOG_RES)
2365                 com_err(whoami, 0, "validating rename %s in %s",
2366                         argv[vo->index], vo->table);
2367             status = validate_rename(argv, vo);
2368             break;
2369
2370         case V_CHAR:
2371             if (log_flags & LOG_RES)
2372               com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2373             status = validate_chars(argv[vo->index]);
2374             break;
2375
2376         case V_SORT:
2377             status = SMS_EXISTS;
2378             break;
2379
2380         }
2381
2382         if (status != SMS_EXISTS) return(status);
2383         vo++;
2384     }
2385
2386     return(SMS_SUCCESS);
2387 }
2388
2389
2390 /* validate_chars: verify that there are no illegal characters in
2391  * the string.  Legal characters are printing chars other than 
2392  * ", *, ?, [ and ].
2393  */
2394 static int illegalchars[] = {
2395     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2396     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2397     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2398     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2399     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2400     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, /* P - _ */
2401     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2402     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2403     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2404     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2405     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2406     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2407     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2408     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2409     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2410     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2411 };
2412
2413 validate_chars(s)
2414 register char *s;
2415 {
2416     while (*s)
2417       if (illegalchars[*s++])
2418         return(SMS_BAD_CHAR);
2419     return(SMS_EXISTS);
2420 }
2421
2422
2423 validate_id(argv, vo)
2424     char *argv[];
2425     register struct valobj *vo;
2426 ##{
2427 ##  char *name;
2428 ##  char *table;
2429 ##  char *namefield;
2430 ##  char *idfield;
2431 ##  int id;
2432 ##  int rowcount;
2433     register char *c;
2434
2435     name = argv[vo->index];
2436     table = vo->table;
2437     /* minor kludge to upcasify machine names */
2438     if (!strcmp(table, "machine"))
2439         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2440     namefield = vo->namefield;
2441     idfield = vo->idfield;
2442     if (!strcmp(namefield, "uid")) {
2443 ##    retrieve (id = table.idfield) where table.namefield = int4(name)
2444 ##    inquire_equel (rowcount = "rowcount")
2445     } else {
2446 ##    retrieve (id = table.idfield) where table.namefield = name
2447 ##    inquire_equel (rowcount = "rowcount")
2448     }
2449     if (rowcount != 1) return(vo->error);
2450     *(int *)argv[vo->index] = id;
2451     return(SMS_EXISTS);
2452 ##}
2453
2454 validate_name(argv, vo)
2455     char *argv[];
2456     register struct valobj *vo;
2457 ##{
2458 ##  char *name;
2459 ##  char *table;
2460 ##  char *namefield;
2461 ##  int rowcount;
2462     register char *c;
2463
2464     name = argv[vo->index];
2465     table = vo->table;
2466     namefield = vo->namefield;
2467     if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2468         for (c = name; *c; c++)
2469           if (islower(*c))
2470             *c = toupper(*c);
2471     }
2472 ##  retrieve (rowcount = countu(table.namefield 
2473 ##            where table.namefield = name))
2474     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2475 ##}
2476
2477 validate_date(argv, vo)
2478     char *argv[];
2479     struct valobj *vo;
2480 ##{
2481 ##  char *idate;
2482 ##  double dd;
2483 ##  int errorno;
2484
2485     idate = argv[vo->index];
2486
2487 ##  retrieve (dd = interval("years", date(idate) - date("today")))
2488 ##  inquire_equel (errorno = "errorno")
2489     if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2490     return(SMS_EXISTS);
2491 ##}
2492
2493
2494 validate_rename(argv, vo)
2495 char *argv[];
2496 struct valobj *vo;
2497 ##{
2498 ##  char *name, *table, *namefield, *idfield;
2499 ##  int id;
2500     register char *c;
2501
2502     c = name = argv[vo->index];
2503     while (*c)
2504       if (illegalchars[*c++])
2505         return(SMS_BAD_CHAR);
2506     table = vo->table;
2507     /* minor kludge to upcasify machine names */
2508     if (!strcmp(table, "machine"))
2509         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2510     namefield = vo->namefield;
2511     idfield = vo->idfield;
2512     id = -1;
2513     if (idfield == 0) {
2514         if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2515           return(SMS_EXISTS);
2516 ##      retrieve (id = any(table.namefield where table.namefield = name))
2517         if (id)
2518           return(vo->error);
2519         else
2520           return(SMS_EXISTS);
2521     }
2522 ##  retrieve (id = table.idfield) where table.namefield = name
2523     if (id == -1 || id == *(int *)argv[vo->index - 1])
2524       return(SMS_EXISTS);
2525     else
2526       return(vo->error);
2527 ##}
2528
2529
2530 validate_type(argv, vo)
2531     char *argv[];
2532     register struct valobj *vo;
2533 ##{
2534 ##  char *typename;
2535 ##  char *value;
2536 ##  int exists;
2537     register char *c;
2538
2539     typename = vo->table;
2540     c = value = argv[vo->index];
2541     while (*c)
2542       if (illegalchars[*c++])
2543         return(SMS_BAD_CHAR);
2544
2545     /* uppercase type fields */
2546     for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
2547
2548 ##  range of a is alias
2549 ##  repeat retrieve (exists = any(a.trans where a.name = @typename and
2550 ##                                    a.type = "TYPE" and
2551 ##                                    a.trans = @value))
2552     return (exists ? SMS_EXISTS : vo->error);
2553 ##}
2554
2555 /* validate member or type-specific data field */
2556
2557 validate_typedata(q, argv, vo)
2558     register struct query *q;
2559     register char *argv[];
2560     register struct valobj *vo;
2561 ##{
2562 ##  char *name;
2563 ##  char *field_type;
2564 ##  char data_type[129];
2565 ##  int id;
2566 ##  int rowcount;
2567     char *index();
2568     register char *c;
2569
2570     /* get named object */
2571     name = argv[vo->index];
2572
2573     /* get field type string (known to be at index-1) */
2574     field_type = argv[vo->index-1];
2575
2576     /* get corresponding data type associated with field type name */
2577 ##  repeat retrieve (data_type = alias.trans) 
2578 ##         where alias.#name = @field_type and alias.type = "TYPEDATA"
2579 ##  inquire_equel (rowcount = "rowcount")
2580     if (rowcount != 1) return(SMS_TYPE);
2581
2582     /* now retrieve the record id corresponding to the named object */
2583     if (index(data_type, ' '))
2584         *index(data_type, ' ') = 0;
2585     if (!strcmp(data_type, "user")) {
2586         /* USER */
2587 ##      repeat retrieve (id = users.users_id) where users.login = @name
2588 ##      inquire_equel (rowcount = "rowcount")
2589         if (rowcount != 1) return(SMS_USER);
2590
2591     } else if (!strcmp(data_type, "list")) {
2592         /* LIST */
2593 ##      repeat retrieve (id = list.list_id) where list.#name = @name
2594 ##      inquire_equel (rowcount = "rowcount")
2595         if (rowcount != 1) {
2596             /* if idfield is non-zero, then if argv[0] matches the string
2597              * that we're trying to resolve, we should get the value of
2598              * values.[idfield] for the id.
2599              */
2600             if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
2601                 name = vo->idfield;
2602 ##              repeat retrieve (id = values.value+1) where values.#name = @name
2603 ##              inquire_equel(rowcount = "rowcount")
2604                 if (rowcount != 1) return(SMS_LIST);
2605             } else
2606               return(SMS_LIST);
2607         }
2608     } else if (!strcmp(data_type, "machine")) {
2609         /* MACHINE */
2610         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2611 ##      repeat retrieve (id = machine.mach_id) where machine.#name = @name
2612 ##      inquire_equel (rowcount = "rowcount")
2613         if (rowcount != 1) return(SMS_MACHINE);
2614
2615     } else if (!strcmp(data_type, "string")) {
2616         /* STRING */
2617 ##      range of s is strings
2618 ##      repeat retrieve (id = s.string_id) where s.string = @name
2619 ##      inquire_equel (rowcount = "rowcount")
2620         if (rowcount == 0) {
2621             if (q->type != APPEND) return(SMS_STRING);
2622 ##          range of v is values
2623 ##          retrieve (id = v.value) where v.#name = "strings_id"
2624             id++;
2625 ##          replace v (value = id) where v.#name = "strings_id"
2626 ##          append to strings (string_id = id, string = name)
2627         }
2628     } else if (!strcmp(data_type, "none")) {
2629         id = 0;
2630     } else {
2631         return(SMS_TYPE);
2632     }
2633
2634     /* now set value in argv */
2635     *(int *)argv[vo->index] = id;
2636     
2637     return (SMS_EXISTS);
2638 ##}
2639
2640
2641 /* This looks up a login name and returns the SMS internal ID.  It is used
2642  * by authenticate to put the users_id in the client structure.
2643  */
2644
2645 int get_users_id(name)
2646 char *name;
2647 ##{
2648 ##  int id, rowcount;
2649 ##  char *login;
2650
2651     login = name;
2652
2653 ##  range of u is users
2654 ##  repeat retrieve (id = u.#users_id) where u.#login = @login
2655 ##  inquire_equel (rowcount = "rowcount")
2656     
2657     if (rowcount == 1)
2658         return(id);
2659     else
2660         return(0);
2661 ##}
2662
2663
2664 /* Check the database at startup time.  For now this just resets the
2665  * inprogress flags that the DCM uses.
2666  */
2667
2668 sanity_check_database()
2669 ##{
2670 ##  replace servers (inprogress = 0)
2671 ##  replace serverhosts (inprogress = 0)
2672 ##}
This page took 0.246587 seconds and 5 git commands to generate.