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