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