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