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