]> andersk Git - moira.git/blob - server/qsupport.qc
24f1bfd5e5045ae10572055692af60eaf86e567d
[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         if (index(box, '/') || index(box, '|'))
1695           return(SMS_BAD_CHAR);
1696 ##      range of s is strings
1697 ##      repeat retrieve (id = s.string_id) where s.string = @box
1698 ##      inquire_equel (rowcount = "rowcount")
1699         if (rowcount == 0) {
1700 ##          range of v is values
1701 ##          repeat retrieve (id = v.value) where v.name = "strings_id"
1702             id++;
1703 ##          repeat replace v (value = @id) where v.name = "strings_id"
1704 ##          append to strings (string_id = id, string = box)
1705         }
1706 ##      repeat replace users (#potype = "SMTP", box_id = @id) 
1707 ##             where users.users_id = @user
1708     } else /* argv[1] == "NONE" */ {
1709 ##      repeat replace users (#potype = "NONE") where users.users_id = @user
1710     }
1711
1712     set_pobox_modtime(q, argv, cl);
1713 ##  repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
1714 ##      where tblstats.#table = "users"
1715     if (ingres_errno) return(sms_errcode);
1716     return(SMS_SUCCESS);
1717 ##}
1718
1719
1720 /* get_list_info:  passed a wildcard list name, returns lots of stuff about
1721  * each list.  This is tricky:  first build a queue of all requested
1722  * data.  Rest of processing consists of fixing gid, ace_name, and modby.
1723  */
1724
1725 get_list_info(q, aargv, cl, action, actarg)
1726     register struct query *q;
1727     char **aargv;
1728     client *cl;
1729     register int (*action)();
1730     int actarg;
1731 ##{
1732     char *argv[13], *malloc(), *realloc();
1733 ##  char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1734 ##  char maillist[5], group[5], gid[6], acl_name[33], desc[256], modtime[27];
1735 ##  char modby[256], modwith[9];
1736 ##  int id, rowcount, acl_id, hid, modby_id;
1737     int returned;
1738     struct save_queue *sq, *sq_create();
1739
1740     returned = rowcount = 0;
1741     name = aargv[0];
1742
1743     sq = sq_create();
1744 ##  range of l is list
1745 ##  repeat retrieve (id = l.list_id) where l.#name = @name {
1746         sq_save_data(sq, id);
1747         rowcount++;
1748 ##  }
1749     if (ingres_errno) return(sms_errcode);
1750     if (rowcount == 0)
1751       return(SMS_NO_MATCH);
1752
1753     argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
1754     argv[4] = maillist; argv[5] = group; argv[6] = gid; argv[7] = acl_type;
1755     argv[8] = acl_name; argv[9] = desc; argv[10] = modtime; argv[11] = modby;
1756     argv[12] = modwith;
1757
1758     while (sq_get_data(sq, &id)) {
1759         if (id == 0)
1760           continue;
1761         argv[6] = gid;
1762 ##      repeat retrieve (listname = l.#name, active = text(l.#active), 
1763 ##              public = text(l.#public), hidden = text(l.#hidden),
1764 ##              hid = l.#hidden, maillist = text(l.#maillist),
1765 ##              group = text(l.#group), gid = text(l.#gid),
1766 ##              acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
1767 ##              desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
1768 ##              modwith =l.#modwith)
1769 ##          where l.list_id = @id
1770         if (ingres_errno) return(sms_errcode);
1771
1772         if (atoi(gid) == -1)
1773             argv[6] = UNIQUE_GID;
1774
1775         if (!strcmp(acl_type, "LIST")) {
1776 ##          repeat retrieve (acl_name = l.#name) where l.list_id = @acl_id
1777 ##          inquire_equel(rowcount = "rowcount")
1778             if (rowcount != 1)
1779                 strcpy(acl_name, "???");
1780         } else if (!strcmp(acl_type, "USER")) {
1781 ##          repeat retrieve (acl_name = users.#login)
1782 ##              where users.users_id = @acl_id
1783 ##          inquire_equel(rowcount = "rowcount")
1784             if (rowcount != 1)
1785                 strcpy(acl_name, "???");
1786         } else if (!strcmp(acl_type, "KERBEROS")) {
1787 ##          repeat retrieve (acl_name = strings.string)
1788 ##              where strings.string_id = @acl_id
1789 ##          inquire_equel(rowcount = "rowcount")
1790             if (rowcount != 1)
1791                 strcpy(acl_name, "???");
1792         } else if (!strcmp(acl_type, "NONE")) {
1793             strcpy(acl_name, "NONE");
1794         } else
1795           strcpy(acl_name, "???");
1796
1797         if (modby_id > 0)
1798 ##        repeat retrieve (modby = users.login) where users.users_id = @modby_id
1799         else {
1800             modby_id = -modby_id;
1801 ##           repeat retrieve (modby = strings.string) 
1802 ##              where strings.string_id = @modby_id
1803             modby_id = -modby_id;
1804         }
1805 ##      inquire_equel(rowcount = "rowcount")
1806         if (rowcount != 1)
1807           sprintf(modby, "#%d", modby_id);
1808         if (ingres_errno) return(sms_errcode);
1809
1810         sms_trim_args(q->vcnt, argv);
1811         returned++;
1812         (*action)(q->vcnt, argv, actarg);
1813     }
1814
1815     sq_destroy(sq);
1816     if (ingres_errno) return(sms_errcode);
1817 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
1818 ##      where tblstats.#table = "list"
1819
1820     return (SMS_SUCCESS);
1821 ##}
1822
1823
1824 /* Add_member_to_list: do list flattening as we go!  MAXLISTDEPTH is
1825  * how many different ancestors a member is allowed to have.
1826  */
1827
1828 #define MAXLISTDEPTH    100
1829
1830 int add_member_to_list(q, argv, cl)
1831     struct query *q;
1832     char **argv;
1833     client *cl;
1834 ##{
1835 ##  int id, lid, mid, exists, error;
1836 ##  char *mtype, dtype[9], buf[256];
1837     int ancestors[MAXLISTDEPTH], acount, a;
1838     int descendants[MAXLISTDEPTH], dcount, d;
1839     char *dtypes[MAXLISTDEPTH];
1840     char *iargv[3];
1841
1842 ##  range of m is imembers
1843     lid = *(int *)argv[0];
1844     mtype = argv[1];
1845     mid = *(int *)argv[2];
1846 ##  repeat retrieve (exists = any(m.list_id where m.list_id=@lid and 
1847 ##                         m.member_id = @mid and m.member_type = @mtype
1848 ##                         and m.direct = 1))
1849     if (exists)
1850       return(SMS_EXISTS);
1851     if (!strcasecmp(mtype, "STRING")) {
1852 ##      repeat retrieve (buf = strings.string) where strings.string_id = @mid
1853         if (index(buf, '/') || index(buf, '|'))
1854           return(SMS_BAD_CHAR);
1855     }
1856
1857     ancestors[0] = lid;
1858     acount = 1;
1859 ##  repeat retrieve (id = m.list_id)
1860 ##      where m.member_id = @lid and m.member_type = "LIST" {
1861         ancestors[acount++] = id;
1862         if (acount >= MAXLISTDEPTH) {
1863 ##          endretrieve
1864         }
1865 ##  }
1866     if (ingres_errno) return(sms_errcode);
1867     if (acount >= MAXLISTDEPTH) {
1868         return(SMS_INTERNAL);
1869     }
1870     descendants[0] = mid;
1871     dtypes[0] = mtype;
1872     dcount = 1;
1873     error = 0;
1874     if (!strcmp(mtype, "LIST")) {
1875 ##      repeat retrieve (id = m.member_id, dtype = m.member_type)
1876 ##        where m.list_id = @mid {
1877             switch (dtype[0]) {
1878             case 'L':
1879                 dtypes[dcount] = "LIST";
1880                 break;
1881             case 'U':
1882                 dtypes[dcount] = "USER";
1883                 break;
1884             case 'S':
1885                 dtypes[dcount] = "STRING";
1886                 break;
1887             case 'K':
1888                 dtypes[dcount] = "KERBEROS";
1889                 break;
1890             default:
1891                 error++;
1892 ##              endretrieve
1893             }
1894             descendants[dcount++] = id;
1895             if (dcount >= MAXLISTDEPTH) {
1896                 error++;
1897 ##              endretrieve
1898             }
1899 ##      }
1900         if (ingres_errno) return(sms_errcode);
1901         if (error)
1902           return(SMS_INTERNAL);
1903     }
1904     for (a = 0; a < acount; a++) {
1905         lid = ancestors[a];
1906         for (d = 0; d < dcount; d++) {
1907             mid = descendants[d];
1908             mtype = dtypes[d];
1909             if (mid == lid && !strcmp(mtype, "LIST")) {
1910                 return(SMS_LISTLOOP);
1911             }
1912 ##          repeat retrieve (exists = any(m.ref_count where m.list_id = @lid
1913 ##                                       and m.member_id = @mid
1914 ##                                       and m.member_type = @mtype))
1915             if (exists) {
1916                 if (a == 0 && d == 0)
1917 ##                replace m (ref_count = m.ref_count+1, direct = 1)
1918 ##                           where m.list_id = lid and m.member_id = mid and
1919 ##                           m.member_type = mtype
1920                 else
1921 ##                replace m (ref_count = m.ref_count+1)
1922 ##                           where m.list_id = lid and m.member_id = mid and
1923 ##                           m.member_type = mtype
1924             } else {
1925                 incremental_clear_before();
1926                 if (a == 0 && d == 0)
1927 ##                append imembers (list_id=lid, member_id = mid, direct = 1,
1928 ##                                 member_type=mtype, ref_count = 1)
1929                 else
1930 ##                append imembers (list_id=lid, member_id = mid,
1931 ##                                 member_type=mtype, ref_count = 1)
1932                 iargv[0] = (char *)lid;
1933                 iargv[1] = mtype;
1934                 iargv[2] = (char *)mid;
1935                 incremental_after("members", 0, iargv);
1936             }
1937         }
1938     }
1939     if (ingres_errno) return(sms_errcode);
1940     return(SMS_SUCCESS);
1941 ##}
1942
1943
1944 /* Delete_member_from_list: do list flattening as we go!
1945  */
1946
1947 int delete_member_from_list(q, argv, cl)
1948     struct query *q;
1949     char **argv;
1950     client *cl;
1951 ##{
1952 ##  int id, lid, mid, cnt, exists, error;
1953 ##  char *mtype, dtype[9];
1954     int ancestors[MAXLISTDEPTH], acount, a;
1955     int descendants[MAXLISTDEPTH], dcount, d;
1956     char *dtypes[MAXLISTDEPTH];
1957     char *iargv[3];
1958
1959 ##  range of m is imembers
1960     lid = *(int *)argv[0];
1961     mtype = argv[1];
1962     mid = *(int *)argv[2];
1963 ##  repeat retrieve (exists = any(m.list_id where m.list_id=@lid and 
1964 ##                         m.member_id = @mid and m.member_type = @mtype
1965 ##                         and m.direct = 1))
1966     if (ingres_errno) return(sms_errcode);
1967     if (!exists)
1968       return(SMS_NO_MATCH);
1969     ancestors[0] = lid;
1970     acount = 1;
1971 ##  repeat retrieve (id = m.list_id)
1972 ##      where m.member_id = @lid and m.member_type = "LIST" {
1973         ancestors[acount++] = id;
1974         if (acount >= MAXLISTDEPTH)
1975 ##        endretrieve
1976 ##  }
1977           if (ingres_errno) return(sms_errcode);
1978     if (acount >= MAXLISTDEPTH)
1979       return(SMS_INTERNAL);
1980     descendants[0] = mid;
1981     dtypes[0] = mtype;
1982     dcount = 1;
1983     error = 0;
1984     if (!strcmp(mtype, "LIST")) {
1985 ##      repeat retrieve (id = m.member_id, dtype = m.member_type)
1986 ##        where m.list_id = @mid {
1987             switch (dtype[0]) {
1988             case 'L':
1989                 dtypes[dcount] = "LIST";
1990                 break;
1991             case 'U':
1992                 dtypes[dcount] = "USER";
1993                 break;
1994             case 'S':
1995                 dtypes[dcount] = "STRING";
1996                 break;
1997             case 'K':
1998                 dtypes[dcount] = "KERBEROS";
1999                 break;
2000             default:
2001                 error++;
2002 ##              endretrieve
2003             }
2004             descendants[dcount++] = id;
2005             if (dcount >= MAXLISTDEPTH)
2006 ##            endretrieve
2007 ##      }
2008               if (ingres_errno) return(sms_errcode);
2009         if (error)
2010           return(SMS_INTERNAL);
2011     }
2012     for (a = 0; a < acount; a++) {
2013         lid = ancestors[a];
2014         for (d = 0; d < dcount; d++) {
2015             mid = descendants[d];
2016             mtype = dtypes[d];
2017             if (mid == lid && !strcmp(mtype, "LIST")) {
2018                 return(SMS_LISTLOOP);
2019             }
2020 ##          repeat retrieve (cnt = m.ref_count)
2021 ##              where m.list_id = @lid and m.member_id = @mid
2022 ##                and m.member_type = @mtype
2023             if (cnt <= 1) {
2024                 iargv[0] = (char *)lid;
2025                 iargv[1] = mtype;
2026                 iargv[2] = (char *)mid;
2027                 incremental_before("members", 0, iargv);
2028 ##              delete m where m.list_id = lid and m.member_id = mid and
2029 ##                  m.member_type = mtype
2030                 incremental_clear_after();
2031             } else if (a == 0 && d == 0) {
2032 ##              replace m (ref_count = m.ref_count-1, direct = 0)
2033 ##                  where m.list_id = lid and m.member_id = mid and
2034 ##                  m.member_type = mtype
2035             } else {
2036 ##              replace m (ref_count = m.ref_count-1)
2037 ##                  where m.list_id = lid and m.member_id = mid and
2038 ##                  m.member_type = mtype
2039             }
2040         }
2041     }
2042     if (ingres_errno) return(sms_errcode);
2043     return(SMS_SUCCESS);
2044 ##}
2045
2046
2047 /* get_ace_use - given a type and a name, return a type and a name.
2048  * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2049  * and argv[1] will contain the ID of the entity in question.  The R*
2050  * types mean to recursively look at every containing list, not just
2051  * when the object in question is a direct member.  On return, the
2052  * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2053  */
2054
2055 int get_ace_use(q, argv, cl, action, actarg)
2056     struct query *q;
2057     char *argv[];
2058     client *cl;
2059     int (*action)();
2060     int actarg;
2061 ##{
2062     int found = 0;
2063 ##  char *atype;
2064 ##  int aid, listid, id;
2065     struct save_queue *sq, *sq_create();
2066
2067 ##  range of m is imembers
2068     atype = argv[0];
2069     aid = *(int *)argv[1];
2070     if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2071         !strcmp(atype, "KERBEROS")) {
2072         return(get_ace_internal(atype, aid, action, actarg));
2073     }
2074
2075     sq = sq_create();
2076     if (!strcmp(atype, "RLIST")) {
2077         sq_save_data(sq, aid);
2078         /* get all the list_id's of containing lists */
2079 ##      range of m is imembers
2080 ##      repeat retrieve (listid = m.list_id)
2081 ##              where m.member_type = "LIST" and m.member_id = @id {
2082             sq_save_unique_data(sq, listid);
2083 ##      }
2084         /* now process each one */
2085         while (sq_get_data(sq, &id)) {
2086             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
2087               found++;
2088         }
2089     }
2090
2091     if (!strcmp(atype, "RUSER")) {
2092 ##      repeat retrieve (listid = m.list_id)
2093 ##              where m.member_type = "USER" and m.member_id = @aid {
2094             sq_save_data(sq, listid);
2095 ##      }
2096         /* now process each one */
2097         while (sq_get_data(sq, &id)) {
2098             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
2099               found++;
2100         }
2101         if (get_ace_internal("USER", aid, action, actarg) == SMS_SUCCESS)
2102           found++;
2103     }
2104
2105     if (!strcmp(atype, "RKERBERO")) {
2106 ##      repeat retrieve (listid = m.list_id)
2107 ##              where m.member_type = "KERBEROS" and m.member_id = @aid {
2108             sq_save_data(sq, listid);
2109 ##      }
2110         /* now process each one */
2111         while (sq_get_data(sq, &id)) {
2112             if (get_ace_internal("LIST", id, action, actarg) == SMS_SUCCESS)
2113               found++;
2114         }
2115         if (get_ace_internal("KERBEROS", aid, action, actarg) == SMS_SUCCESS)
2116           found++;
2117     }
2118
2119     sq_destroy(sq);     
2120     if (ingres_errno) return(sms_errcode);
2121     if (!found) return(SMS_NO_MATCH);
2122     return(SMS_SUCCESS);
2123 ##}
2124
2125
2126 /* This looks up a single list or user for ace use.  atype must be "USER"
2127  * or "LIST", and aid is the ID of the corresponding object.  This is used
2128  * by get_ace_use above.
2129  */
2130
2131 ##get_ace_internal(atype, aid, action, actarg)
2132 ##  char *atype;
2133 ##  int aid;
2134     int (*action)();
2135     int actarg;
2136 ##{
2137     char *rargv[2];
2138     int found = 0;
2139 ##  char name[33];
2140
2141     rargv[1] = name;
2142     if (!strcmp(atype, "LIST")) {
2143         rargv[0] = "FILESYS";
2144 ##      repeat retrieve (name = filesys.label) 
2145 ##              where filesys.owners = @aid {
2146             (*action)(2, rargv, actarg);
2147             found++;
2148 ##      }
2149
2150         rargv[0] = "QUERY";
2151 ##      repeat retrieve (name = capacls.capability)
2152 ##              where capacls.list_id = @aid {
2153             (*action)(2, rargv, actarg);
2154             found++;
2155 ##      }
2156     } else if (!strcmp(atype, "USER")) {
2157         rargv[0] = "FILESYS";
2158 ##      repeat retrieve (name = filesys.label) 
2159 ##              where filesys.owner = @aid {
2160             (*action)(2, rargv, actarg);
2161             found++;
2162 ##      }
2163     }
2164
2165     rargv[0] = "LIST";
2166 ##  repeat retrieve (name = list.#name) 
2167 ##              where list.acl_type = @atype and list.acl_id = @aid {
2168          (*action)(2, rargv, actarg);
2169          found++;
2170 ##  }
2171
2172     rargv[0] = "SERVICE";
2173 ##  repeat retrieve (name = servers.#name) 
2174 ##              where servers.acl_type = @atype and servers.acl_id = @aid {
2175          (*action)(2, rargv, actarg);
2176          found++;
2177 ##  }
2178
2179     rargv[0] = "HOSTACCESS";
2180 ##  repeat retrieve (name = machine.#name)
2181 ##              where machine.mach_id = hostaccess.mach_id and 
2182 ##                   hostaccess.acl_type = @atype and hostaccess.acl_id = @aid {
2183         (*action)(2, rargv, actarg);
2184         found++;
2185 ##  }
2186     rargv[0] = "ZEPHYR";
2187 ##  repeat retrieve (name = zephyr.class) 
2188 ##              where zephyr.xmt_type = @atype and zephyr.xmt_id = @aid or
2189 ##                    zephyr.sub_type = @atype and zephyr.sub_id = @aid or
2190 ##                    zephyr.iws_type = @atype and zephyr.iws_id = @aid or
2191 ##                    zephyr.iui_type = @atype and zephyr.iui_id = @aid {
2192          (*action)(2, rargv, actarg);
2193          found++;
2194 ##  }
2195
2196     if (!found) return(SMS_NO_MATCH);
2197     return(SMS_SUCCESS);
2198 ##}
2199
2200
2201 /* get_lists_of_member - given a type and a name, return the name and flags
2202  * of all of the lists of the given member.  The member_type is one of
2203  * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2204  * and argv[1] will contain the ID of the entity in question.  The R*
2205  * types mean to recursively look at every containing list, not just
2206  * when the object in question is a direct member.
2207  */
2208
2209 int get_lists_of_member(q, argv, cl, action, actarg)
2210     struct query *q;
2211     char *argv[];
2212     client *cl;
2213     int (*action)();
2214     int actarg;
2215 ##{
2216     int found = 0, direct = 1;
2217     char *rargv[6];
2218 ##  char *atype;
2219 ##  int aid, listid, id;
2220 ##  char name[33], active[5], public[5], hidden[5], maillist[5], group[5];
2221
2222     atype = argv[0];
2223     aid = *(int *)argv[1];
2224     if (!strcmp(atype, "RLIST")) {
2225         atype = "LIST";
2226         direct = 0;
2227     }
2228     if (!strcmp(atype, "RUSER")) {
2229         atype = "USER";
2230         direct = 0;
2231     }
2232     if (!strcmp(atype, "RSTRING")) {
2233         atype = "STRING";
2234         direct = 0;
2235     }
2236     if (!strcmp(atype, "RKERBEROS")) {
2237         atype = "KERBEROS";
2238         direct = 0;
2239     }
2240
2241     rargv[0] = name;
2242     rargv[1] = active;
2243     rargv[2] = public;
2244     rargv[3] = hidden;
2245     rargv[4] = maillist;
2246     rargv[5] = group;
2247     if (direct) {
2248 ##    repeat retrieve (name = list.#name, active = text(list.#active), 
2249 ##                   public = text(list.#public), hidden = text(list.#hidden),
2250 ##                   maillist = text(list.#maillist), group = text(list.#group))
2251 ##              where list.list_id = m.list_id and m.direct = 1 and
2252 ##                    m.member_type = @atype and m.member_id = @aid {
2253          (*action)(6, rargv, actarg);
2254          found++;
2255 ##    }
2256     } else {
2257 ##    repeat retrieve (name = list.#name, active = text(list.#active), 
2258 ##                   public = text(list.#public), hidden = text(list.#hidden),
2259 ##                   maillist = text(list.#maillist), group = text(list.#group))
2260 ##              where list.list_id = m.list_id and
2261 ##                    m.member_type = @atype and m.member_id = @aid {
2262          (*action)(6, rargv, actarg);
2263          found++;
2264 ##    }
2265     }
2266
2267     if (ingres_errno) return(sms_errcode);
2268     if (!found) return(SMS_NO_MATCH);
2269     return(SMS_SUCCESS);
2270 ##}
2271
2272
2273 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2274  * the five flags associated with each list.  It will return the name of
2275  * each list that meets the quailifications.  It does this by building a
2276  * where clause based on the arguments, then doing a retrieve.
2277  */
2278
2279 static char *lflags[5] = { "active", "public", "hidden", "maillist", "group" };
2280
2281 int qualified_get_lists(q, argv, cl, action, actarg)
2282     struct query *q;
2283     char *argv[];
2284     client *cl;
2285     int (*action)();
2286     int actarg;
2287 {
2288     return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2289                          "l", "name", lflags));
2290 }
2291
2292
2293 /** get_members_of_list - optimized query for retrieval of list members
2294  **
2295  ** Inputs:
2296  **   argv[0] - list_id
2297  **
2298  ** Description:
2299  **   - retrieve USER members, then LIST members, then STRING members
2300  **/
2301
2302 get_members_of_list(q, argv, cl, action, actarg)
2303     struct query *q;
2304     char *argv[];
2305     client *cl;
2306     int (*action)();
2307     int actarg;
2308 ##{
2309 ##  int list_id;
2310 ##  char member_name[129];
2311     char *targv[2];
2312
2313     list_id = *(int *)argv[0];
2314     targv[0] = "USER";
2315     targv[1] = member_name;
2316
2317 ##  range of m is imembers
2318 ##  repeat retrieve (member_name = users.login)
2319 ##             where m.#list_id = @list_id and m.member_type = "USER"
2320 ##                   and m.member_id = users.users_id and m.direct = 1
2321 ##             sort by #member_name
2322 ##  {
2323          (*action)(2, targv, actarg);
2324 ##  }
2325     if (ingres_errno) return(sms_errcode);
2326
2327     targv[0] = "LIST";
2328 ##  repeat retrieve (member_name = list.name)
2329 ##             where m.#list_id = @list_id and m.member_type = "LIST"
2330 ##                   and m.member_id = list.#list_id and m.direct = 1
2331 ##             sort by #member_name
2332 ##  {
2333          (*action)(2, targv, actarg);
2334 ##  }
2335     if (ingres_errno) return(sms_errcode);
2336
2337     targv[0] = "STRING";
2338 ##  repeat retrieve (member_name = strings.string)
2339 ##             where m.#list_id = @list_id and m.member_type = "STRING"
2340 ##                   and m.member_id = strings.string_id and m.direct = 1
2341 ##             sort by #member_name
2342 ##  {
2343          (*action)(2, targv, actarg);
2344 ##  }
2345     if (ingres_errno) return(sms_errcode);
2346
2347     targv[0] = "KERBEROS";
2348 ##  repeat retrieve (member_name = strings.string)
2349 ##             where m.#list_id = @list_id and m.member_type = "KERBEROS"
2350 ##                   and m.member_id = strings.string_id and m.direct = 1
2351 ##             sort by #member_name
2352 ##  {
2353          (*action)(2, targv, actarg);
2354 ##  }
2355     if (ingres_errno) return(sms_errcode);
2356
2357     return(SMS_SUCCESS);
2358 ##}
2359
2360
2361 /* count_members_of_list: this is a simple query, but it cannot be done
2362  * through the dispatch table.
2363  */
2364
2365 int count_members_of_list(q, argv, cl, action, actarg)
2366     struct query *q;
2367     char *argv[];
2368     client *cl;
2369     int (*action)();
2370     int actarg;
2371 ##{
2372 ##  int  list, ct = 0;
2373     char *rargv[1], countbuf[5];
2374
2375     list = *(int *)argv[0];
2376     rargv[0] = countbuf;
2377 ##  repeat retrieve (ct = count(imembers.list_id
2378 ##                              where imembers.list_id = @list and
2379 ##                                    imembers.direct = 1))
2380     if (ingres_errno) return(sms_errcode);
2381     sprintf(countbuf, "%d", ct);
2382     (*action)(1, rargv, actarg);
2383     return(SMS_SUCCESS);
2384 ##}
2385
2386
2387 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2388  * the three flags associated with each service.  It will return the name of
2389  * each service that meets the quailifications.  It does this by building a
2390  * where clause based on the arguments, then doing a retrieve.
2391  */
2392
2393 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2394
2395 int qualified_get_server(q, argv, cl, action, actarg)
2396     struct query *q;
2397     char *argv[];
2398     client *cl;
2399     int (*action)();
2400     int actarg;
2401 {
2402     return(qualified_get(q, argv, action, actarg, "s.name != \"\"",
2403                          "s", "name", sflags));
2404 }
2405
2406
2407 /* generic qualified get routine, used by qualified_get_lists,
2408  * qualified_get_server, and qualified_get_serverhost.
2409  *   Args:
2410  *      start - a simple where clause, must not be empty
2411  *      range - the name of the range variable
2412  *      field - the field to return
2413  *      flags - an array of strings, names of the flag variables
2414  */
2415
2416 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2417     struct query *q;
2418     char *argv[];
2419     int (*action)();
2420     int actarg;
2421     char *start;
2422     char *range;
2423     char *field;
2424     char *flags[];
2425 ##{
2426 ##  char name[33], qual[256], *rvar, *rtbl, *rfield;
2427     char *rargv[1], buf[32];
2428 ##  int rowcount, i;
2429
2430     strcpy(qual, start);
2431     for (i = 0; i < q->argc; i++) {
2432         if (!strcmp(argv[i], "TRUE")) {
2433             sprintf(buf, " and %s.%s != 0", range, flags[i]);
2434             (void) strcat(qual, buf);
2435         } else if (!strcmp(argv[i], "FALSE")) {
2436             sprintf(buf, " and %s.%s = 0", range, flags[i]);
2437             (void) strcat(qual, buf);
2438         }
2439     }
2440       
2441     rargv[0] = name;
2442     rvar = range;
2443     rtbl = q->rtable;
2444     rfield = field;
2445 ##  range of rvar is rtbl
2446 ##  retrieve (name = rvar.rfield) where qual {
2447         (*action)(1, rargv, actarg);
2448 ##  }
2449     if (ingres_errno) return(sms_errcode);
2450 ##  inquire_equel(rowcount = "rowcount")
2451 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2452 ##      where tblstats.#table = @rtbl
2453     if (rowcount == 0)
2454       return(SMS_NO_MATCH);
2455     return(SMS_SUCCESS);
2456 ##}
2457
2458
2459 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2460  * the five flags associated with each serverhost.  It will return the name of
2461  * each service and host that meets the quailifications.  It does this by 
2462  * building a where clause based on the arguments, then doing a retrieve.
2463  */
2464
2465 static char *shflags[6] = { "service", "enable", "override", "success",
2466                             "inprogress", "hosterror" };
2467
2468 int qualified_get_serverhost(q, argv, cl, action, actarg)
2469     struct query *q;
2470     char *argv[];
2471     client *cl;
2472     int (*action)();
2473     int actarg;
2474 ##{
2475 ##  char sname[33], mname[33], qual[256];
2476     char *rargv[2], buf[32];
2477 ##  int rowcount, i;
2478
2479     sprintf(qual, "machine.mach_id = sh.mach_id and sh.service = uppercase(\"%s\")",
2480             argv[0]);
2481     for (i = 1; i < q->argc; i++) {
2482         if (!strcmp(argv[i], "TRUE")) {
2483             sprintf(buf, " and sh.%s != 0", shflags[i]);
2484             strcat(qual, buf);
2485         } else if (!strcmp(argv[i], "FALSE")) {
2486             sprintf(buf, " and sh.%s = 0", shflags[i]);
2487             strcat(qual, buf);
2488         }
2489     }
2490       
2491     rargv[0] = sname;
2492     rargv[1] = mname;
2493 ##  range of sh is serverhosts
2494 ##  retrieve (sname = sh.service, mname = machine.name) where qual {
2495         (*action)(2, rargv, actarg);
2496 ##  }
2497     if (ingres_errno) return(sms_errcode);
2498 ##  inquire_equel(rowcount = "rowcount")
2499 ##  repeat replace tblstats (retrieves = tblstats.retrieves + 1)
2500 ##      where tblstats.#table = "serverhosts"
2501     if (rowcount == 0)
2502       return(SMS_NO_MATCH);
2503     return(SMS_SUCCESS);
2504 ##}
2505
2506
2507 /* register_user - change user's login name and allocate a pobox, group,
2508  * filesystem, and quota for them.  The user's status must start out as 0,
2509  * and is left as 2.  Arguments are: user's UID, new login name, and user's
2510  * type for filesystem allocation (SMS_FS_STUDENT, SMS_FS_FACULTY, 
2511  * SMS_FS_STAFF, SMS_FS_MISC).
2512  */
2513
2514 register_user(q, argv, cl)
2515     struct query *q;
2516     char **argv;
2517     client *cl;
2518 ##{
2519 ##  char *login, dir[65], *entity, *directory, machname[33];
2520 ##  int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
2521 ##  int size, alloc, pid, m_id;
2522     char buffer[256], *aargv[3];
2523     int maxsize;
2524
2525     entity = cl->entity;
2526     who = cl->client_id;
2527
2528     uid = atoi(argv[0]);
2529     login = argv[1];
2530     utype = atoi(argv[2]);
2531
2532 ##  range of u is users
2533 ##  range of l is list
2534 ##  range of sh is serverhosts
2535 ##  range of n is nfsphys
2536 ##  range of m is machine
2537
2538     /* find user */
2539 ##  repeat retrieve (users_id = u.#users_id)
2540 ##      where u.#uid = @uid and (u.status = 0 or u.status = 5)
2541 ##  inquire_equel(rowcount = "rowcount");
2542     if (rowcount == 0)
2543       return(SMS_NO_MATCH);
2544     if (rowcount > 1)
2545       return(SMS_NOT_UNIQUE);
2546
2547     /* check new login name */
2548 ##  repeat retrieve (flag = any(u.#login where u.#login = @login and
2549 ##                              u.#users_id != users_id))
2550     if (ingres_errno) return(sms_errcode);
2551     if (flag) return(SMS_IN_USE);
2552 ##  repeat retrieve (flag = any(l.#name where l.#name = @login))
2553     if (ingres_errno) return(sms_errcode);
2554     if (flag) return(SMS_IN_USE);
2555 ##  repeat retrieve (flag = any(filesys.#label where filesys.#label = @login))
2556     if (ingres_errno) return(sms_errcode);
2557     if (flag) return(SMS_IN_USE);
2558     com_err(whoami, 0, "new login name OK");
2559
2560     /* choose place for pobox, put in mid */
2561 ##  repeat retrieve (mid = sh.mach_id, machname = m.name)
2562 ##    where sh.service = "POP" and m.mach_id = sh.mach_id and
2563 ##      sh.value2 - sh.value1 = max(sh.value2-sh.value1 where sh.service="POP")
2564     if (ingres_errno) return(sms_errcode);
2565 ##  inquire_equel(rowcount = "rowcount");
2566     if (rowcount == 0)
2567       return(SMS_NO_POBOX);
2568
2569     /* change login name, set pobox */
2570     sprintf(buffer, "u.users_id = %d", users_id);
2571     incremental_before("users", buffer, 0);
2572 ##  repeat replace u (#login = @login, status = 2, modtime = "now",
2573 ##                    modby = @who, modwith = @entity, potype="POP",
2574 ##                    pop_id = @mid, pmodtime="now", pmodby=@who,
2575 ##                    pmodwith=@entity)
2576 ##      where u.#users_id = @users_id
2577 ##  inquire_equel(rowcount = "rowcount");
2578     if (ingres_errno) return(sms_errcode);
2579     if (rowcount != 1)
2580       return(SMS_INTERNAL);
2581     set_pop_usage(mid, 1);
2582     com_err(whoami, 0, "set login name to %s and pobox to %s", login,
2583             strtrim(machname));
2584     incremental_after("users", buffer, 0);
2585
2586     /* create group list */
2587     if (set_next_object_id("gid", "list"))
2588       return(SMS_NO_ID);
2589     if (set_next_object_id("list_id", "list"))
2590       return(SMS_NO_ID);
2591 ##  repeat retrieve (list_id = values.value) where values.name = "list_id"
2592     if (ingres_errno) return(sms_errcode);
2593 ##  inquire_equel(rowcount = "rowcount");
2594     if (rowcount != 1)
2595       return(SMS_INTERNAL);
2596     incremental_clear_before();
2597 ##  repeat append list (name = @login, #list_id = @list_id, active = 1,
2598 ##                      public = 0, hidden = 0, maillist = 0, group = 1,
2599 ##                      #gid = values.value, desc = "User Group",
2600 ##                      acl_type = "USER", acl_id = @users_id, modtime = "now",
2601 ##                      modby = @who, modwith = @entity)
2602 ##      where values.name = "gid"
2603     if (ingres_errno) return(sms_errcode);
2604 ##  inquire_equel(rowcount = "rowcount");
2605     if (rowcount != 1)
2606       return(SMS_INTERNAL);
2607     sprintf(buffer, "l.list_id = %d", list_id);
2608     incremental_after("list", buffer, 0);
2609     aargv[0] = (char *) list_id;
2610     aargv[1] = "USER";
2611     aargv[2] = (char *) users_id;
2612     incremental_clear_before();
2613 ##  repeat append imembers (#list_id = @list_id, member_type = "USER",
2614 ##                         member_id = @users_id, ref_count = 1, direct = 1)
2615     if (ingres_errno) return(sms_errcode);
2616 ##  inquire_equel(rowcount = "rowcount");
2617     if (rowcount != 1)
2618       return(SMS_INTERNAL);
2619     incremental_after("members", 0, aargv);
2620     com_err(whoami, 0, "group list created");
2621
2622     /* decide where to put filesystem */
2623     maxsize = 0;
2624     directory = NULL;
2625 ##  repeat retrieve (mid = n.mach_id, dir = trim(n.#dir), nid = n.nfsphys_id,
2626 ##                   flag = n.status, size = n.#size, alloc = n.allocated) {
2627         if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
2628             maxsize = size - alloc;
2629             if (directory)
2630               free(directory);
2631             directory = strsave(dir);
2632             pid = nid;
2633             m_id = mid;
2634         }
2635 ##  }
2636     if (ingres_errno) return(sms_errcode);
2637     if (maxsize == 0)
2638       return(SMS_NO_FILESYS);
2639
2640     /* create filesystem */
2641     if (set_next_object_id("filsys_id", "filesys"))
2642       return(SMS_NO_ID);
2643     incremental_clear_before(); 
2644 ##  repeat append filesys (filsys_id = values.value, phys_id = @pid,
2645 ##                         label = @login, type = "NFS", mach_id = @m_id,
2646 ##                         name = @directory + "/" + @login,
2647 ##                         mount = "/mit/" + @login,
2648 ##                         access = "w", comments = "User Locker",
2649 ##                         owner = @users_id, owners = @list_id, createflg = 1,
2650 ##                         lockertype = "HOMEDIR", modtime = "now",
2651 ##                         modby = @who, modwith = @entity)
2652 ##      where values.name = "filsys_id"
2653     if (ingres_errno) return(sms_errcode);
2654 ##  inquire_equel(rowcount = "rowcount");
2655     if (rowcount != 1)
2656       return(SMS_INTERNAL);
2657     incremental_after("filesys", 
2658           "fs.filsys_id = values.value and values.name = \"filsys_id\"",
2659                       0);
2660     com_err(whoami, 0, "filesys created on mach %d in %s/%s", m_id,
2661             directory, login);
2662
2663     /* set quota */
2664 ##  repeat retrieve (quota = values.value) where values.name = "def_quota"
2665     if (ingres_errno) return(sms_errcode);
2666 ##  inquire_equel(rowcount = "rowcount");
2667     if (rowcount != 1)
2668       return(SMS_NO_QUOTA);
2669     incremental_clear_before();
2670 ##  repeat append nfsquota (#users_id = @users_id, filsys_id = values.value,
2671 ##                          #quota = @quota, phys_id = @pid, modtime = "now",
2672 ##                          modby = @who, modwith = @entity)
2673 ##      where values.name = "filsys_id"
2674     if (ingres_errno) return(sms_errcode);
2675 ##  inquire_equel(rowcount = "rowcount");
2676     if (rowcount != 1)
2677       return(SMS_INTERNAL);
2678 ##  repeat replace nfsphys (allocated = nfsphys.allocated + @quota)
2679 ##      where nfsphys.nfsphys_id = filesys.#phys_id and
2680 ##            filesys.filsys_id = values.value and values.name = "filsys_id"
2681     if (ingres_errno) return(sms_errcode);
2682 ##  inquire_equel(rowcount = "rowcount");
2683     if (rowcount != 1)
2684       return(SMS_INTERNAL);
2685     aargv[0] = login;
2686     aargv[1] = login;
2687     sprintf(buffer, "nq.users_id = %d and nq.filsys_id = values.value and values.name = \"filsys_id\"", users_id);
2688     incremental_after("nfsquota", buffer, aargv);
2689     com_err(whoami, 0, "quota of %d assigned", quota);
2690     if (ingres_errno) return(sms_errcode);
2691
2692 ##  repeat replace tblstats (updates = tblstats.updates + 1, modtime = "now")
2693 ##      where tblstats.table = "users"
2694 ##  repeat replace tblstats (appends = tblstats.appends + 1, modtime = "now")
2695 ##      where tblstats.table = "list" or tblstats.table = "filesys" or
2696 ##            tblstats.table = "nfsquota"
2697     if (ingres_errno) return(sms_errcode);
2698     return(SMS_SUCCESS);
2699 ##}
2700
2701
2702
2703 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
2704  **
2705  ** Inputs:
2706  **   id of machine
2707  **   delta (will be +/- 1)
2708  **
2709  ** Description:
2710  **   - incr/decr value field in serverhosts table for pop/mach_id
2711  **
2712  **/
2713
2714 static int set_pop_usage(id, count)
2715 int id;
2716 int count;
2717 ##{
2718 ##  int mach_id = id;
2719 ##  int n = count;
2720
2721 ##  range of sh is serverhosts
2722 ##  repeat replace sh (value1 = sh.value1 + @n)
2723 ##         where sh.service = "POP" and sh.#mach_id = @mach_id
2724
2725     if (ingres_errno) return(sms_errcode);
2726     return(SMS_SUCCESS);
2727 ##}
2728
2729
2730 \f
2731 /* Validation Routines */
2732
2733 validate_row(q, argv, v)
2734     register struct query *q;
2735     char *argv[];
2736     register struct validate *v;
2737 ##{
2738 ##  char *rvar;
2739 ##  char *table;
2740 ##  char *name;
2741 ##  char qual[128];
2742 ##  int rowcount;
2743
2744     /* build where clause */
2745     build_qual(v->qual, v->argc, argv, qual);
2746
2747     /* setup ingres variables */
2748     rvar = q->rvar;
2749     table = q->rtable;
2750     name = v->field;
2751
2752     if (log_flags & LOG_VALID)
2753         /* tell the logfile what we're doing */
2754         com_err(whoami, 0, "validating row: %s", qual);
2755     
2756     /* look for the record */
2757 ##  range of rvar is table
2758 ##  retrieve (rowcount = count(rvar.name where qual))
2759     if (ingres_errno) return(sms_errcode);
2760     if (rowcount == 0) return(SMS_NO_MATCH);
2761     if (rowcount > 1) return(SMS_NOT_UNIQUE);
2762     return(SMS_EXISTS);
2763 ##}
2764
2765 validate_fields(q, argv, vo, n)
2766     struct query *q;
2767     register char *argv[];
2768     register struct valobj *vo;
2769     register int n;
2770 {
2771     register int status;
2772
2773     while (--n >= 0) {
2774         switch (vo->type) {
2775         case V_NAME:
2776             if (log_flags & LOG_VALID)
2777                 com_err(whoami, 0, "validating %s in %s: %s", 
2778                     vo->namefield, vo->table, argv[vo->index]);
2779             status = validate_name(argv, vo);
2780             break;
2781
2782         case V_ID:
2783             if (log_flags & LOG_VALID)
2784                 com_err(whoami, 0, "validating %s in %s: %s", 
2785                     vo->idfield, vo->table, argv[vo->index]);
2786             status = validate_id(argv, vo);
2787             break;
2788
2789         case V_DATE:
2790             if (log_flags & LOG_VALID)
2791                 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
2792             status = validate_date(argv, vo);
2793             break;
2794
2795         case V_TYPE:
2796             if (log_flags & LOG_VALID)
2797                 com_err(whoami, 0, "validating %s type: %s",
2798                     vo->table, argv[vo->index]);
2799             status = validate_type(argv, vo);
2800             break;
2801
2802         case V_TYPEDATA:
2803             if (log_flags & LOG_VALID)
2804                 com_err(whoami, 0, "validating typed data (%s): %s",
2805                     argv[vo->index - 1], argv[vo->index]);
2806             status = validate_typedata(q, argv, vo);
2807             break;
2808
2809         case V_RENAME:
2810             if (log_flags & LOG_VALID)
2811                 com_err(whoami, 0, "validating rename %s in %s",
2812                         argv[vo->index], vo->table);
2813             status = validate_rename(argv, vo);
2814             break;
2815
2816         case V_CHAR:
2817             if (log_flags & LOG_VALID)
2818               com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
2819             status = validate_chars(argv[vo->index]);
2820             break;
2821
2822         case V_SORT:
2823             status = SMS_EXISTS;
2824             break;
2825
2826         case V_LOCK:
2827             status = lock_table(vo);
2828             break;
2829         }
2830
2831         if (status != SMS_EXISTS) return(status);
2832         vo++;
2833     }
2834
2835     if (ingres_errno) return(sms_errcode);
2836     return(SMS_SUCCESS);
2837 }
2838
2839
2840 /* validate_chars: verify that there are no illegal characters in
2841  * the string.  Legal characters are printing chars other than 
2842  * ", *, ?, \, [ and ].
2843  */
2844 static int illegalchars[] = {
2845     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
2846     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
2847     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
2848     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
2849     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* @ - O */
2850     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
2851     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
2852     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
2853     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2854     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2855     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2856     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2857     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2858     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2859     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2860     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2861 };
2862
2863 validate_chars(s)
2864 register char *s;
2865 {
2866     while (*s)
2867       if (illegalchars[*s++])
2868         return(SMS_BAD_CHAR);
2869     return(SMS_EXISTS);
2870 }
2871
2872
2873 validate_id(argv, vo)
2874     char *argv[];
2875     register struct valobj *vo;
2876 ##{
2877 ##  char *name;
2878 ##  char *table;
2879 ##  char *namefield;
2880 ##  char *idfield;
2881 ##  int id;
2882 ##  int rowcount;
2883     register char *c;
2884
2885     name = argv[vo->index];
2886     table = vo->table;
2887     /* minor kludge to upcasify machine names */
2888     if (!strcmp(table, "machine"))
2889         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2890     namefield = vo->namefield;
2891     idfield = vo->idfield;
2892     if (!strcmp(namefield, "uid")) {
2893 ##    retrieve (id = table.idfield) where table.namefield = int4(name)
2894       if (ingres_errno) return(sms_errcode);
2895 ##    inquire_equel (rowcount = "rowcount")
2896     } else {
2897 ##    retrieve (id = table.idfield) where table.namefield = name
2898       if (ingres_errno) return(sms_errcode);
2899 ##    inquire_equel (rowcount = "rowcount")
2900     }
2901     if (rowcount != 1) return(vo->error);
2902     *(int *)argv[vo->index] = id;
2903     return(SMS_EXISTS);
2904 ##}
2905
2906 validate_name(argv, vo)
2907     char *argv[];
2908     register struct valobj *vo;
2909 ##{
2910 ##  char *name;
2911 ##  char *table;
2912 ##  char *namefield;
2913 ##  int rowcount;
2914     register char *c;
2915
2916     name = argv[vo->index];
2917     table = vo->table;
2918     namefield = vo->namefield;
2919     if (!strcmp(table, "servers") && !strcmp(namefield, "name")) {
2920         for (c = name; *c; c++)
2921           if (islower(*c))
2922             *c = toupper(*c);
2923     }
2924 ##  retrieve (rowcount = countu(table.namefield 
2925 ##            where table.namefield = name))
2926     if (ingres_errno) return(sms_errcode);
2927     return ((rowcount == 1) ? SMS_EXISTS : vo->error);
2928 ##}
2929
2930 validate_date(argv, vo)
2931     char *argv[];
2932     struct valobj *vo;
2933 ##{
2934 ##  char *idate;
2935 ##  double dd;
2936 ##  int errorno;
2937
2938     idate = argv[vo->index];
2939
2940 ##  retrieve (dd = interval("years", date(idate) - date("today")))
2941 ##  inquire_equel (errorno = "errorno")
2942     if (errorno != 0 || dd > 5.0) return(SMS_DATE);
2943     return(SMS_EXISTS);
2944 ##}
2945
2946
2947 validate_rename(argv, vo)
2948 char *argv[];
2949 struct valobj *vo;
2950 ##{
2951 ##  char *name, *table, *namefield, *idfield;
2952 ##  int id;
2953     register char *c;
2954
2955     c = name = argv[vo->index];
2956     while (*c)
2957       if (illegalchars[*c++])
2958         return(SMS_BAD_CHAR);
2959     table = vo->table;
2960     /* minor kludge to upcasify machine names */
2961     if (!strcmp(table, "machine"))
2962         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
2963     namefield = vo->namefield;
2964     idfield = vo->idfield;
2965     id = -1;
2966     if (idfield == 0) {
2967         if (!strcmp(argv[vo->index], argv[vo->index - 1]))
2968           return(SMS_EXISTS);
2969 ##      retrieve (id = any(table.namefield where table.namefield = name))
2970         if (ingres_errno) return(sms_errcode);
2971         if (id)
2972           return(vo->error);
2973         else
2974           return(SMS_EXISTS);
2975     }
2976 ##  retrieve (id = table.idfield) where table.namefield = name
2977     if (ingres_errno) return(sms_errcode);
2978     if (id == -1 || id == *(int *)argv[vo->index - 1])
2979       return(SMS_EXISTS);
2980     else
2981       return(vo->error);
2982 ##}
2983
2984
2985 validate_type(argv, vo)
2986     char *argv[];
2987     register struct valobj *vo;
2988 ##{
2989 ##  char *typename;
2990 ##  char *value;
2991 ##  int exists;
2992     register char *c;
2993
2994     typename = vo->table;
2995     c = value = argv[vo->index];
2996     while (*c)
2997       if (illegalchars[*c++])
2998         return(SMS_BAD_CHAR);
2999
3000     /* uppercase type fields */
3001     for (c = value; *c; c++) if (islower(*c)) *c = toupper(*c);
3002
3003 ##  range of a is alias
3004 ##  repeat retrieve (exists = any(a.trans where a.name = @typename and
3005 ##                                    a.type = "TYPE" and
3006 ##                                    a.trans = @value))
3007     if (ingres_errno) return(sms_errcode);
3008     return (exists ? SMS_EXISTS : vo->error);
3009 ##}
3010
3011 /* validate member or type-specific data field */
3012
3013 validate_typedata(q, argv, vo)
3014     register struct query *q;
3015     register char *argv[];
3016     register struct valobj *vo;
3017 ##{
3018 ##  char *name;
3019 ##  char *field_type;
3020 ##  char data_type[129];
3021 ##  int id;
3022 ##  int rowcount;
3023     char *index();
3024     register char *c;
3025
3026     /* get named object */
3027     name = argv[vo->index];
3028
3029     /* get field type string (known to be at index-1) */
3030     field_type = argv[vo->index-1];
3031
3032     /* get corresponding data type associated with field type name */
3033 ##  repeat retrieve (data_type = alias.trans) 
3034 ##         where alias.#name = @field_type and alias.type = "TYPEDATA"
3035     if (ingres_errno) return(sms_errcode);
3036 ##  inquire_equel (rowcount = "rowcount")
3037     if (rowcount != 1) return(SMS_TYPE);
3038
3039     /* now retrieve the record id corresponding to the named object */
3040     if (index(data_type, ' '))
3041         *index(data_type, ' ') = 0;
3042     if (!strcmp(data_type, "user")) {
3043         /* USER */
3044 ##      repeat retrieve (id = users.users_id) where users.login = @name
3045 ##      inquire_equel (rowcount = "rowcount")
3046         if (rowcount != 1) return(SMS_USER);
3047
3048     } else if (!strcmp(data_type, "list")) {
3049         /* LIST */
3050 ##      repeat retrieve (id = list.list_id) where list.#name = @name
3051 ##      inquire_equel (rowcount = "rowcount")
3052         if (rowcount != 1) {
3053             /* if idfield is non-zero, then if argv[0] matches the string
3054              * that we're trying to resolve, we should get the value of
3055              * values.[idfield] for the id.
3056              */
3057             if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3058                 set_next_object_id(q->validate->object_id, q->rtable);
3059                 name = vo->idfield;
3060 ##              repeat retrieve (id = values.value) where values.#name = @name
3061 ##              inquire_equel(rowcount = "rowcount")
3062                 if (rowcount != 1) return(SMS_LIST);
3063             } else
3064               return(SMS_LIST);
3065         }
3066     } else if (!strcmp(data_type, "machine")) {
3067         /* MACHINE */
3068         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3069 ##      repeat retrieve (id = machine.mach_id) where machine.#name = @name
3070 ##      inquire_equel (rowcount = "rowcount")
3071         if (rowcount != 1) return(SMS_MACHINE);
3072
3073     } else if (!strcmp(data_type, "string")) {
3074         /* STRING */
3075 ##      range of s is strings
3076 ##      repeat retrieve (id = s.string_id) where s.string = @name
3077 ##      inquire_equel (rowcount = "rowcount")
3078         if (rowcount == 0) {
3079             if (q->type != APPEND) return(SMS_STRING);
3080 ##          range of v is values
3081 ##          retrieve (id = v.value) where v.#name = "strings_id"
3082             id++;
3083 ##          replace v (value = id) where v.#name = "strings_id"
3084 ##          append to strings (string_id = id, string = name)
3085         }
3086     } else if (!strcmp(data_type, "none")) {
3087         id = 0;
3088     } else {
3089         return(SMS_TYPE);
3090     }
3091
3092     /* now set value in argv */
3093     *(int *)argv[vo->index] = id;
3094     
3095     return (SMS_EXISTS);
3096 ##}
3097
3098
3099 /* Lock the table named by the validation object */
3100
3101 lock_table(vo)
3102 struct valobj *vo;
3103 ##{
3104 ##  char *table, *idfield;
3105 ##  int rowcount;
3106
3107     table = vo->table;
3108     idfield = vo->idfield;
3109 ##  replace table (modtime = "now") where table.idfield = 0
3110     if (ingres_errno) return(sms_errcode);
3111 ##  inquire_equel (rowcount = "rowcount")
3112     if (rowcount != 1)
3113       return(vo->error);
3114     else
3115       return(SMS_EXISTS);
3116 ##}
3117
3118
3119 /* Check the database at startup time.  For now this just resets the
3120  * inprogress flags that the DCM uses.
3121  */
3122
3123 sanity_check_database()
3124 ##{
3125 ##}
This page took 0.43266 seconds and 3 git commands to generate.