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