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