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