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