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