]> andersk Git - moira.git/blob - server/qsupport.dc
typo; commit lookup in incremental
[moira.git] / server / qsupport.dc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987 by the Massachusetts Institute of Technology
7  *      For copying and distribution information, please see the file
8  *      <mit-copyright.h>.
9  *
10  */
11
12 #ifndef lint
13 static char *rcsid_qsupport_dc = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include "query.h"
18 #include "mr_server.h"
19 #include <ctype.h>
20 #ifdef GDSS
21 #include "gdss.h"
22 #endif /* GDSS */
23 EXEC SQL INCLUDE sqlca;
24 EXEC SQL INCLUDE sqlda;
25 #include "qrtn.h"
26
27 extern char *whoami, *strsave();
28 extern int ingres_errno, mr_errcode;
29
30 EXEC SQL BEGIN DECLARE SECTION;
31 extern char stmt_buf[];
32 int idummy;
33 extern char cdummy[];           
34 EXEC SQL END DECLARE SECTION;
35
36 /* Specialized Access Routines */
37
38 /* access_user - verify that client name equals specified login name
39  *
40  *  - since field validation routines are called first, a users_id is
41  *    now in argv[0] instead of the login name.
42  */
43
44 EXEC SQL WHENEVER SQLERROR CALL ingerr;
45
46 access_user(q, argv, cl)
47     struct query *q;
48     char *argv[];
49     client *cl;
50 {
51     if (cl->users_id != *(int *)argv[0])
52         return(MR_PERM);
53     else
54         return(MR_SUCCESS);
55 }
56
57
58
59 /* access_login - verify that client name equals specified login name
60  *
61  *   argv[0...n] contain search info.  q->
62  */
63
64 access_login(q, argv, cl)
65     struct query *q;
66     char *argv[];
67     client *cl;
68 {
69     EXEC SQL BEGIN DECLARE SECTION;
70     int id;
71     char qual[256];
72     EXEC SQL END DECLARE SECTION;
73
74     build_qual(q->qual, q->argc, argv, qual);
75     if (!strncmp(q->name,"get_user_account",strlen("get_user_account"))) {
76         EXEC SQL SELECT users_id INTO :id FROM users u, strings str WHERE :qual;
77     } else {
78         EXEC SQL SELECT users_id INTO :id FROM users u WHERE :qual;
79     }
80
81     if (sqlca.sqlerrd[2] != 1 || id != cl->users_id)
82         return(MR_PERM);
83     else
84         return(MR_SUCCESS);
85 }
86
87
88
89 /* access_list - check access for most list operations
90  *
91  * Inputs: argv[0] - list_id
92  *          q - query name
93  *          argv[2] - member ID (only for queries "amtl" and  "dmfl")
94  *          argv[7] - group IID (only for query "ulis")
95  *          cl - client name
96  *
97  * - check that client is a member of the access control list
98  * - OR, if the query is add_member_to_list or delete_member_from_list
99  *      and the list is public, allow access if client = member
100  */
101
102 access_list(q, argv, cl)
103     struct query *q;
104     char *argv[];
105     client *cl;
106 {
107     EXEC SQL BEGIN DECLARE SECTION;
108     int list_id, acl_id, flags, gid;
109     char acl_type[9];
110     EXEC SQL END DECLARE SECTION;
111     char *client_type;
112     int client_id, status;
113
114     list_id = *(int *)argv[0];
115     EXEC SQL SELECT acl_id, acl_type, gid, publicflg
116       INTO :acl_id, :acl_type, :gid, :flags
117       FROM list
118       WHERE list_id = :list_id;
119
120     if (sqlca.sqlerrd[2] != 1)
121       return(MR_INTERNAL);
122
123     /* parse client structure */
124     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
125         return(status);
126
127     /* if amtl or dmfl and list is public allow client to add or delete self */
128     if (((!strcmp("amtl", q->shortname) && flags) ||
129          (!strcmp("dmfl", q->shortname))) &&
130         (!strcmp("USER", argv[1]))) {
131         if (*(int *)argv[2] == client_id) return(MR_SUCCESS);
132     /* if update_list, don't allow them to change the GID */
133     } else if (!strcmp("ulis", q->shortname)) {
134         if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
135             (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
136           return(MR_PERM);
137     }
138
139     /* check for client in access control list */
140     status = find_member(acl_type, acl_id, client_type, client_id, 0);
141     if (!status) return(MR_PERM);
142
143     return(MR_SUCCESS);
144 }
145
146
147 /* access_visible_list - allow access to list only if it is not hidden,
148  *      or if the client is on the ACL
149  *
150  * Inputs: argv[0] - list_id
151  *         cl - client identifier
152  */
153
154 access_visible_list(q, argv, cl)
155     struct query *q;
156     char *argv[];
157     client *cl;
158 {
159     EXEC SQL BEGIN DECLARE SECTION;
160     int list_id, acl_id, flags ;
161     char acl_type[9];
162     EXEC SQL END DECLARE SECTION;
163     char *client_type;
164     int client_id, status;
165
166     list_id = *(int *)argv[0];
167     EXEC SQL SELECT hidden, acl_id, acl_type
168       INTO :flags, :acl_id, :acl_type
169       FROM list
170       WHERE list_id = :list_id;
171     if (sqlca.sqlerrd[2] != 1)
172       return(MR_INTERNAL);
173     if (!flags)
174         return(MR_SUCCESS);
175
176     /* parse client structure */
177     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
178         return(status);
179
180     /* check for client in access control list */
181     status = find_member(acl_type, acl_id, client_type, client_id, 0);
182     if (!status)
183         return(MR_PERM);
184
185     return(MR_SUCCESS);
186 }
187
188
189 /* access_vis_list_by_name - allow access to list only if it is not hidden,
190  *      or if the client is on the ACL
191  *
192  * Inputs: argv[0] - list name
193  *         cl - client identifier
194  */
195
196 access_vis_list_by_name(q, argv, cl)
197     struct query *q;
198     char *argv[];
199     client *cl;
200 {
201     EXEC SQL BEGIN DECLARE SECTION;
202     int acl_id, flags, rowcount;
203     char acl_type[9], *listname;
204     EXEC SQL END DECLARE SECTION;
205     char *client_type;
206     int client_id, status;
207
208     listname = argv[0];
209     EXEC SQL SELECT hidden, acl_id, acl_type INTO :flags, :acl_id, :acl_type
210       FROM list WHERE name = :listname;
211
212     rowcount=sqlca.sqlerrd[2];
213     if (rowcount > 1)
214       return(MR_WILDCARD);
215     if (rowcount == 0)
216       return(MR_NO_MATCH);
217     if (!flags)
218         return(MR_SUCCESS);
219
220     /* parse client structure */
221     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
222         return(status);
223
224     /* check for client in access control list */
225     status = find_member(acl_type, acl_id, client_type, client_id, 0);
226     if (!status)
227         return(MR_PERM);
228
229     return(MR_SUCCESS);
230 }
231
232
233 /* access_member - allow user to access member of type "USER" and name matches
234  * username, or to access member of type "LIST" and list is one that user is
235  * on the acl of, or the list is visible.
236  */
237
238 access_member(q, argv, cl)
239     struct query *q;
240     char *argv[];
241     client *cl;
242 {
243     if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
244       return(access_visible_list(q, &argv[1], cl));
245
246     if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
247         if (cl->users_id == *(int *)argv[1])
248           return(MR_SUCCESS);
249     }
250
251     if (!strcmp(argv[0], "KERBEROS") || !strcmp(argv[0], "RKERBERO")) {
252         if (cl->client_id == *(int *)argv[1])
253           return(MR_SUCCESS);
254     }
255
256     return(MR_PERM);
257 }
258
259
260 /* access_qgli - special access routine for Qualified_get_lists.  Allows
261  * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
262  */
263
264 access_qgli(q, argv, cl)
265     struct query *q;
266     char *argv[];
267     client *cl;
268 {
269     if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
270       return(MR_SUCCESS);
271     return(MR_PERM);
272 }
273
274
275 /* access_service - allow access if user is on ACL of service.  Don't
276  * allow access if a wildcard is used.
277  */
278
279 access_service(q, argv, cl)
280     struct query *q;
281     char *argv[];
282     client *cl;
283 {
284     EXEC SQL BEGIN DECLARE SECTION;
285     int acl_id;
286     char *name, acl_type[9];
287     EXEC SQL END DECLARE SECTION;
288     int client_id, status;
289     char *client_type, *c;
290
291     name = argv[0];
292     for(c=name;*c;c++) if(islower(*c)) *c = toupper(*c);  /* uppercasify */
293     EXEC SQL SELECT acl_id, acl_type INTO :acl_id, :acl_type FROM servers
294       WHERE name = :name;
295     if (sqlca.sqlerrd[2] > 1)
296       return(MR_PERM);
297
298     /* parse client structure */
299     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
300         return(status);
301
302     /* check for client in access control list */
303     status = find_member(acl_type, acl_id, client_type, client_id, 0);
304     if (!status) return(MR_PERM);
305
306     return(MR_SUCCESS);
307 }
308
309
310 /* access_filesys - verify that client is owner or on owners list of filesystem
311  *      named by argv[0]
312  */
313
314 access_filesys(q, argv, cl)
315     struct query *q;
316     char *argv[];
317     client *cl;
318 {
319     EXEC SQL BEGIN DECLARE SECTION;
320     int users_id, list_id;
321     char *name;
322     EXEC SQL END DECLARE SECTION;
323     int status, client_id;
324     char *client_type;
325
326     name = argv[0];
327     EXEC SQL SELECT owner, owners INTO :users_id, :list_id FROM filesys
328       WHERE label = :name;
329
330     if (sqlca.sqlerrd[2] != 1)
331       return(MR_PERM);
332     if (users_id == cl->users_id)
333       return(MR_SUCCESS);
334     if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
335       return(status);
336     status = find_member("LIST", list_id, client_type, client_id, 0);
337     if (status)
338       return(MR_SUCCESS);
339     else
340       return(MR_PERM);
341 }
342
343
344 \f
345 /* Setup Routines */
346
347 /* Setup routine for add_user
348  *
349  * Inputs: argv[0] - login
350  *         argv[1] - uid
351  *
352  * Description:
353  *
354  * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
355  * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
356  */
357
358 setup_ausr(q, argv, cl)
359     struct query *q;
360     register char *argv[];
361     client *cl;
362 {
363     int row;
364     EXEC SQL BEGIN DECLARE SECTION;
365     int nuid;
366     EXEC SQL END DECLARE SECTION;
367
368     if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
369       row = 2;
370     else
371       row = 1;
372     if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1) {
373         if (set_next_object_id("uid", "users", 1))
374           return(MR_INGRES_ERR);
375         EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'uid';
376         if (sqlca.sqlerrd[2] != 1)
377           return(MR_INTERNAL);
378         sprintf(argv[row], "%d", nuid);
379     }
380
381     if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1) {
382         sprintf(argv[0], "#%s", argv[row]);
383     }
384
385     if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
386       return(mr_errcode);
387
388     return(MR_SUCCESS);
389 }
390
391
392 /* setup_dusr - verify that the user is no longer being referenced
393  * and may safely be deleted.
394  */
395
396 int setup_dusr(q, argv)
397     struct query *q;
398     char **argv;
399 {
400     EXEC SQL BEGIN DECLARE SECTION;
401     int flag, id;
402     EXEC SQL END DECLARE SECTION;
403
404     id = *(int *)argv[0];
405
406     /* For now, only allow users to be deleted if their status is 0 */
407     EXEC SQL REPEATED SELECT status INTO :flag FROM users
408       WHERE users_id = :id;
409     if (flag != 0 && flag != 4)
410       return(MR_IN_USE);
411
412     EXEC SQL REPEATED DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
413     EXEC SQL REPEATED DELETE FROM krbmap WHERE users_id = :id;
414     EXEC SQL REPEATED SELECT member_id INTO :idummy FROM imembers
415       WHERE member_id = :id AND member_type = 'USER';
416     if (sqlca.sqlerrd[2] > 0)
417         return(MR_IN_USE);
418     EXEC SQL REPEATED SELECT label INTO :cdummy FROM filesys WHERE owner = :id;
419     if (sqlca.sqlerrd[2]> 0)
420         return(MR_IN_USE);
421     EXEC SQL REPEATED SELECT name INTO :cdummy FROM list
422       WHERE acl_id = :id AND acl_type = 'USER';
423     if (sqlca.sqlerrd[2] > 0)
424         return(MR_IN_USE);
425     EXEC SQL REPEATED SELECT name INTO :cdummy FROM servers
426       WHERE acl_id = :id AND acl_type = 'USER';
427     if (sqlca.sqlerrd[2] > 0)
428         return(MR_IN_USE);
429     EXEC SQL REPEATED SELECT acl_id INTO :idummy FROM hostaccess
430       WHERE acl_id = :id AND acl_type = 'USER';
431     if (sqlca.sqlerrd[2] > 0)
432         return(MR_IN_USE);
433     if (ingres_errno)
434         return(mr_errcode);
435     return(MR_SUCCESS);
436 }
437
438
439 /* setup_spop: verify that there is already a valid POP machine_id in the
440  * pop_id field.  Also take care of keeping track of the post office usage.
441  */
442 int setup_spop(q, argv)
443 struct query *q;
444 char **argv;
445 {
446     EXEC SQL BEGIN DECLARE SECTION;
447     int id, mid, flag;
448     char type[9];
449     EXEC SQL END DECLARE SECTION;
450
451     id = *(int *)argv[0];
452     EXEC SQL REPEATED SELECT potype, pop_id INTO :type, :mid FROM users
453       WHERE users_id = :id;
454     if(sqlca.sqlerrd[2] = 0)
455       return(MR_MACHINE);
456     EXEC SQL REPEATED SELECT mach_id INTO :mid FROM machine
457       WHERE mach_id = :mid;
458     if (sqlca.sqlerrd[2] = 0)
459       return(MR_MACHINE);
460     if (strcmp(strtrim(type), "POP"))
461       set_pop_usage(mid, 1);
462     return(MR_SUCCESS);
463 }
464
465
466 /* setup_dpob:  Take care of keeping track of the post office usage.
467  */
468 int setup_dpob(q, argv)
469      struct query *q;
470      char **argv;
471 {
472     EXEC SQL BEGIN DECLARE SECTION;
473     int id, user;
474     char type[9];
475     EXEC SQL END DECLARE SECTION;
476
477     user = *(int *)argv[0];
478     EXEC SQL REPEATED SELECT potype, pop_id INTO :type, :id FROM users
479       WHERE users_id = :user;
480     if (ingres_errno) return(mr_errcode);
481
482     if (!strcmp(strtrim(type), "POP"))
483       set_pop_usage(id, -1);
484     return(MR_SUCCESS);
485 }
486
487
488 /* setup_dmac - verify that the machine is no longer being referenced
489  * and may safely be deleted.
490  */
491
492 int setup_dmac(q, argv)
493     struct query *q;
494     char **argv;
495 {
496     EXEC SQL BEGIN DECLARE SECTION;
497     int flag, id;
498     EXEC SQL END DECLARE SECTION;
499
500     id = *(int *)argv[0];
501     EXEC SQL REPEATED SELECT login INTO :cdummy FROM users
502       WHERE potype='POP' AND pop_id = :id;
503     if (sqlca.sqlerrd[2] > 0)
504         return(MR_IN_USE);
505     EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM serverhosts
506       WHERE mach_id = :id;
507     if (sqlca.sqlerrd[2] > 0)
508         return(MR_IN_USE);
509     EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM nfsphys
510       WHERE mach_id = :id;
511     if (sqlca.sqlerrd[2] > 0)
512         return(MR_IN_USE);
513     EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM hostaccess
514       WHERE mach_id = :id;
515     if (sqlca.sqlerrd[2] > 0)
516         return(MR_IN_USE);
517     EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM printcap
518       WHERE mach_id = :id;
519     if (sqlca.sqlerrd[2] > 0)
520         return(MR_IN_USE);
521     EXEC SQL REPEATED SELECT quotaserver INTO :idummy FROM printcap
522       WHERE quotaserver = :id;
523     if (sqlca.sqlerrd[2] > 0)
524         return(MR_IN_USE);
525     EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM palladium
526       WHERE mach_id = :id;
527     if (sqlca.sqlerrd[2] > 0)
528         return(MR_IN_USE);
529
530     EXEC SQL REPEATED DELETE FROM mcmap WHERE mach_id = :id;
531     if (ingres_errno) return(mr_errcode);
532     return(MR_SUCCESS);
533 }
534
535
536 /* setup_dclu - verify that the cluster is no longer being referenced
537  * and may safely be deleted.
538  */
539
540 int setup_dclu(q, argv)
541     struct query *q;
542     char **argv;
543 {
544     EXEC SQL BEGIN DECLARE SECTION;
545     int id;
546     EXEC SQL END DECLARE SECTION;
547
548     id = *(int *)argv[0];
549     EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM mcmap
550       WHERE clu_id = :id;
551     if (sqlca.sqlerrd[2] > 0)
552         return(MR_IN_USE);
553     EXEC SQL REPEATED SELECT clu_id INTO :idummy FROM svc
554       WHERE clu_id = :id;
555     if (sqlca.sqlerrd[2] > 0)
556         return(MR_IN_USE);
557     if (ingres_errno)
558         return(mr_errcode);
559     return(MR_SUCCESS);
560 }
561
562
563 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
564  * a new gid and put it in argv[6].  Otherwise if argv[6] is UNIQUE_ID but
565  * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
566  * a -1 there.  Remember that this is also used for ulis, with the indexes
567  * at 6 & 7.  Also check that the list name does not contain uppercase
568  * characters, control characters, @, or :.
569  */
570
571 static int badlistchars[] = {
572     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
573     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
574     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
575     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
576     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
577     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, /* P - _ */
578     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
579     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
580     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
581     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
582     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
583     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
584     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
585     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
586     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
587     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
588 };
589
590 int setup_alis(q, argv, cl)
591     struct query *q;
592     char *argv[];
593     client *cl;
594 {
595     EXEC SQL BEGIN DECLARE SECTION;
596     int ngid;
597     EXEC SQL END DECLARE SECTION;
598     char *malloc();
599     unsigned char *p;
600     int idx;
601
602     if (!strcmp(q->shortname, "alis"))
603       idx = 0;
604     else if (!strcmp(q->shortname, "ulis"))
605       idx = 1;
606
607     for (p = (unsigned char *) argv[idx]; *p; p++)
608       if (badlistchars[*p])
609         return(MR_BAD_CHAR);
610  
611     if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1) {
612         if (atoi(argv[5 + idx])) {
613             if (set_next_object_id("gid", "list", 1))
614               return(MR_INGRES_ERR);
615             EXEC SQL REPEATED SELECT value INTO :ngid FROM numvalues
616               WHERE name = 'gid';
617             if (ingres_errno) return(mr_errcode);
618             sprintf(argv[6 + idx], "%d", ngid);
619         } else {
620             strcpy(argv[6 + idx], "-1");
621         }
622     }
623
624     if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
625       return(mr_errcode);
626
627     return(MR_SUCCESS);
628 }
629
630
631 /* setup_dlis - verify that the list is no longer being referenced
632  * and may safely be deleted.
633  */
634
635 int setup_dlis(q, argv)
636     struct query *q;
637     char *argv[];
638 {
639     int flag, id, ec;
640
641     id = *(int *)argv[0];
642     sprintf(stmt_buf,"SELECT member_id FROM imembers WHERE member_id = %d AND member_type='LIST'",id);
643     if(ec=mr_select_any(stmt_buf)) {
644         if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
645     }
646     
647     sprintf(stmt_buf,"SELECT member_id FROM imembers WHERE list_id = %d",id);
648     if(ec=mr_select_any(stmt_buf)) {
649         if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
650     }
651
652     sprintf(stmt_buf,"SELECT label FROM filesys WHERE owners = %d",id);
653     if(ec=mr_select_any(stmt_buf)) {
654         if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
655     }
656
657     sprintf(stmt_buf,"SELECT tag FROM capacls WHERE list_id = %d",id);
658     if(ec=mr_select_any(stmt_buf)) {
659         if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
660     }
661
662     sprintf(stmt_buf,"SELECT name FROM list WHERE acl_id = %d AND acl_type='LIST' AND list_id != %d",id,id);
663     if(ec=mr_select_any(stmt_buf)) {
664         if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
665     }
666
667     sprintf(stmt_buf,"SELECT name FROM servers WHERE acl_id = %d AND acl_type='LIST'",id);
668     if(ec=mr_select_any(stmt_buf)) {
669         if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
670     }
671
672     sprintf(stmt_buf,"SELECT entity_id FROM quota WHERE entity_id = %d AND type='GROUP'",id);
673     if(ec=mr_select_any(stmt_buf)) {
674         if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
675     }
676  
677     sprintf(stmt_buf,"SELECT acl_id  FROM hostaccess WHERE acl_id = %d AND acl_type='LIST'",id);
678     if(ec=mr_select_any(stmt_buf)) {
679         if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
680     }
681
682     sprintf(stmt_buf,"SELECT class FROM zephyr z \
683 WHERE z.xmt_type = 'LIST' AND z.xmt_id = %d \
684 OR z.sub_type = 'LIST' AND z.sub_id = %d \
685 OR z.iws_type = 'LIST' AND z.iws_id = %d \
686 OR z.iui_type = 'LIST' AND z.iui_id = %d",id,id,id,id);
687     if(ec=mr_select_any(stmt_buf)) {
688         if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
689     }
690
691     return(MR_SUCCESS);
692 }
693
694
695 /* setup_dsin - verify that the service is no longer being referenced
696  * and may safely be deleted.
697  */
698
699 int setup_dsin(q, argv)
700     struct query *q;
701     char **argv;
702 {
703     EXEC SQL BEGIN DECLARE SECTION;     
704     int ec;
705     char *svrname;
706     EXEC SQL END DECLARE SECTION;
707
708     sprintf(stmt_buf,"SELECT service FROM serverhosts WHERE service = UPPERCASE('%s')",argv[0]);
709     if(ec=mr_select_any(stmt_buf)) {
710         if(ec==MR_EXISTS) 
711             return(MR_IN_USE); 
712         else 
713             return(ec);
714     }
715
716     svrname=argv[0];
717     EXEC SQL SELECT inprogress INTO :ec FROM servers 
718       WHERE name=UPPERCASE(:svrname);
719     if(ingres_errno) 
720         return(mr_errcode);
721     if(ec) 
722         return(MR_IN_USE); 
723
724     return(MR_SUCCESS);
725 }
726
727
728 /* setup_dshi - verify that the service-host is no longer being referenced
729  * and may safely be deleted.
730  */
731
732 int setup_dshi(q, argv)
733     struct query *q;
734     char **argv;
735 {
736     EXEC SQL BEGIN DECLARE SECTION;
737     int id, ec;
738     char *svrname;
739     EXEC SQL END DECLARE SECTION;
740
741     svrname=argv[0];
742     id = *(int *)argv[1];
743
744     EXEC SQL SELECT inprogress INTO :ec FROM serverhosts 
745       WHERE service=UPPERCASE(:svrname) AND mach_id = :id;
746     if(ingres_errno) 
747         return(mr_errcode);
748     if(ec) 
749         return(MR_IN_USE); 
750
751
752     return(MR_SUCCESS);
753 }
754
755
756 /**
757  ** setup_add_filesys - verify existance of referenced file systems
758  **
759  ** Inputs:     Add
760  **   argv[1] - type
761  **   argv[2] - mach_id
762  **   argv[3] - name
763  **   argv[5] - access
764  **
765  ** Description:
766  **   - for type = RVD:
767  **        * allow anything
768  **   - for type = NFS:
769  **        * extract directory prefix from name
770  **        * verify mach_id/dir in nfsphys
771  **        * verify access in {r, w, R, W}
772  **
773  **  Side effect: sets variable var_phys_id to the ID of the physical
774  **     filesystem (nfsphys_id for NFS, 0 for RVD)
775  **
776  ** Errors:
777  **   MR_NFS - specified directory not exported
778  **   MR_FILESYS_ACCESS - invalid filesys access
779  **
780  **/
781
782 EXEC SQL BEGIN DECLARE SECTION;
783 static int var_phys_id;
784 EXEC SQL END DECLARE SECTION;
785
786 setup_afil(q, argv, cl)
787     struct query *q;
788     char *argv[];
789     client *cl;
790 {
791     char *type, *name;
792     int mach_id;
793     EXEC SQL BEGIN DECLARE SECTION;
794     int ok;
795     char ftype[32], *access;
796     EXEC SQL END DECLARE SECTION;
797
798     type = argv[1];
799     mach_id = *(int *)argv[2];
800     name = argv[3];
801     access = argv[5];
802     var_phys_id = 0;
803
804     sprintf(ftype, "fs_access_%s", type);
805     EXEC SQL SELECT trans INTO :cdummy FROM alias
806       WHERE name = :ftype AND type = 'TYPE' and trans = :access;   /** Use mr_select_any() */
807     if (ingres_errno) return(mr_errcode);
808     if (sqlca.sqlerrd[2] == 0) return(MR_FILESYS_ACCESS);
809
810     if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
811       return(mr_errcode);
812
813     if (!strcmp(type, "NFS"))
814         return (check_nfs(mach_id, name, access));
815
816     return(MR_SUCCESS);
817 }
818
819
820 /* Verify the arguments, depending on the FStype.  Also, if this is an
821  * NFS filesystem, then update any quotas for that filesystem to reflect
822  * the new phys_id.
823  */
824
825 setup_ufil(q, argv, cl)
826     struct query *q;
827     char *argv[];
828     client *cl;
829 {
830     int mach_id, status;
831     char *type, *name;
832     EXEC SQL BEGIN DECLARE SECTION;
833     int fid, total, who;
834     char *entity, ftype[32], *access;
835     int var_phys_id = 0;
836     EXEC SQL END DECLARE SECTION;
837
838     type = argv[2];
839     mach_id = *(int *)argv[3];
840     name = argv[4];
841     access = argv[6];
842     fid = *(int *)argv[0];
843     who = cl->client_id;
844     entity = cl->entity;
845
846     sprintf(ftype, "fs_access_%s", type);
847     EXEC SQL SELECT trans INTO :cdummy FROM alias
848       WHERE name = :ftype AND type='TYPE' AND trans = :access;
849     if (ingres_errno) return(mr_errcode);
850     if (sqlca.sqlerrd[2] == 0) return(MR_FILESYS_ACCESS);
851
852     EXEC SQL SELECT type INTO :ftype FROM filesys
853       WHERE filsys_id = :fid;
854     strtrim(ftype);
855     if (ingres_errno) return(mr_errcode);
856
857     if (!strcmp(type, "NFS")) {
858         status = check_nfs(mach_id, name, access);
859         EXEC SQL UPDATE quota SET phys_id = :var_phys_id
860           WHERE filsys_id = :fid;
861         if (ingres_errno) return(mr_errcode);
862         return(status);
863     } else if (!strcmp(type, "AFS") && strcmp(ftype, "AFS")) {
864         total = 0;
865         EXEC SQL REPEATED DELETE FROM quota
866           WHERE type = 'ANY' AND filsys_id = :fid;
867         EXEC SQL SELECT SUM (quota) INTO :total FROM quota
868           WHERE filsys_id = :fid AND phys_id != 0;
869         if (ingres_errno) return(mr_errcode);
870         if (total != 0) {
871 /*
872  *             append quota (quota = total, filsys_id = fid,
873  *                           phys_id = 0, entity_id = 0, type = "ANY",
874  *                           modtime = "now", modby = who, modwith = entity)
875  */
876             EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
877                                         type, modtime, modby, modwith)
878               VALUES (:total, :fid, 0, 0,
879                       'ANY', 'now', :who, :entity) ;
880             if (ingres_errno) return(mr_errcode);
881         }
882     } else {
883         EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
884         if (ingres_errno) return(mr_errcode);
885     }
886     return(MR_SUCCESS);
887 }
888
889
890 /* Find the NFS physical partition that the named directory is on.
891  * This is done by comparing the dir against the mount point of the
892  * partition.  To make sure we get the correct match when there is
893  * more than one, we sort the query in reverse order by dir name.
894  */
895
896 check_nfs(mach_id, name, access)
897     EXEC SQL BEGIN DECLARE SECTION;
898     int mach_id;
899     EXEC SQL END DECLARE SECTION;
900     char *name;
901     char *access;
902 {
903     EXEC SQL BEGIN DECLARE SECTION;
904     char dir[81];
905     EXEC SQL END DECLARE SECTION;
906     char caccess;
907     register int status;
908     register char *cp1;
909     register char *cp2;
910
911     status = MR_NFS;
912     EXEC SQL DECLARE csr101 CURSOR FOR
913       SELECT nfsphys_id, TRIM (dir) FROM nfsphys
914         WHERE mach_id = :mach_id
915         ORDER BY 2 DESC;
916     EXEC SQL OPEN csr101;
917     while(1) {
918         EXEC SQL FETCH csr101 INTO :var_phys_id, :dir;
919         if(sqlca.sqlcode != 0) break;
920         cp1 = name;
921         cp2 = dir;
922         while (*cp2) {
923             if (*cp1++ != *cp2) break;
924             cp2++;
925         }
926         if (*cp2 == 0) {
927             status = MR_SUCCESS;
928             break;
929         }
930     }
931     EXEC SQL CLOSE csr101;
932     if (ingres_errno)
933         return(mr_errcode);
934     return(status);
935 }
936
937
938 /* setup_dfil: free any quota records and fsgroup info associated with
939  * a filesystem when it is deleted.  Also adjust the allocation numbers.
940  */
941
942 setup_dfil(q, argv, cl)
943     struct query  *q;
944     char **argv;
945     client *cl;
946 {
947     EXEC SQL BEGIN DECLARE SECTION;
948     int id, total, phys_id;
949     short int none;
950     EXEC SQL END DECLARE SECTION;
951
952     id = *(int *)argv[0];
953     EXEC SQL REPEATED SELECT SUM (quota) INTO :total:none FROM quota
954       WHERE filsys_id = :id;
955
956     if(none) total=0;
957
958     /** What if there are multiple phys_id's per f/s? (bad data) **/
959     EXEC SQL REPEATED SELECT phys_id INTO :phys_id FROM filesys
960       WHERE filsys_id = :id;
961     EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated - :total
962       WHERE nfsphys_id = :phys_id;
963
964     if(!none) {
965         EXEC SQL REPEATED DELETE FROM quota WHERE filsys_id = :id;
966     }
967     EXEC SQL REPEATED DELETE FROM fsgroup WHERE filsys_id = :id;
968     EXEC SQL REPEATED DELETE FROM fsgroup WHERE group_id = :id;
969     if (ingres_errno) return(mr_errcode);
970     return(MR_SUCCESS);
971 }
972
973
974 /* setup_dnfp: check to see that the nfs physical partition does not have
975  * any filesystems assigned to it before allowing it to be deleted.
976  */
977
978 setup_dnfp(q, argv, cl)
979     struct query  *q;
980     char **argv;
981     client *cl;
982 {
983     EXEC SQL BEGIN DECLARE SECTION;
984     int id;
985     char *dir;
986     EXEC SQL END DECLARE SECTION;
987
988     id = *(int *)argv[0];
989     dir = argv[1];
990     EXEC SQL REPEATED SELECT label INTO :cdummy FROM filesys fs, nfsphys np
991       WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
992         AND np.mach_id = :id AND np.dir = :dir;
993     if (sqlca.sqlerrd[2] > 0)
994       return(MR_IN_USE);
995     if (ingres_errno)
996       return(mr_errcode);
997     return(MR_SUCCESS);
998 }
999
1000
1001 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
1002  *   argv[0] = filsys_id
1003  *   argv[1] = type if "update_quota" or "delete_quota"
1004  *   argv[2 or 1] = users_id or list_id
1005  */
1006
1007 setup_dqot(q, argv, cl)
1008     struct query  *q;
1009     char **argv;
1010     client *cl;
1011 {
1012     EXEC SQL BEGIN DECLARE SECTION;
1013     int quota, fs, id, physid;
1014     char *qtype;
1015     EXEC SQL END DECLARE SECTION;
1016
1017     fs = *(int *)argv[0];
1018     if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
1019         qtype = argv[1];
1020         id = *(int *)argv[2];
1021     } else {
1022         qtype = "USER";
1023         id = *(int *)argv[1];
1024     }
1025
1026     EXEC SQL REPEATED SELECT quota INTO :quota FROM quota
1027       WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
1028     EXEC SQL REPEATED SELECT phys_id INTO :physid FROM filesys 
1029       WHERE filsys_id = :fs;
1030     EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated - :quota
1031       WHERE nfsphys_id = :physid;
1032
1033     if (ingres_errno) return(mr_errcode);
1034     return(MR_SUCCESS);
1035 }
1036
1037
1038 /* setup_sshi: don't exclusive lock the machine table during
1039  * set_server_host_internal.
1040  */
1041 /** Not allowed under (INGRES) SQL **/
1042 setup_sshi(q, argv, cl)
1043     struct query  *q;
1044     char **argv;
1045     client *cl;
1046 {
1047 #if 0
1048 #ifsql INGRES
1049     EXEC SQL set lockmode session where readlock = system;
1050 #endsql
1051 #endif
1052 }
1053
1054
1055 /* setup add_kerberos_user_mapping: add the string to the string
1056  * table if necessary.
1057  */
1058
1059 setup_akum(q, argv, cl)
1060 struct query *q;
1061 char **argv;
1062 client *cl;
1063 {
1064     EXEC SQL BEGIN DECLARE SECTION;
1065     int id, rowcount;
1066     char *name;
1067     EXEC SQL END DECLARE SECTION;
1068
1069     name = argv[1];
1070     if (name_to_id(name, "STRING", &id) != MR_SUCCESS) {
1071         if (q->type != APPEND) return(MR_STRING);
1072         EXEC SQL SELECT value INTO :id FROM numvalues
1073           WHERE name = 'strings_id';
1074         id++;
1075         EXEC SQL UPDATE numvalues SET value = :id
1076           WHERE name = 'strings_id';
1077         EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
1078         cache_entry(name, "STRING", id);
1079     }
1080     if (ingres_errno) return(mr_errcode);
1081     *(int *)argv[1] = id;
1082     return(MR_SUCCESS);
1083 }
1084
1085
1086 \f
1087 /* FOLLOWUP ROUTINES */
1088
1089 /* generic set_modtime routine.  This takes the table name from the query,
1090  * and will update the modtime, modby, and modwho fields in the entry in
1091  * the table whose name field matches argv[0].
1092  */
1093
1094 set_modtime(q, argv, cl)
1095     struct query *q;
1096     char *argv[];
1097     client *cl;
1098 {
1099     char *name, *entity, *table;
1100     int who;
1101
1102     entity = cl->entity;
1103     who = cl->client_id;
1104     table = q->rtable;
1105     name = argv[0];
1106
1107     sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, modwith = '%s' WHERE %s.name = LEFT('%s',SIZE(%s.name))",table,who,entity,table,name,table);
1108     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1109
1110     return(MR_SUCCESS);
1111 }
1112
1113 /* generic set_modtime_by_id routine.  This takes the table name from
1114  * the query, and the id name from the validate record,
1115  * and will update the modtime, modby, and modwho fields in the entry in
1116  * the table whose id matches argv[0].
1117  */
1118
1119 set_modtime_by_id(q, argv, cl)
1120     struct query *q;
1121     char **argv;
1122     client *cl;
1123 {
1124     char *entity, *table, *id_name;
1125     int who, id;
1126
1127     entity = cl->entity;
1128     who = cl->client_id;
1129     table = q->rtable;
1130     id_name = q->validate->object_id;
1131
1132     id = *(int *)argv[0];
1133     sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, \
1134 modwith = '%s' WHERE %s.%s = %d",table,who,entity,table,id_name,id);
1135     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1136     return(MR_SUCCESS);
1137 }
1138
1139
1140 /* Sets the finger modtime on a user record.  The users_id will be in argv[0].
1141  */
1142
1143 set_finger_modtime(q, argv, cl)
1144     struct query *q;
1145     char *argv[];
1146     client *cl;
1147 {
1148     EXEC SQL BEGIN DECLARE SECTION;
1149     int users_id, who;
1150     char *entity;
1151     EXEC SQL END DECLARE SECTION;
1152
1153     entity = cl->entity;
1154     who = cl->client_id;
1155     users_id = *(int *)argv[0];
1156
1157     EXEC SQL UPDATE users SET fmodtime='now', fmodby = :who, fmodwith = :entity
1158       WHERE users.users_id = :users_id;
1159
1160    return(MR_SUCCESS);
1161 }
1162
1163
1164 /* Sets the pobox modtime on a user record.  The users_id will be in argv[0].
1165  */
1166
1167 set_pobox_modtime(q, argv, cl)
1168     struct query *q;
1169     char **argv;
1170     client *cl;
1171 {
1172     EXEC SQL BEGIN DECLARE SECTION;
1173     int users_id, who;
1174     char *entity;
1175     EXEC SQL END DECLARE SECTION;
1176
1177     entity = cl->entity;
1178     who = cl->client_id;
1179     users_id = *(int *)argv[0];
1180
1181     EXEC SQL UPDATE users SET pmodtime='now', pmodby = :who, pmodwith = :entity
1182       WHERE users.users_id = :users_id;
1183
1184     return(MR_SUCCESS);
1185 }
1186
1187
1188 /* Like set_modtime, but uppercases the name first.
1189  */
1190
1191 set_uppercase_modtime(q, argv, cl)
1192     struct query *q;
1193     char **argv;
1194     client *cl;
1195 {
1196     char *name, *entity, *table;
1197     int who;
1198
1199     entity = cl->entity;
1200     who = cl->client_id;
1201     table = q->rtable;
1202     name = argv[0];
1203
1204     sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, modwith = '%s' WHERE %s.name = UPPERCASE(LEFT('%s',SIZE(%s.name)))",table,who,entity,table,name,table);
1205     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1206
1207     return(MR_SUCCESS);
1208 }
1209
1210
1211 /* Sets the modtime on the machine whose mach_id is in argv[0].  This routine
1212  * is necessary for add_machine_to_cluster becuase the table that query
1213  * operates on is "mcm", not "machine".
1214  */
1215
1216 set_mach_modtime_by_id(q, argv, cl)
1217     struct query *q;
1218     char **argv;
1219     client *cl;
1220 {
1221     EXEC SQL BEGIN DECLARE SECTION;
1222     char *entity;
1223     int who, id;
1224     EXEC SQL END DECLARE SECTION;
1225
1226     entity = cl->entity;
1227     who = cl->client_id;
1228     id = *(int *)argv[0];
1229     EXEC SQL UPDATE machine SET modtime='now', modby = :who, modwith = :entity
1230       WHERE machine.mach_id = :id;
1231
1232     return(MR_SUCCESS);
1233 }
1234
1235
1236 /* Sets the modtime on the cluster whose mach_id is in argv[0].  This routine
1237  * is necessary for add_cluster_data and delete_cluster_data becuase the
1238  * table that query operates on is "svc", not "cluster".
1239  */
1240
1241 set_cluster_modtime_by_id(q, argv, cl)
1242     struct query *q;
1243     char **argv;
1244     client *cl;
1245 {
1246     EXEC SQL BEGIN DECLARE SECTION;
1247     char *entity;
1248     int who, id;
1249     EXEC SQL END DECLARE SECTION;
1250
1251     entity = cl->entity;
1252     who = cl->client_id;
1253
1254     id = *(int *)argv[0];
1255     EXEC SQL UPDATE cluster SET modtime='now', modby = :who, modwith = :entity
1256       WHERE cluster.clu_id = :id;
1257     return(MR_SUCCESS);
1258 }
1259
1260
1261 /* sets the modtime on the serverhost where the service name is in argv[0]
1262  * and the mach_id is in argv[1].
1263  */
1264
1265 set_serverhost_modtime(q, argv, cl)
1266     struct query *q;
1267     char **argv;
1268     client *cl;
1269 {
1270     EXEC SQL BEGIN DECLARE SECTION;
1271     char *entity, *serv;
1272     int who, id;
1273     EXEC SQL END DECLARE SECTION;
1274
1275     entity = cl->entity;
1276     who = cl->client_id;
1277
1278     serv = argv[0];
1279     id = *(int *)argv[1];
1280     EXEC SQL UPDATE serverhosts
1281       SET modtime = 'now', modby = :who, modwith = :entity
1282       WHERE service = :serv AND mach_id = :id;
1283     return(MR_SUCCESS);
1284 }
1285
1286
1287 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1288  * directory name is in argv[1].
1289  */
1290
1291 set_nfsphys_modtime(q, argv, cl)
1292     struct query *q;
1293     char **argv;
1294     client *cl;
1295 {
1296     EXEC SQL BEGIN DECLARE SECTION;
1297     char *entity, *dir;
1298     int who, id;
1299     EXEC SQL END DECLARE SECTION;
1300
1301     entity = cl->entity;
1302     who = cl->client_id;
1303
1304     id = *(int *)argv[0];
1305     dir = argv[1];
1306     EXEC SQL UPDATE nfsphys SET modtime = 'now', modby = :who, modwith = :entity
1307       WHERE dir = :dir AND mach_id = :id;
1308     return(MR_SUCCESS);
1309 }
1310
1311
1312 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1313  * label.
1314  */
1315
1316 set_filesys_modtime(q, argv, cl)
1317     struct query *q;
1318     char *argv[];
1319     client *cl;
1320 {
1321     EXEC SQL BEGIN DECLARE SECTION;
1322     char *label, *entity;
1323     int who;
1324     EXEC SQL END DECLARE SECTION;
1325
1326     entity = cl->entity;
1327     who = cl->client_id;
1328
1329     label = argv[0];
1330     if (!strcmp(q->shortname, "ufil"))
1331       label = argv[1];
1332
1333     EXEC SQL UPDATE filesys SET modtime = 'now', modby = :who,
1334         modwith = :entity, phys_id = :var_phys_id
1335       WHERE label = LEFT(:label,SIZE(label));
1336     return(MR_SUCCESS);
1337 }
1338
1339
1340 /* sets the modtime on a zephyr class, where argv[0] contains the class
1341  * name.
1342  */
1343
1344 set_zephyr_modtime(q, argv, cl)
1345     struct query *q;
1346     char *argv[];
1347     client *cl;
1348 {
1349     EXEC SQL BEGIN DECLARE SECTION;
1350     char *class, *entity;
1351     int who;
1352     EXEC SQL END DECLARE SECTION;
1353
1354     entity = cl->entity;
1355     who = cl->client_id;
1356
1357     class = argv[0];
1358
1359     EXEC SQL UPDATE zephyr SET modtime = 'now', modby = :who, modwith = :entity
1360       WHERE class = LEFT(:class,SIZE(class));
1361
1362     return(MR_SUCCESS);
1363 }
1364
1365
1366 /* fixes the modby field.  This will be the second to last thing in the
1367  * argv, the argv length is determined from the query structure.  It is
1368  * passed as a pointer to an integer.  This will either turn it into a
1369  * username, or # + the users_id.
1370  */
1371 followup_fix_modby(q, sq, v, action, actarg, cl)
1372     struct query *q;
1373     register struct save_queue *sq;
1374     struct validate *v;
1375     register int (*action)();
1376     register int actarg;
1377     client *cl;
1378 {
1379     register int i, j;
1380     char **argv, *malloc();
1381     int id, status;
1382
1383     i = q->vcnt - 2;
1384     while (sq_get_data(sq, &argv)) {
1385         id = atoi(argv[i]);
1386         if (id > 0)
1387           status = id_to_name(id, "USER", &argv[i]);
1388         else
1389           status = id_to_name(-id, "STRING", &argv[i]);
1390         if (status && status != MR_NO_MATCH)
1391           return(status);
1392         (*action)(q->vcnt, argv, actarg);
1393         for (j = 0; j < q->vcnt; j++)
1394           free(argv[j]);
1395         free(argv);
1396     }
1397     sq_destroy(sq);
1398     return(MR_SUCCESS);
1399 }
1400
1401
1402 /* After retrieving a user account, fix the modby field and signature.
1403  * The modby field is the second to last thing in the
1404  * argv, the argv length is determined from the query structure.  It is
1405  * passed as a pointer to an integer.  This will either turn it into a
1406  * username, or # + the users_id.  Only "gua*" queries have a signature,
1407  * these are ones with U_END return values.  "gub*" queries also use this
1408  * routine but don't have a signature.
1409  */
1410 followup_guax(q, sq, v, action, actarg, cl)
1411     struct query *q;
1412     register struct save_queue *sq;
1413     struct validate *v;
1414     register int (*action)();
1415     register int actarg;
1416     client *cl;
1417 {
1418     register int i, j;
1419     char **argv, *malloc();
1420 #ifdef GDSS
1421     unsigned char sigbuf[256];
1422     char *kname;
1423     SigInfo  si;
1424     EXEC SQL BEGIN DECLARE SECTION; 
1425     int timestamp, who;
1426     char *login;
1427     varchar struct { short data_size; char data_buf[257];} rsig;
1428     EXEC SQL END DECLARE SECTION; 
1429 #endif /* GDSS */
1430     int id, status;
1431
1432     i = q->vcnt - 2;
1433     while (sq_get_data(sq, &argv)) {
1434 #ifdef DEBUG
1435         com_err(whoami, 0, "argv[SIGNATURE] = \"%s\"", argv[U_SIGNATURE]);
1436 #endif /* DEBUG */
1437         id = atoi(argv[i]);
1438         if (id > 0)
1439           status = id_to_name(id, "USER", &argv[i]);
1440         else
1441           status = id_to_name(-id, "STRING", &argv[i]);
1442         if (status && status != MR_NO_MATCH)
1443           return(status);
1444 #ifdef GDSS
1445         if (q->vcnt == U_END && strlen(argv[U_SIGNATURE])) {
1446             login = argv[U_NAME];
1447             EXEC SQL REPEATED SELECT signature, sigdate, sigwho 
1448               INTO :rsig, :timestamp, :who FROM users
1449               WHERE login = :login;
1450             /** What about (INGRES) error handling? **/
1451             kname = malloc(1);
1452             status = id_to_name(who, "STRING", &kname);
1453             si.timestamp = timestamp;
1454             si.SigInfoVersion = 0; /* XXXXX this isn't used */
1455             kname_parse(si.pname, si.pinst, si.prealm, kname);
1456             free(kname);
1457             rsig.data_buf[rsig.data_size] = 0;
1458             si.rawsig = (unsigned char *)strsave(rsig.data_buf);
1459 #ifdef DEBUG
1460             com_err(whoami, 0, "rawsig length = %d, sig=\"%s\"", strlen(si.rawsig), si.rawsig);
1461 #endif /* DEBUG */
1462             GDSS_Recompose(&si, sigbuf);
1463             free(si.rawsig);
1464             free(argv[U_SIGNATURE]);
1465             argv[U_SIGNATURE] = strsave(sigbuf);
1466 #ifdef DEBUG
1467             com_err(whoami, 0, "generated signature length %d", strlen(sigbuf));
1468 #endif /* DEBUG */
1469         }
1470 #endif /* GDSS */
1471         (*action)(q->vcnt, argv, actarg);
1472         for (j = 0; j < q->vcnt; j++)
1473           free(argv[j]);
1474         free(argv);
1475     }
1476     sq_destroy(sq);
1477     return(MR_SUCCESS);
1478 }
1479
1480
1481 /**
1482  ** followup_ausr - add finger and pobox entries, set_user_modtime
1483  **
1484  ** Inputs:
1485  **     argv[0] - login (add_user)
1486  **     argv[3] - last name
1487  **     argv[4] - first name
1488  **     argv[5] - middle name
1489  **
1490  **/
1491
1492 followup_ausr(q, argv, cl)
1493     struct query *q;
1494     char *argv[];
1495     client *cl;
1496 {
1497     EXEC SQL BEGIN DECLARE SECTION;
1498     int who, status, id;
1499     char *login, *entity, *src, *dst, *name;
1500     char fullname[129];
1501     EXEC SQL END DECLARE SECTION;
1502 #ifdef GDSS
1503     char databuf[32], *kname_unparse();
1504     EXEC SQL BEGIN DECLARE SECTION;
1505     char rawsig[128];
1506     int sigwho, timestamp;
1507     EXEC SQL END DECLARE SECTION;
1508     SigInfo si;
1509 #endif /* GDSS */
1510
1511     /* build fullname */
1512     if (strlen(argv[4]) && strlen(argv[5]))
1513         sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1514     else if (strlen(argv[4]))
1515         sprintf(fullname, "%s %s", argv[4], argv[3]);
1516     else
1517         sprintf(fullname, "%s", argv[3]);
1518
1519 #ifdef GDSS
1520       if (q->vcnt == U_END && *argv[U_SIGNATURE]) {
1521         sprintf(databuf, "%s:%s", argv[U_NAME], argv[U_MITID]);
1522         /* skip bytes for timestamp & kname */
1523         si.rawsig = (unsigned char *) rawsig;
1524         status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE], &si);
1525         if (strlen(rawsig) > mr_sig_length) {
1526             com_err(whoami, 0, "GDSS signature would be truncated.");  /** untested **/
1527             return(MR_INTERNAL);
1528         }
1529         if (status == 0) {
1530             name = kname_unparse(si.pname, si.pinst, si.prealm);
1531             status = name_to_id(name, "STRING", &sigwho);
1532             if (status == MR_NO_MATCH) {
1533                 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1534                   WHERE name='strings_id';
1535                 sigwho++;
1536                 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1537                   WHERE name='strings_id';
1538                 EXEC SQL INSERT INTO strings (string_id, string) 
1539                   VALUES (:sigwho, :name);
1540             } else if (status)
1541               return(gdss2et(status));
1542             timestamp = si.timestamp;
1543         } else
1544           return(gdss2et(status));
1545       } else {
1546         rawsig[0] = 0;
1547         sigwho = 0;
1548         timestamp = 0;
1549       }
1550 #endif /* GDSS */
1551
1552     login = argv[0];
1553     who = cl->client_id;
1554     entity = cl->entity;
1555
1556     /* create finger entry, pobox & set modtime on user */
1557 #ifdef GDSS
1558     EXEC SQL REPEATED UPDATE users
1559       SET modtime='now', modby=:who, modwith = :entity,
1560           fullname = :fullname, affiliation = type,
1561           signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho,
1562           fmodtime='now', fmodby = :who, fmodwith = :entity,
1563           potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1564       WHERE login = :login;
1565 #else /* GDSS */
1566     EXEC SQL REPEATED UPDATE users
1567       SET modtime='now', modby=:who, modwith = :entity,
1568           fullname = :fullname, affiliation = type,
1569           fmodtime='now', fmodby = :who, fmodwith = :entity,
1570           potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1571       WHERE login = :login;
1572 #endif /* GDSS */
1573
1574     return(MR_SUCCESS);
1575 }
1576
1577
1578 /**
1579  ** followup_uusr - do signature, set_user_modtime
1580  **
1581  ** Inputs:
1582  **   argv[0] - login (add_user)
1583  **   argv[U_SIGNATURE] - sig
1584  **
1585  **/
1586
1587 followup_uuac(q, argv, cl)
1588     struct query *q;
1589     char *argv[];
1590     client *cl;
1591 {
1592     EXEC SQL BEGIN DECLARE SECTION; 
1593     int who, status, id;
1594     char *entity, *name;
1595     EXEC SQL END DECLARE SECTION; 
1596 #ifdef GDSS
1597     char databuf[32], *kname_unparse();
1598     EXEC SQL BEGIN DECLARE SECTION; 
1599     char rawsig[128];
1600     char *login;
1601     int sigwho, timestamp;
1602     EXEC SQL END DECLARE SECTION; 
1603     SigInfo si;
1604 #endif /* GDSS */
1605     
1606     id = *(int *)argv[0];
1607     who = cl->client_id;
1608     entity = cl->entity;
1609     
1610 #ifdef GDSS
1611     if (q->vcnt == U_MODTIME && *argv[U_SIGNATURE + 1]) {
1612         login = malloc(1);
1613         status = id_to_name(id, "USER", &login);
1614         sprintf(databuf, "%s:%s", login, argv[U_MITID+1]);
1615         free(login);
1616         /* skip bytes for timestamp & kname */
1617         si.rawsig = (unsigned char *) rawsig;
1618 #ifdef DEBUG
1619         com_err(whoami, 0, "verifying sig");
1620 #endif /* DEBUG */
1621         status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE+1], &si);
1622 #ifdef DEBUG
1623         com_err(whoami, 0, "verified");
1624 #endif /* DEBUG */
1625         if (strlen(rawsig) > mr_sig_length) {
1626             com_err(whoami, 0, "GDSS signature would be truncated.");  /** untested **/
1627             return(MR_INTERNAL);
1628         }
1629         if (status == 0) {
1630             name = kname_unparse(si.pname, si.pinst, si.prealm);
1631             status = name_to_id(name, "STRING", &sigwho);
1632             if (status == MR_NO_MATCH) {
1633                 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1634                   WHERE name='strings_id';
1635                 sigwho++;
1636                 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1637                   WHERE name='strings_id';
1638                 EXEC SQL INSERT INTO strings (string_id, string) 
1639                   VALUES (:sigwho, :name);
1640             } else if (status)
1641               return(gdss2et(status));
1642             timestamp = si.timestamp;
1643         } else
1644           return(gdss2et(status));
1645     } else {
1646         rawsig[0] = 0;
1647         sigwho = 0;
1648         timestamp = 0;
1649     }
1650 #endif /* GDSS */
1651  
1652     /* create finger entry, pobox & set modtime on user */
1653
1654 #ifdef GDSS
1655     EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity,
1656         signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho
1657       WHERE users_id = :id;
1658 #else /* GDSS */
1659     EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity
1660       WHERE users_id = :id;
1661 #endif /* GDSS */
1662     return(MR_SUCCESS);
1663 }
1664  
1665  
1666 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1667  * type in argv[1].  Then completes the upcall to the user.
1668  *
1669  * argv[2] is of the form "123:234" where the first integer is the machine
1670  * ID if it is a pop box, and the second is the string ID if it is an SMTP
1671  * box.  argv[1] should be "POP", "SMTP", or "NONE".  Boxes of type NONE
1672  * are skipped.
1673  */
1674
1675 followup_gpob(q, sq, v, action, actarg, cl)
1676     register struct query *q;
1677     register struct save_queue *sq;
1678     register struct validate *v;
1679     register int (*action)();
1680     int actarg;
1681     client *cl;
1682 {
1683     char **argv, *index();
1684     char *ptype, *p;
1685     int mid, sid, status, i;
1686
1687     /* for each row */
1688     while (sq_get_data(sq, &argv)) {
1689         mr_trim_args(2, argv);
1690         ptype = argv[1];
1691         p = index(argv[2], ':');
1692         *p++ = 0;
1693         mid = atoi(argv[2]);
1694         sid = atoi(p);
1695
1696         if (!strcmp(ptype, "POP")) {
1697             status = id_to_name(mid, "MACHINE", &argv[2]);
1698             if (status == MR_NO_MATCH)
1699               return(MR_MACHINE);
1700         } else if (!strcmp(ptype, "SMTP")) {
1701             status = id_to_name(sid, "STRING", &argv[2]);
1702             if (status == MR_NO_MATCH)
1703               return(MR_STRING);
1704         } else /* ptype == "NONE" */ {
1705             goto skip;
1706         }
1707         if (status) return(status);
1708
1709         if (!strcmp(q->shortname, "gpob")) {
1710             sid = atoi(argv[4]);
1711             if (sid > 0)
1712               status = id_to_name(sid, "USER", &argv[4]);
1713             else
1714               status = id_to_name(-sid, "STRING", &argv[4]);
1715         }
1716         if (status && status != MR_NO_MATCH) return(status);
1717
1718         (*action)(q->vcnt, argv, actarg);
1719     skip:
1720         /* free saved data */
1721         for (i = 0; i < q->vcnt; i++)
1722             free(argv[i]);
1723         free(argv);
1724     }
1725
1726     sq_destroy(sq);
1727     return (MR_SUCCESS);
1728 }
1729
1730
1731 /* followup_glin: fix the ace_name in argv[8].  argv[7] will contain the
1732  * ace_type: "LIST", "USER", or "NONE".  Decode the id in argv[8] into the
1733  * proper name based on the type, and repace that string in the argv.
1734  * Also fixes the modby field by called followup_fix_modby.
1735  */
1736
1737 followup_glin(q, sq, v, action, actarg, cl)
1738     register struct query *q;
1739     register struct save_queue *sq;
1740     register struct validate *v;
1741     register int (*action)();
1742     int actarg;
1743     client *cl;
1744 {
1745     char **argv, *malloc(), *realloc(), *type;
1746     int id, i, idx, status;
1747
1748     idx = 8;
1749     if (!strcmp(q->shortname, "gsin"))
1750       idx = 12;
1751
1752     while (sq_get_data(sq, &argv)) {
1753         mr_trim_args(q->vcnt, argv);
1754
1755         id = atoi(argv[i = q->vcnt - 2]);
1756         if (id > 0)
1757           status = id_to_name(id, "USER", &argv[i]);
1758         else
1759           status = id_to_name(-id, "STRING", &argv[i]);
1760         if (status && status != MR_NO_MATCH)
1761           return(status);
1762
1763         id = atoi(argv[idx]);
1764         type = argv[idx - 1];
1765
1766         if (!strcmp(type, "LIST")) {
1767             status = id_to_name(id, "LIST", &argv[idx]);
1768         } else if (!strcmp(type, "USER")) {
1769             status = id_to_name(id, "USER", &argv[idx]);
1770         } else if (!strcmp(type, "KERBEROS")) {
1771             status = id_to_name(id, "STRING", &argv[idx]);
1772         } else if (!strcmp(type, "NONE")) {
1773             status = 0;
1774             free(argv[idx]);
1775             argv[idx] = strsave("NONE");
1776         } else {
1777             status = 0;
1778             free(argv[idx]);
1779             argv[idx] = strsave("???");
1780         }
1781         if (status && status != MR_NO_MATCH)
1782           return(status);
1783
1784         if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1785             argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1786             strcpy(argv[6], UNIQUE_GID);
1787         }
1788
1789         /* send the data */
1790         (*action)(q->vcnt, argv, actarg);
1791
1792         /* free saved data */
1793         for (i = 0; i < q->vcnt; i++)
1794             free(argv[i]);
1795         free(argv);
1796     }
1797
1798     sq_destroy(sq);
1799     return (MR_SUCCESS);
1800 }
1801
1802
1803 /* followup_gqot: Fix the entity name, directory name & modby fields
1804  *   argv[0] = filsys_id
1805  *   argv[1] = type
1806  *   argv[2] = entity_id
1807  *   argv[3] = ascii(quota)
1808  */
1809
1810 followup_gqot(q, sq, v, action, actarg, cl)
1811     struct query *q;
1812     register struct save_queue *sq;
1813     struct validate *v;
1814     register int (*action)();
1815     register int actarg;
1816     client *cl;
1817 {
1818     register int j;
1819     char **argv, *malloc();
1820     EXEC SQL BEGIN DECLARE SECTION;
1821     int id;
1822     char *name, *label;
1823     EXEC SQL END DECLARE SECTION;
1824     int status, idx;
1825
1826     if (!strcmp(q->name, "get_quota") ||
1827         !strcmp(q->name, "get_quota_by_filesys"))
1828       idx = 4;
1829     else
1830       idx = 3;
1831     while (sq_get_data(sq, &argv)) {
1832         if (idx == 4) {
1833             switch (argv[1][0]) {
1834             case 'U':
1835                 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1836                 break;
1837             case 'G':
1838             case 'L':
1839                 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1840                 break;
1841             case 'A':
1842                 free(argv[2]);
1843                 argv[2] = strsave("system:anyuser");
1844                 break;
1845             default:
1846                 id = atoi(argv[2]);
1847                 argv[2] = malloc(8);
1848                 sprintf(argv[2], "%d", id);
1849             }
1850         }
1851         id = atoi(argv[idx]);
1852         free(argv[idx]);
1853         argv[idx] = malloc(256);
1854         name = argv[idx];
1855         if (id == 0) {
1856             label = argv[0];
1857             EXEC SQL REPEATED SELECT name INTO :name FROM filesys
1858               WHERE label = :label;
1859         } else {
1860             EXEC SQL REPEATED SELECT dir INTO :name FROM nfsphys
1861               WHERE nfsphys_id = :id;
1862         }
1863         if (sqlca.sqlerrd[2] != 1) {
1864             sprintf(argv[idx], "#%d", id);
1865         }
1866
1867         id = atoi(argv[idx+3]);
1868         if (id > 0)
1869           status = id_to_name(id, "USER", &argv[idx+3]);
1870         else
1871           status = id_to_name(-id, "STRING", &argv[idx+3]);
1872         if (status && status != MR_NO_MATCH)
1873           return(status);
1874         (*action)(q->vcnt, argv, actarg);
1875         for (j = 0; j < q->vcnt; j++)
1876           free(argv[j]);
1877         free(argv);
1878     }
1879     sq_destroy(sq);
1880     return(MR_SUCCESS);
1881 }
1882
1883
1884 /* followup_aqot: Add allocation to nfsphys after creating quota.
1885  *   argv[0] = filsys_id
1886  *   argv[1] = type if "add_quota" or "update_quota"
1887  *   argv[2 or 1] = id
1888  *   argv[3 or 2] = ascii(quota)
1889  */
1890
1891 followup_aqot(q, argv, cl)
1892     struct query  *q;
1893     char **argv;
1894     client *cl;
1895 {
1896     EXEC SQL BEGIN DECLARE SECTION;
1897     int quota, id, fs, who, physid;
1898     char *entity, *qtype, *table_name;
1899     EXEC SQL END DECLARE SECTION;
1900     char incr_qual[60];
1901     char *incr_argv[2];
1902     int status;
1903
1904     table_name=q->rtable;
1905     fs = *(int *)argv[0];
1906     EXEC SQL REPEATED SELECT phys_id INTO :physid FROM filesys
1907       WHERE filsys_id = :fs;
1908     if(ingres_errno)
1909         return(mr_errcode);
1910
1911     if (!strcmp(q->shortname, "aqot") || !strcmp(q->shortname, "uqot")) {
1912         qtype = argv[1];
1913         id = *(int *)argv[2];
1914         quota = atoi(argv[3]);
1915         sprintf(incr_qual,"q.filsys_id = %d",fs);
1916     } else {
1917         qtype = "USER";
1918         id = *(int *)argv[1];
1919         quota = atoi(argv[2]);
1920         sprintf(incr_qual,"q.filsys_id=%d AND q.type='%s' AND q.entity_id=%d",
1921                 fs,qtype,id);
1922     }
1923
1924     /* quota case of incremental_{before|after} only looks at slot 1 */
1925     incr_argv[1]=qtype;
1926
1927     /* Follows one of many possible gross hacks to fix these particular
1928      * conflicts between what is possible in the query table and what 
1929      * is possible in SQL.    
1930      */
1931     if(q->type==APPEND) {
1932         incremental_clear_before();
1933         EXEC SQL INSERT INTO quota 
1934             (filsys_id, type, entity_id, quota, phys_id) 
1935           VALUES (:fs, :qtype, :id, :quota, :physid);
1936         incremental_after(table_name, incr_qual, incr_argv);    
1937     } else {
1938         incremental_before(table_name, incr_qual, incr_argv);
1939         EXEC SQL UPDATE quota SET quota = :quota
1940           WHERE filsys_id = :fs AND type = :qtype AND entity_id = :id;
1941         status = mr_errcode;
1942         incremental_after(table_name, incr_qual, incr_argv);
1943     }
1944
1945     if (ingres_errno)
1946         return(mr_errcode);
1947     flush_name(argv[0], q->rtable);  
1948     if(q->type==APPEND) {
1949         EXEC SQL UPDATE tblstats SET appends = appends + 1, modtime = 'now'
1950           WHERE table_name = :table_name;
1951     } else {
1952         EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = 'now'
1953           WHERE table_name = :table_name;
1954     }
1955         
1956     /* Proceed with original followup */
1957     who = cl->client_id;
1958     entity = cl->entity;
1959
1960     EXEC SQL REPEATED UPDATE quota
1961       SET modtime = 'now', modby = :who, modwith = :entity
1962       WHERE filsys_id = :fs and type = :qtype and entity_id = :id;
1963     EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated + :quota
1964       WHERE nfsphys_id = :physid;
1965     if (ingres_errno) return(mr_errcode);
1966     return(MR_SUCCESS);
1967 }
1968
1969
1970 /* Necessitated by the requirement of a correlation name by the incremental
1971  * routines, since query table deletes don't provide one. 
1972  */
1973 followup_dqot(q,argv,cl)
1974     struct query *q;
1975     char **argv;
1976     struct client *cl;
1977 {
1978     char *qtype;
1979     int id, fs;
1980     char *incr_argv[2];
1981     EXEC SQL BEGIN DECLARE SECTION; 
1982     char incr_qual[80];
1983     char *tblname;
1984     EXEC SQL END DECLARE SECTION; 
1985
1986     fs = *(int *)argv[0];
1987     if (!strcmp(q->shortname, "dqot")) {
1988         qtype = argv[1];
1989         id = *(int *)argv[2];
1990     } else {
1991         qtype = "USER";
1992         id = *(int *)argv[1];
1993     }
1994     sprintf(incr_qual,"q.filsys_id=%d AND q.type='%s' AND q.entity_id=%d",
1995             fs,qtype,id);
1996
1997     /* quota case of incremental_{before|after} only looks at slot 1 */
1998     incr_argv[1]=qtype;
1999
2000     incremental_before(q->rtable, incr_qual, incr_argv);
2001     EXEC SQL DELETE FROM quota q WHERE :incr_qual;
2002     incremental_clear_after();
2003
2004     if (ingres_errno) 
2005         return(mr_errcode);
2006     flush_name(argv[0], q->rtable);
2007
2008     tblname = q->rtable;
2009     EXEC SQL UPDATE tblstats SET deletes = deletes + 1, modtime = 'now'
2010       WHERE table_name = :tblname;
2011     return(MR_SUCCESS);
2012 }
2013
2014
2015 followup_gpce(q, sq, v, action, actarg, cl)
2016     struct query *q;
2017     register struct save_queue *sq;
2018     struct validate *v;
2019     register int (*action)();
2020     register int actarg;
2021     client *cl;
2022 {
2023     register int i, j;
2024     char **argv, *malloc();
2025     int id, status;
2026
2027     i = q->vcnt - 2;
2028     while (sq_get_data(sq, &argv)) {
2029         id = atoi(argv[PCAP_QSERVER]);
2030         status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
2031         if (status) return (status);
2032         id = atoi(argv[i]);
2033         if (id > 0)
2034           status = id_to_name(id, "USER", &argv[i]);
2035         else
2036           status = id_to_name(-id, "STRING", &argv[i]);
2037         if (status && status != MR_NO_MATCH)
2038           return(status);
2039         (*action)(q->vcnt, argv, actarg);
2040         for (j = 0; j < q->vcnt; j++)
2041           free(argv[j]);
2042         free(argv);
2043     }
2044     sq_destroy(sq);
2045     return(MR_SUCCESS);
2046 }
2047
2048
2049 /* followup_gzcl:
2050  */
2051
2052 followup_gzcl(q, sq, v, action, actarg, cl)
2053     register struct query *q;
2054     register struct save_queue *sq;
2055     register struct validate *v;
2056     register int (*action)();
2057     int actarg;
2058     client *cl;
2059 {
2060     int id, i, status;
2061     char **argv;
2062
2063     while (sq_get_data(sq, &argv)) {
2064         mr_trim_args(q->vcnt, argv);
2065
2066         id = atoi(argv[i = q->vcnt - 2]);
2067         if (id > 0)
2068           status = id_to_name(id, "USER", &argv[i]);
2069         else
2070           status = id_to_name(-id, "STRING", &argv[i]);
2071         if (status && status != MR_NO_MATCH)
2072           return(status);
2073
2074         for (i = 1; i < 8; i+=2) {
2075             id = atoi(argv[i+1]);
2076             if (!strcmp(argv[i], "LIST")) {
2077                 status = id_to_name(id, "LIST", &argv[i+1]);
2078             } else if (!strcmp(argv[i], "USER")) {
2079                 status = id_to_name(id, "USER", &argv[i+1]);
2080             } else if (!strcmp(argv[i], "KERBEROS")) {
2081                 status = id_to_name(id, "STRING", &argv[i+1]);
2082             } else if (!strcmp(argv[i], "NONE")) {
2083                 status = 0;
2084                 free(argv[i+1]);
2085                 argv[i+1] = strsave("NONE");
2086             } else {
2087                 status = 0;
2088                 free(argv[i+1]);
2089                 argv[i+1] = strsave("???");
2090             }
2091             if (status && status != MR_NO_MATCH)
2092               return(status);
2093         }
2094
2095         /* send the data */
2096         (*action)(q->vcnt, argv, actarg);
2097
2098         /* free saved data */
2099         for (i = 0; i < q->vcnt; i++)
2100             free(argv[i]);
2101         free(argv);
2102     }
2103     sq_destroy(sq);
2104     return(MR_SUCCESS);
2105 }
2106
2107
2108 /* followup_gsha:
2109  */
2110
2111 followup_gsha(q, sq, v, action, actarg, cl)
2112     register struct query *q;
2113     register struct save_queue *sq;
2114     register struct validate *v;
2115     register int (*action)();
2116     int actarg;
2117     client *cl;
2118 {
2119     char **argv;
2120     int i, id, status;
2121
2122     while (sq_get_data(sq, &argv)) {
2123         mr_trim_args(q->vcnt, argv);
2124
2125         id = atoi(argv[4]);
2126         if (id > 0)
2127           status = id_to_name(id, "USER", &argv[4]);
2128         else
2129           status = id_to_name(-id, "STRING", &argv[4]);
2130         if (status && status != MR_NO_MATCH)
2131           return(status);
2132
2133         id = atoi(argv[2]);
2134         if (!strcmp(argv[1], "LIST")) {
2135             status = id_to_name(id, "LIST", &argv[2]);
2136         } else if (!strcmp(argv[1], "USER")) {
2137             status = id_to_name(id, "USER", &argv[2]);
2138         } else if (!strcmp(argv[1], "KERBEROS")) {
2139             status = id_to_name(id, "STRING", &argv[2]);
2140         } else if (!strcmp(argv[1], "NONE")) {
2141             status = 0;
2142             free(argv[2]);
2143             argv[2] = strsave("NONE");
2144         } else {
2145             status = 0;
2146             free(argv[2]);
2147             argv[2] = strsave("???");
2148         }
2149         if (status && status != MR_NO_MATCH)
2150           return(status);
2151
2152         /* send the data */
2153         (*action)(q->vcnt, argv, actarg);
2154
2155         /* free saved data */
2156         for (i = 0; i < q->vcnt; i++)
2157             free(argv[i]);
2158         free(argv);
2159     }
2160     sq_destroy(sq);
2161     return(MR_SUCCESS);
2162 }
2163
2164
2165 \f
2166 /* Special query routines */
2167
2168 /* set_pobox - this does all of the real work.
2169  *       argv = user_id, type, box
2170  * if type is POP, then box should be a machine, and its ID should be put in
2171  * pop_id.  If type is SMTP, then box should be a string and its ID should
2172  * be put in box_id.  If type is NONE, then box doesn't matter.
2173  */
2174
2175 int set_pobox(q, argv, cl)
2176     struct query *q;
2177     char **argv;
2178     client *cl;
2179 {
2180     EXEC SQL BEGIN DECLARE SECTION;
2181     int user, id;
2182     char *box, potype[9];
2183     EXEC SQL END DECLARE SECTION;
2184     int status;
2185
2186     box = argv[2];
2187     user = *(int *)argv[0];
2188
2189     EXEC SQL REPEATED SELECT pop_id, potype INTO :id, :potype FROM users
2190       WHERE users_id = :user;
2191     if (ingres_errno) return(mr_errcode);
2192     if (!strcmp(strtrim(potype), "POP"))
2193       set_pop_usage(id, -1);
2194
2195     if (!strcmp(argv[1], "POP")) {
2196         status = name_to_id(box, "MACHINE", &id);
2197         if (status == MR_NO_MATCH)
2198           return(MR_MACHINE);
2199         else if (status)
2200           return(status);
2201         EXEC SQL REPEATED UPDATE users SET potype = 'POP', pop_id = :id
2202           WHERE users_id = :user;
2203         set_pop_usage(id, 1);
2204     } else if (!strcmp(argv[1], "SMTP")) {
2205         if (index(box, '/') || index(box, '|'))
2206           return(MR_BAD_CHAR);
2207         status = name_to_id(box, "STRING", &id);
2208         if (status == MR_NO_MATCH) {
2209             EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
2210               WHERE name='strings_id';
2211             id++;
2212             EXEC SQL REPEATED UPDATE numvalues SET value = :id
2213               WHERE name='strings_id';
2214             EXEC SQL INSERT INTO strings (string_id, string)
2215               VALUES (:id, :box);
2216         } else if (status)
2217           return(status);
2218         EXEC SQL REPEATED UPDATE users SET potype='SMTP', box_id = :id
2219           WHERE users_id = :user;
2220     } else /* argv[1] == "NONE" */ {
2221         EXEC SQL REPEATED UPDATE users SET potype='NONE'
2222           WHERE users_id = :user;
2223     }
2224
2225     set_pobox_modtime(q, argv, cl);
2226     EXEC SQL REPEATED UPDATE tblstats SET updates = updates+1, modtime='now'
2227       WHERE table_name='users';
2228     if (ingres_errno) return(mr_errcode);
2229     return(MR_SUCCESS);
2230 }
2231
2232
2233 /* get_list_info:  passed a wildcard list name, returns lots of stuff about
2234  * each list.  This is tricky:  first build a queue of all requested
2235  * data.  Rest of processing consists of fixing gid, ace_name, and modby.
2236  */
2237
2238 get_list_info(q, aargv, cl, action, actarg)
2239     register struct query *q;
2240     char **aargv;
2241     client *cl;
2242     register int (*action)();
2243     int actarg;
2244 {
2245     char *argv[13], *malloc(), *realloc();
2246     EXEC SQL BEGIN DECLARE SECTION;
2247     char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
2248     char maillist[5], grouplist[5], gid_str[6], acl_name[256], desc[256];
2249     char modtime[27], modby[256], modwith[9];
2250     int id, rowcount, acl_id, hid, modby_id;
2251     char qual[80];
2252     EXEC SQL END DECLARE SECTION;
2253     int returned, status;
2254     struct save_queue *sq, *sq_create();
2255
2256     returned = rowcount = 0;
2257     name = aargv[0];
2258     convert_wildcards(name);
2259
2260     sq = sq_create();
2261     sprintf(qual,"name LIKE '%s' ESCAPE '*'",name);
2262     optimize_sql_stmt(qual);
2263     EXEC SQL DECLARE csr102 CURSOR FOR SELECT list_id FROM list
2264       WHERE :qual;
2265     EXEC SQL OPEN csr102;
2266     while(1)
2267     {
2268         EXEC SQL FETCH csr102 INTO :id;
2269         if(sqlca.sqlcode!=0) break;
2270         sq_save_data(sq, id);
2271         rowcount++;
2272     }
2273     EXEC SQL CLOSE csr102;
2274
2275     if (ingres_errno) return(mr_errcode);
2276     if (rowcount == 0)
2277       return(MR_NO_MATCH);
2278
2279     argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
2280     argv[4] = maillist; argv[5] = grouplist; argv[6] = gid_str;
2281     argv[7] = acl_type; argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
2282
2283     while (sq_get_data(sq, &id)) {
2284         if (id == 0)
2285           continue;
2286         argv[6] = gid_str;
2287         EXEC SQL REPEATED SELECT name, CHAR(active), CHAR(publicflg),
2288             CHAR(hidden), hidden, CHAR(maillist), CHAR(grouplist), CHAR(gid),
2289             TRIM(acl_type), acl_id, description, CHAR(modtime), modby, modwith
2290           INTO :listname, :active, :public, :hidden, :hid, :maillist,
2291             :grouplist, :gid_str, :acl_type, :acl_id, :desc,
2292             :modtime, :modby_id, :modwith
2293           FROM list WHERE list_id = :id;
2294
2295         if (ingres_errno) return(mr_errcode);
2296
2297         if (atoi(gid_str) == -1)
2298             argv[6] = UNIQUE_GID;
2299
2300         argv[8] = malloc(0);
2301         if (!strcmp(acl_type, "LIST")) {
2302             status = id_to_name(acl_id, "LIST", &argv[8]);
2303         } else if (!strcmp(acl_type, "USER")) {
2304             status = id_to_name(acl_id, "USER", &argv[8]);
2305         } else if (!strcmp(acl_type, "KERBEROS")) {
2306             status = id_to_name(acl_id, "STRING", &argv[8]);
2307         } else if (!strcmp(acl_type, "NONE")) {
2308             status = 0;
2309             free(argv[8]);
2310             argv[8] = strsave("NONE");
2311         } else {
2312             status = 0;
2313             free(argv[8]);
2314             argv[8] = strsave("???");
2315         }
2316         if (status && status != MR_NO_MATCH) return(status);
2317
2318         argv[11] = malloc(0);
2319         if (modby_id > 0)
2320           status = id_to_name(modby_id, "USER", &argv[11]);
2321         else
2322           status = id_to_name(-modby_id, "STRING", &argv[11]);
2323         if (status && status != MR_NO_MATCH) return(status);
2324
2325         mr_trim_args(q->vcnt, argv);
2326         returned++;
2327         (*action)(q->vcnt, argv, actarg);
2328         free(argv[8]);
2329         free(argv[11]);
2330     }
2331
2332     sq_destroy(sq);
2333     if (ingres_errno) return(mr_errcode);
2334     return (MR_SUCCESS);
2335 }
2336
2337
2338 /* Add_member_to_list: do list flattening as we go!  MAXLISTDEPTH is
2339  * how many different ancestors a member is allowed to have.
2340  */
2341
2342 #define MAXLISTDEPTH    1024
2343
2344 int add_member_to_list(q, argv, cl)
2345     struct query *q;
2346     char **argv;
2347     client *cl;
2348 {
2349     EXEC SQL BEGIN DECLARE SECTION;
2350     int id, lid, mid, error, who, ref;
2351     char *mtype, dtype[9], *entity;
2352     EXEC SQL END DECLARE SECTION;
2353     int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2354     int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2355     int status;
2356     char *dtypes[MAXLISTDEPTH];
2357     char *iargv[3], *buf;
2358
2359     lid = *(int *)argv[0];
2360     mtype = argv[1];
2361     mid = *(int *)argv[2];
2362     /* if the member is already a direct member of the list, punt */
2363     EXEC SQL REPEATED SELECT list_id INTO :idummy FROM imembers
2364       WHERE list_id = :lid AND member_id = :mid
2365         AND member_type = :mtype AND direct = 1;
2366     if (sqlca.sqlerrd[2] > 0)
2367       return(MR_EXISTS);
2368     if (!strcasecmp(mtype, "STRING")) {
2369         buf = malloc(0);
2370         status = id_to_name(mid, "STRING", &buf);
2371         if (status) return(status);
2372         if (index(buf, '/') || index(buf, '|')) {
2373             free(buf);
2374             return(MR_BAD_CHAR);
2375         }
2376         free(buf);
2377     }
2378
2379     ancestors[0] = lid;
2380     aref[0] = 1;
2381     acount = 1;
2382     EXEC SQL DECLARE csr103 CURSOR FOR
2383       SELECT list_id, ref_count FROM imembers
2384         WHERE member_id = :lid AND member_type='LIST';
2385     EXEC SQL OPEN csr103;
2386     while(1) {
2387         EXEC SQL FETCH csr103 INTO :id, :ref;
2388         if(sqlca.sqlcode != 0) break;
2389         aref[acount] = ref;
2390         ancestors[acount++] = id;
2391         if (acount >= MAXLISTDEPTH) break;
2392     }
2393     EXEC SQL CLOSE csr103;
2394     if (ingres_errno) return(mr_errcode);
2395     if (acount >= MAXLISTDEPTH) {
2396         return(MR_INTERNAL);
2397     }
2398     descendants[0] = mid;
2399     dtypes[0] = mtype;
2400     dref[0] = 1;
2401     dcount = 1;
2402     error = 0;
2403     if (!strcmp(mtype, "LIST")) {
2404         EXEC SQL DECLARE csr104 CURSOR FOR
2405           SELECT member_id, member_type, ref_count
2406           FROM imembers
2407           WHERE list_id = :mid;
2408         EXEC SQL OPEN csr104;
2409         while(1) {
2410             EXEC SQL FETCH csr104 INTO :id, :dtype, :ref;
2411             if(sqlca.sqlcode != 0) break;
2412             switch (dtype[0]) {
2413             case 'L':
2414                 dtypes[dcount] = "LIST";
2415                 break;
2416             case 'U':
2417                 dtypes[dcount] = "USER";
2418                 break;
2419             case 'S':
2420                 dtypes[dcount] = "STRING";
2421                 break;
2422             case 'K':
2423                 dtypes[dcount] = "KERBEROS";
2424                 break;
2425             default:
2426                 error++;
2427                 break;
2428             }
2429             dref[dcount] = ref;
2430             descendants[dcount++] = id;
2431             if (dcount >= MAXLISTDEPTH) {
2432                 error++;
2433                 break;
2434             }
2435         }
2436         EXEC SQL CLOSE csr104;
2437         if (ingres_errno) return(mr_errcode);
2438         if (error)
2439           return(MR_INTERNAL);
2440     }
2441     for (a = 0; a < acount; a++) {
2442         lid = ancestors[a];
2443         for (d = 0; d < dcount; d++) {
2444             mid = descendants[d];
2445             mtype = dtypes[d];
2446             if (mid == lid && !strcmp(mtype, "LIST")) {
2447                 return(MR_LISTLOOP);
2448             }
2449             EXEC SQL REPEATED SELECT ref_count INTO :idummy FROM imembers
2450               WHERE list_id = :lid AND member_id = :mid
2451                 AND member_type = :mtype;
2452             ref = aref[a] * dref[d];
2453             if (sqlca.sqlerrd[2] > 0) {
2454                 if (a == 0 && d == 0) {
2455                     EXEC SQL UPDATE imembers
2456                       SET ref_count = ref_count+:ref, direct=1
2457                       WHERE list_id = :lid AND member_id = :mid
2458                         AND member_type = :mtype;
2459                 } else {
2460                     EXEC SQL UPDATE imembers
2461                       SET ref_count = ref_count+:ref
2462                       WHERE list_id = :lid AND member_id = :mid
2463                         AND member_type = :mtype;
2464                 }
2465             } else {
2466                 incremental_clear_before();
2467                 if (a == 0 && d == 0) {
2468                     EXEC SQL INSERT INTO imembers
2469                       (list_id, member_id, direct, member_type, ref_count)
2470                       VALUES (:lid, :mid, 1, :mtype, 1);
2471                 } else {
2472                     EXEC SQL INSERT INTO imembers
2473                       (list_id, member_id, member_type, ref_count)
2474                       VALUES (:lid, :mid, :mtype, 1);
2475                 }
2476                 iargv[0] = (char *)lid;
2477                 iargv[1] = mtype;
2478                 iargv[2] = (char *)mid;
2479                 incremental_after("members", 0, iargv);
2480             }
2481         }
2482     }
2483     lid = *(int *)argv[0];
2484     entity = cl->entity;
2485     who = cl->client_id;
2486     EXEC SQL REPEATED UPDATE list
2487       SET modtime='now', modby = :who, modwith = :entity
2488       WHERE list_id = :lid;
2489     if (ingres_errno) return(mr_errcode);
2490     return(MR_SUCCESS);
2491 }
2492
2493
2494 /* Delete_member_from_list: do list flattening as we go!
2495  */
2496
2497 int delete_member_from_list(q, argv, cl)
2498     struct query *q;
2499     char **argv;
2500     client *cl;
2501 {
2502     EXEC SQL BEGIN DECLARE SECTION;
2503     int id, lid, mid, cnt, error, who, ref;
2504     char *mtype, dtype[9], *entity;
2505     EXEC SQL END DECLARE SECTION;
2506     int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2507     int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2508     char *dtypes[MAXLISTDEPTH];
2509     char *iargv[3];
2510
2511     lid = *(int *)argv[0];
2512     mtype = argv[1];
2513     mid = *(int *)argv[2];
2514     /* if the member is not a direct member of the list, punt */
2515     EXEC SQL REPEATED SELECT list_id INTO :idummy FROM imembers
2516       WHERE list_id = :lid AND member_id = :mid
2517         AND member_type = :mtype AND direct = 1;
2518     if (ingres_errno) return(mr_errcode);
2519     if (sqlca.sqlcode == 100)
2520       return(MR_NO_MATCH);
2521     ancestors[0] = lid;
2522     aref[0] = 1;
2523     acount = 1;
2524     EXEC SQL DECLARE csr105 CURSOR FOR
2525       SELECT list_id, ref_count FROM imembers
2526         WHERE member_id = :lid AND member_type = 'LIST';
2527     EXEC SQL OPEN csr105;
2528     while(1) {
2529         EXEC SQL FETCH csr105 INTO :id, :ref;
2530         if(sqlca.sqlcode!=0) break;
2531         aref[acount] = ref;
2532         ancestors[acount++] = id;
2533         if (acount >= MAXLISTDEPTH) break;
2534     }
2535     EXEC SQL CLOSE csr105;
2536     if (ingres_errno)
2537       return(mr_errcode);
2538     if (acount >= MAXLISTDEPTH)
2539       return(MR_INTERNAL);
2540     descendants[0] = mid;
2541     dtypes[0] = mtype;
2542     dref[0] = 1;
2543     dcount = 1;
2544     error = 0;
2545     if (!strcmp(mtype, "LIST")) {
2546         EXEC SQL DECLARE csr106 CURSOR FOR
2547           SELECT member_id, member_type, ref_count FROM imembers
2548             WHERE list_id = :mid;
2549         EXEC SQL OPEN csr106;
2550         while(1) {
2551             EXEC SQL FETCH csr106 INTO :id, :dtype, :ref;
2552             if(sqlca.sqlcode!=0) break;
2553             switch (dtype[0]) {
2554             case 'L':
2555                 dtypes[dcount] = "LIST";
2556                 break;
2557             case 'U':
2558                 dtypes[dcount] = "USER";
2559                 break;
2560             case 'S':
2561                 dtypes[dcount] = "STRING";
2562                 break;
2563             case 'K':
2564                 dtypes[dcount] = "KERBEROS";
2565                 break;
2566             default:
2567                 error++;
2568                 break;
2569             }
2570             dref[dcount] = ref;
2571             descendants[dcount++] = id;
2572             if (dcount >= MAXLISTDEPTH) break;
2573         }
2574         EXEC SQL CLOSE csr106;
2575         if (ingres_errno)
2576           return(mr_errcode);
2577         if (error)
2578           return(MR_INTERNAL);
2579     }
2580     for (a = 0; a < acount; a++) {
2581         lid = ancestors[a];
2582         for (d = 0; d < dcount; d++) {
2583             mid = descendants[d];
2584             mtype = dtypes[d];
2585             if (mid == lid && !strcmp(mtype, "LIST")) {
2586                 return(MR_LISTLOOP);
2587             }
2588             EXEC SQL REPEATED SELECT ref_count INTO :cnt FROM imembers
2589               WHERE list_id = :lid AND member_id = :mid AND member_type = :mtype;
2590             ref = aref[a] * dref[d];
2591             if (cnt <= ref) {
2592                 iargv[0] = (char *)lid;
2593                 iargv[1] = mtype;
2594                 iargv[2] = (char *)mid;
2595                 incremental_before("members", 0, iargv);
2596                 EXEC SQL DELETE FROM imembers
2597                   WHERE list_id = :lid AND member_id = :mid
2598                     AND member_type= :mtype;
2599                 incremental_clear_after();
2600             } else if (a == 0 && d == 0) {
2601                 EXEC SQL UPDATE imembers
2602                   SET ref_count = ref_count - :ref, direct = 0
2603                   WHERE list_id = :lid AND member_id = :mid
2604                     AND member_type = :mtype;
2605             } else {
2606                 EXEC SQL UPDATE imembers
2607                   SET ref_count = ref_count - :ref
2608                   WHERE list_id = :lid AND member_id = :mid
2609                     AND member_type = :mtype;
2610             }
2611         }
2612     }
2613     lid = *(int *)argv[0];
2614     entity = cl->entity;
2615     who = cl->client_id;
2616     EXEC SQL UPDATE list SET modtime = 'now', modby = :who, modwith = :entity
2617       WHERE list_id = :lid;
2618     if (ingres_errno) return(mr_errcode);
2619     return(MR_SUCCESS);
2620 }
2621
2622
2623 /* get_ace_use - given a type and a name, return a type and a name.
2624  * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2625  * and argv[1] will contain the ID of the entity in question.  The R*
2626  * types mean to recursively look at every containing list, not just
2627  * when the object in question is a direct member.  On return, the
2628  * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2629  */
2630
2631 int get_ace_use(q, argv, cl, action, actarg)
2632     struct query *q;
2633     char *argv[];
2634     client *cl;
2635     int (*action)();
2636     int actarg;
2637 {
2638     int found = 0;
2639     EXEC SQL BEGIN DECLARE SECTION;
2640     char *atype;
2641     int aid, listid, id;
2642     EXEC SQL END DECLARE SECTION;
2643     struct save_queue *sq, *sq_create();
2644
2645     atype = argv[0];
2646     aid = *(int *)argv[1];
2647     if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2648         !strcmp(atype, "KERBEROS")) {
2649         return(get_ace_internal(atype, aid, action, actarg));
2650     }
2651
2652     sq = sq_create();
2653     if (!strcmp(atype, "RLIST")) {
2654         sq_save_data(sq, aid);
2655         /* get all the list_id's of containing lists */
2656         EXEC SQL DECLARE csr107 CURSOR FOR
2657           SELECT list_id FROM imembers
2658             WHERE member_type='LIST' AND member_id = :aid;
2659         EXEC SQL OPEN csr107;
2660         while(1) {
2661             EXEC SQL FETCH csr107 INTO :listid;
2662             if(sqlca.sqlcode != 0) break;
2663             sq_save_unique_data(sq, listid);
2664         }
2665         EXEC SQL CLOSE csr107;
2666         /* now process each one */
2667         while (sq_get_data(sq, &id)) {
2668             if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2669               found++;
2670         }
2671     }
2672
2673     if (!strcmp(atype, "RUSER")) {
2674         EXEC SQL DECLARE csr108 CURSOR FOR
2675           SELECT list_id FROM imembers
2676             WHERE member_type='USER' AND member_id = :aid;
2677         EXEC SQL OPEN csr108;
2678         while(1) {
2679             EXEC SQL FETCH csr108 INTO :listid;
2680             if(sqlca.sqlcode != 0) break;
2681             sq_save_data(sq, listid);
2682         }
2683         EXEC SQL CLOSE csr108;
2684         /* now process each one */
2685         while (sq_get_data(sq, &id)) {
2686             if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2687               found++;
2688         }
2689         if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2690           found++;
2691     }
2692
2693     if (!strcmp(atype, "RKERBERO")) {
2694         EXEC SQL DECLARE csr109 CURSOR FOR
2695           SELECT list_id FROM imembers
2696             WHERE member_type='KERBEROS' AND member_id = :aid;
2697         EXEC SQL OPEN csr109;
2698         while(1) {
2699             EXEC SQL FETCH csr109 INTO :listid;
2700             if(sqlca.sqlcode != 0) break;
2701             sq_save_data(sq, listid);
2702         }
2703         EXEC SQL CLOSE csr109;
2704         /* now process each one */
2705         while (sq_get_data(sq, &id)) {
2706             if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2707               found++;
2708         }
2709         if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2710           found++;
2711     }
2712
2713     sq_destroy(sq);
2714     if (ingres_errno) return(mr_errcode);
2715     if (!found) return(MR_NO_MATCH);
2716     return(MR_SUCCESS);
2717 }
2718
2719
2720 /* This looks up a single list or user for ace use.  atype must be "USER"
2721  * or "LIST", and aid is the ID of the corresponding object.  This is used
2722  * by get_ace_use above.
2723  */
2724
2725 get_ace_internal(atype, aid, action, actarg)
2726     EXEC SQL BEGIN DECLARE SECTION;
2727     char *atype;
2728     int aid;
2729     EXEC SQL END DECLARE SECTION;
2730     int (*action)();
2731     int actarg;
2732 {
2733     char *rargv[2];
2734     int found = 0;
2735     EXEC SQL BEGIN DECLARE SECTION;
2736     char name[33];
2737     EXEC SQL END DECLARE SECTION;
2738
2739     rargv[1] = name;
2740     if (!strcmp(atype, "LIST")) {
2741         rargv[0] = "FILESYS";
2742         EXEC SQL DECLARE csr110 CURSOR FOR
2743           SELECT label FROM filesys
2744             WHERE owners = :aid;
2745         EXEC SQL OPEN csr110;
2746         while(1) {
2747             EXEC SQL FETCH csr110 INTO :name;
2748             if(sqlca.sqlcode != 0) break;
2749             (*action)(2, rargv, actarg);
2750             found++;
2751         }
2752         EXEC SQL CLOSE csr110;
2753
2754         rargv[0] = "QUERY";
2755         EXEC SQL DECLARE csr111 CURSOR FOR
2756           SELECT capability FROM capacls
2757             WHERE list_id = :aid ;
2758         EXEC SQL OPEN csr111;
2759         while(1) {
2760             EXEC SQL FETCH csr111 INTO :name ;
2761             if(sqlca.sqlcode != 0) break;
2762             (*action)(2, rargv, actarg);
2763             found++;
2764         }
2765         EXEC SQL CLOSE csr111;
2766     } else if (!strcmp(atype, "USER")) {
2767         rargv[0] = "FILESYS";
2768         EXEC SQL DECLARE csr112 CURSOR FOR
2769           SELECT label FROM filesys
2770             WHERE owner = :aid;
2771         EXEC SQL OPEN csr112;
2772         while(1) {
2773             EXEC SQL FETCH csr112 INTO :name ;
2774             if(sqlca.sqlcode != 0) break;
2775             (*action)(2, rargv, actarg);
2776             found++;
2777         }
2778         EXEC SQL CLOSE csr112;
2779     }
2780
2781     rargv[0] = "LIST";
2782     EXEC SQL DECLARE csr113 CURSOR FOR
2783       SELECT name FROM list
2784         WHERE acl_type = :atype AND acl_id = :aid;
2785     EXEC SQL OPEN csr113;
2786     while(1) {
2787         EXEC SQL FETCH csr113 INTO :name;
2788         if(sqlca.sqlcode != 0) break;
2789         (*action)(2, rargv, actarg);
2790         found++;
2791     }
2792     EXEC SQL CLOSE csr113;
2793
2794     rargv[0] = "SERVICE";
2795     EXEC SQL DECLARE csr114 CURSOR FOR
2796       SELECT name FROM servers
2797         WHERE acl_type = :atype AND acl_id = :aid;
2798     EXEC SQL OPEN csr114;
2799     while(1) {
2800         EXEC SQL FETCH csr114 INTO :name;
2801         if(sqlca.sqlcode != 0) break;
2802         (*action)(2, rargv, actarg);
2803         found++;
2804     }
2805     EXEC SQL CLOSE csr114;
2806
2807     rargv[0] = "HOSTACCESS";
2808     EXEC SQL DECLARE csr115 CURSOR FOR
2809       SELECT name FROM machine m, hostaccess ha
2810         WHERE m.mach_id = ha.mach_id AND ha.acl_type = :atype
2811           AND ha.acl_id = :aid;
2812     EXEC SQL OPEN csr115;
2813     while(1) {
2814         EXEC SQL FETCH csr115 INTO :name;
2815         if(sqlca.sqlcode != 0) break;
2816         (*action)(2, rargv, actarg);
2817         found++;
2818     }
2819     EXEC SQL CLOSE csr115;
2820
2821     rargv[0] = "ZEPHYR";
2822     EXEC SQL DECLARE csr116 CURSOR FOR
2823       SELECT class FROM zephyr z
2824         WHERE z.xmt_type = :atype AND z.xmt_id = :aid
2825           OR z.sub_type = :atype AND z.sub_id = :aid
2826           OR z.iws_type = :atype AND z.iws_id = :aid
2827           OR z.iui_type = :atype AND z.iui_id = :aid;
2828     EXEC SQL OPEN csr116;
2829     while(1) {
2830         EXEC SQL FETCH csr116 INTO :name;
2831         if(sqlca.sqlcode != 0) break;
2832         (*action)(2, rargv, actarg);
2833         found++;
2834     }
2835     EXEC SQL CLOSE csr116;
2836
2837     if (!found) return(MR_NO_MATCH);
2838     return(MR_SUCCESS);
2839 }
2840
2841
2842 /* get_lists_of_member - given a type and a name, return the name and flags
2843  * of all of the lists of the given member.  The member_type is one of
2844  * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2845  * and argv[1] will contain the ID of the entity in question.  The R*
2846  * types mean to recursively look at every containing list, not just
2847  * when the object in question is a direct member.
2848  */
2849
2850 int get_lists_of_member(q, argv, cl, action, actarg)
2851     struct query *q;
2852     char *argv[];
2853     client *cl;
2854     int (*action)();
2855     int actarg;
2856 {
2857     int found = 0, direct = 1;
2858     char *rargv[6];
2859     EXEC SQL BEGIN DECLARE SECTION;
2860     char *atype;
2861     int aid, listid, id;
2862     char name[33], active[5], public[5], hidden[5], maillist[5], grouplist[5];
2863     EXEC SQL END DECLARE SECTION;
2864
2865     atype = argv[0];
2866     aid = *(int *)argv[1];
2867     if (!strcmp(atype, "RLIST")) {
2868         atype = "LIST";
2869         direct = 0;
2870     }
2871     if (!strcmp(atype, "RUSER")) {
2872         atype = "USER";
2873         direct = 0;
2874     }
2875     if (!strcmp(atype, "RSTRING")) {
2876         atype = "STRING";
2877         direct = 0;
2878     }
2879     if (!strcmp(atype, "RKERBEROS")) {
2880         atype = "KERBEROS";
2881         direct = 0;
2882     }
2883
2884     rargv[0] = name;
2885     rargv[1] = active;
2886     rargv[2] = public;
2887     rargv[3] = hidden;
2888     rargv[4] = maillist;
2889     rargv[5] = grouplist;
2890     if (direct) {
2891         EXEC SQL DECLARE csr117a CURSOR FOR
2892           SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2893               CHAR(l.maillist), CHAR(l.grouplist)
2894             FROM list l, imembers im
2895             WHERE l.list_id = im.list_id AND im.direct = 1
2896               AND im.member_type = :atype AND im.member_id = :aid;
2897         EXEC SQL OPEN csr117a;
2898         while(1) {
2899             EXEC SQL FETCH csr117a
2900               INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2901             if(sqlca.sqlcode != 0) break;
2902             (*action)(6, rargv, actarg);
2903             found++;
2904         }
2905         EXEC SQL CLOSE csr117a;
2906     } else {
2907         EXEC SQL DECLARE csr117b CURSOR FOR
2908           SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2909               CHAR(l.maillist), CHAR(l.grouplist)
2910             FROM list l, imembers im
2911             WHERE l.list_id = im.list_id
2912               AND im.member_type = :atype AND im.member_id = :aid;
2913         EXEC SQL OPEN csr117b;
2914         while(1) {
2915             EXEC SQL FETCH csr117b
2916               INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2917             if(sqlca.sqlcode != 0) break;
2918             (*action)(6, rargv, actarg);
2919             found++;
2920         }
2921         EXEC SQL CLOSE csr117b;
2922     }
2923
2924     if (ingres_errno) return(mr_errcode);
2925     if (!found) return(MR_NO_MATCH);
2926     return(MR_SUCCESS);
2927 }
2928
2929
2930 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2931  * the five flags associated with each list.  It will return the name of
2932  * each list that meets the quailifications.  It does this by building a
2933  * where clause based on the arguments, then doing a retrieve.
2934  */
2935
2936 static char *lflags[5] = { "active", "publicflg", "hidden", "maillist", "grouplist" };
2937
2938 int qualified_get_lists(q, argv, cl, action, actarg)
2939     struct query *q;
2940     char *argv[];
2941     client *cl;
2942     int (*action)();
2943     int actarg;
2944 {
2945     return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2946                          "l", "name", lflags));
2947 }
2948
2949
2950 /* get_members_of_list - this gets only direct members */
2951  
2952 get_members_of_list(q, argv, cl, action, actarg)
2953     struct query *q;
2954     char *argv[];
2955     client *cl;
2956     int (*action)();
2957     int actarg;
2958 {
2959     return(gmol_internal(q, argv, cl, action, actarg, 1));
2960 }
2961  
2962 /* get_end_members_of_list - this gets direct or indirect members */
2963  
2964 get_end_members_of_list(q, argv, cl, action, actarg)
2965     struct query *q;
2966     char *argv[];
2967     client *cl;
2968     int (*action)();
2969     int actarg;
2970 {
2971     return(gmol_internal(q, argv, cl, action, actarg, 0));
2972 }
2973  
2974 /** gmol_internal - optimized query for retrieval of list members
2975  **   used by both get_members_of_list and get_end_members_of_list
2976  **
2977  ** Inputs:
2978  **   argv[0] - list_id
2979  **
2980  ** Description:
2981  **   - retrieve USER members, then LIST members, then STRING members
2982  **/
2983
2984 gmol_internal(q, argv, cl, action, actarg, flag)
2985     struct query *q;
2986     char *argv[];
2987     client *cl;
2988     int (*action)();
2989     int actarg;
2990     int flag;
2991 {
2992     EXEC SQL BEGIN DECLARE SECTION;
2993     int list_id, member_id, direct;
2994     char member_name[129], member_type[9];
2995     EXEC SQL END DECLARE SECTION;
2996     char *targv[2];
2997     int members;
2998     struct save_queue *sq;
2999
3000     /* true/false flag indicates whether to display only direct members. */
3001     if (flag)
3002       direct = 0;
3003     else
3004       direct = -1;
3005
3006     list_id = *(int *)argv[0];
3007     members = 0;
3008     sq = sq_create();
3009
3010     EXEC SQL DECLARE csr118 CURSOR FOR
3011       SELECT member_type, member_id FROM imembers
3012         WHERE list_id = :list_id AND direct > :direct;
3013     EXEC SQL OPEN csr118;
3014     while(1) {
3015         EXEC SQL FETCH csr118 INTO :member_type, :member_id;
3016         if (sqlca.sqlcode != 0) break;
3017         if (members++ > 49)
3018           break;
3019         sq_save_data(sq, ((int)member_type[0] << 24) | (member_id & 0xffffff));
3020     }
3021     EXEC SQL CLOSE csr118;
3022
3023     if (members <= 49) {
3024         targv[1] = malloc(0);
3025         while (sq_remove_data(sq, &member_id)) {
3026             switch (member_id >> 24) {
3027             case 'U':
3028                 targv[0] = "USER";
3029                 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
3030                 (*action)(2, targv, actarg);
3031                 break;
3032             case 'L':
3033                 targv[0] = "LIST";
3034                 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
3035                 (*action)(2, targv, actarg);
3036                 break;
3037             case 'S':
3038                 targv[0] = "STRING";
3039                 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
3040                 (*action)(2, targv, actarg);
3041                 break;
3042             case 'K':
3043                 targv[0] = "KERBEROS";
3044                 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
3045                 (*action)(2, targv, actarg);
3046                 break;
3047             default:
3048                 sq_destroy(sq);
3049                 return(MR_INTERNAL);
3050             }
3051         }
3052         free(targv[1]);
3053         sq_destroy(sq);
3054         return(MR_SUCCESS);
3055     }
3056     sq_destroy(sq);
3057
3058     targv[1] = member_name;
3059     targv[0] = "USER";
3060     EXEC SQL DECLARE csr119 CURSOR FOR
3061       SELECT u.login FROM users u, imembers im
3062         WHERE im.list_id = :list_id AND im.member_type = 'USER'
3063           AND im.member_id = u.users_id AND im.direct > :direct
3064         ORDER BY 1;
3065     EXEC SQL OPEN csr119;
3066     while(1) {
3067         EXEC SQL FETCH csr119 INTO :member_name;
3068         if(sqlca.sqlcode != 0) break;
3069         (*action)(2, targv, actarg);
3070     }
3071     EXEC SQL CLOSE csr119;
3072     if (ingres_errno) return(mr_errcode);
3073
3074     targv[0] = "LIST";
3075     EXEC SQL DECLARE csr120 CURSOR FOR
3076       SELECT l.name FROM list l, imembers im
3077         WHERE im.list_id = :list_id AND im.member_type='LIST'
3078           AND im.member_id = l.list_id AND im.direct > :direct
3079         ORDER BY 1;
3080     EXEC SQL OPEN csr120;
3081     while(1) {
3082         EXEC SQL FETCH csr120 INTO :member_name;
3083         if(sqlca.sqlcode != 0) break;
3084         (*action)(2, targv, actarg);
3085     }
3086     EXEC SQL CLOSE csr120;
3087     if (ingres_errno) return(mr_errcode);
3088
3089     targv[0] = "STRING";
3090     EXEC SQL DECLARE csr121 CURSOR FOR
3091       SELECT CHAR(str.string) FROM strings str, imembers im
3092         WHERE im.list_id = :list_id AND im.member_type='STRING'
3093           AND im.member_id = str.string_id AND im.direct > :direct
3094         ORDER BY 1;
3095     EXEC SQL OPEN csr121;
3096     while(1) {
3097         EXEC SQL FETCH csr121 INTO :member_name;
3098         if(sqlca.sqlcode != 0) break;
3099         (*action)(2, targv, actarg);
3100     }
3101     EXEC SQL CLOSE csr121;
3102     if (ingres_errno) return(mr_errcode);
3103
3104     targv[0] = "KERBEROS";
3105     EXEC SQL DECLARE csr122 CURSOR FOR
3106       SELECT CHAR(str.string) FROM strings str, imembers im
3107         WHERE im.list_id = :list_id AND im.member_type='KERBEROS'
3108           AND im.member_id = str.string_id 
3109           AND im.direct > :direct
3110         ORDER BY 1;
3111     EXEC SQL OPEN csr122;
3112     while(1) {
3113         EXEC SQL FETCH csr122 INTO :member_name;
3114         if(sqlca.sqlcode != 0) break;
3115         (*action)(2, targv, actarg);
3116     }
3117     EXEC SQL CLOSE csr122;
3118     if (ingres_errno) return(mr_errcode);
3119
3120     return(MR_SUCCESS);
3121 }
3122
3123
3124 /* count_members_of_list: this is a simple query, but it cannot be done
3125  * through the dispatch table.
3126  */
3127
3128 int count_members_of_list(q, argv, cl, action, actarg)
3129     struct query *q;
3130     char *argv[];
3131     client *cl;
3132     int (*action)();
3133     int actarg;
3134 {
3135     EXEC SQL BEGIN DECLARE SECTION;
3136     int  list, ct = 0;
3137     EXEC SQL END DECLARE SECTION;
3138     char *rargv[1], countbuf[5];
3139
3140     list = *(int *)argv[0];
3141     rargv[0] = countbuf;
3142     EXEC SQL REPEATED SELECT count (*) INTO :ct FROM imembers
3143       WHERE list_id = :list AND direct=1;
3144     if (ingres_errno) return(mr_errcode);
3145     sprintf(countbuf, "%d", ct);
3146     (*action)(1, rargv, actarg);
3147     return(MR_SUCCESS);
3148 }
3149
3150
3151 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
3152  * the three flags associated with each service.  It will return the name of
3153  * each service that meets the quailifications.  It does this by building a
3154  * where clause based on the arguments, then doing a retrieve.
3155  */
3156
3157 static char *sflags[3] = { "enable", "inprogress", "harderror" };
3158
3159 int qualified_get_server(q, argv, cl, action, actarg)
3160     struct query *q;
3161     char *argv[];
3162     client *cl;
3163     int (*action)();
3164     int actarg;
3165 {
3166     return(qualified_get(q, argv, action, actarg, "s.name != ''",
3167                          "s", "name", sflags));
3168 }
3169
3170
3171 /* generic qualified get routine, used by qualified_get_lists,
3172  * qualified_get_server, and qualified_get_serverhost.
3173  *   Args:
3174  *      start - a simple where clause, must not be empty
3175  *      range - the name of the range variable
3176  *      field - the field to return
3177  *      flags - an array of strings, names of the flag variables
3178  */
3179
3180 int qualified_get(q, argv, action, actarg, start, range, field, flags)
3181     struct query *q;
3182     char *argv[];
3183     int (*action)();
3184     int actarg;
3185     char *start;
3186     char *range;
3187     char *field;
3188     char *flags[];
3189 {
3190     char name[33], qual[256];
3191     int rowcount=0, i;
3192     char *rargv[1], buf[32];
3193
3194     strcpy(qual, start);
3195     for (i = 0; i < q->argc; i++) {
3196         if (!strcmp(argv[i], "TRUE")) {
3197             sprintf(buf, " AND %s.%s != 0", range, flags[i]);
3198             (void) strcat(qual, buf);
3199         } else if (!strcmp(argv[i], "FALSE")) {
3200             sprintf(buf, " AND %s.%s = 0", range, flags[i]);
3201             (void) strcat(qual, buf);
3202         }
3203     }
3204
3205     rargv[0] = SQLDA->sqlvar[0].sqldata;
3206     sprintf(stmt_buf,"SELECT CHAR(%s.%s) FROM %s %s WHERE %s",range,field,q->rtable,range,qual);
3207     EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3208     if(sqlca.sqlcode)
3209       return(MR_INTERNAL);
3210     EXEC SQL DECLARE csr123 CURSOR FOR stmt;
3211     EXEC SQL OPEN csr123;
3212     while(1) {
3213         EXEC SQL FETCH csr123 USING DESCRIPTOR :SQLDA;
3214         if(sqlca.sqlcode != 0) break;
3215         rowcount++;
3216         (*action)(1, rargv, actarg);
3217     }
3218     EXEC SQL CLOSE csr123;
3219     if (ingres_errno) return(mr_errcode);
3220     if (rowcount == 0)
3221       return(MR_NO_MATCH);
3222     return(MR_SUCCESS);
3223 }
3224
3225
3226 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
3227  * the five flags associated with each serverhost.  It will return the name of
3228  * each service and host that meets the quailifications.  It does this by
3229  * building a where clause based on the arguments, then doing a retrieve.
3230  */
3231
3232 static char *shflags[6] = { "service", "enable", "override", "success",
3233                             "inprogress", "hosterror" };
3234
3235 int qualified_get_serverhost(q, argv, cl, action, actarg)
3236     struct query *q;
3237     char *argv[];
3238     client *cl;
3239     int (*action)();
3240     int actarg;
3241 {
3242     EXEC SQL BEGIN DECLARE SECTION;
3243     char sname[33], mname[33], qual[256];
3244     EXEC SQL END DECLARE SECTION;
3245     char *rargv[2], buf[32];
3246     int i, rowcount;
3247
3248     sprintf(qual, "m.mach_id = sh.mach_id AND sh.service = uppercase('%s')",
3249             argv[0]);
3250     for (i = 1; i < q->argc; i++) {
3251         if (!strcmp(argv[i], "TRUE")) {
3252             sprintf(buf, " AND sh.%s != 0", shflags[i]);
3253             strcat(qual, buf);
3254         } else if (!strcmp(argv[i], "FALSE")) {
3255             sprintf(buf, " AND sh.%s = 0", shflags[i]);
3256             strcat(qual, buf);
3257         }
3258     }
3259
3260     rargv[0] = sname;
3261     rargv[1] = mname;
3262     EXEC SQL DECLARE csr124 CURSOR FOR
3263       SELECT sh.service, m.name FROM serverhosts sh, machine m
3264         WHERE :qual;
3265     EXEC SQL OPEN csr124;
3266     while(1) {
3267         EXEC SQL FETCH csr124 INTO :sname, :mname;
3268         if(sqlca.sqlcode != 0) break;
3269         rowcount++;
3270         (*action)(2, rargv, actarg);
3271     }
3272     EXEC SQL CLOSE csr124;
3273
3274     if (ingres_errno) return(mr_errcode);
3275     if (rowcount == 0)
3276       return(MR_NO_MATCH);
3277     return(MR_SUCCESS);
3278 }
3279
3280
3281 /* register_user - change user's login name and allocate a pobox, group,
3282  * filesystem, and quota for them.  The user's status must start out as 0,
3283  * and is left as 2.  Arguments are: user's UID, new login name, and user's
3284  * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY,
3285  * MR_FS_STAFF, MR_FS_MISC).
3286  */
3287
3288 register_user(q, argv, cl)
3289     struct query *q;
3290     char **argv;
3291     client *cl;
3292 {
3293     EXEC SQL BEGIN DECLARE SECTION;
3294     char *login, dir[65], *entity, directory[129], machname[33];
3295     int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
3296     int size, alloc, pid, ostatus, nstatus, gidval, fsidval, npidval;
3297     static int m_id = 0, def_quota = 0;
3298     EXEC SQL END DECLARE SECTION;
3299     char buffer[256], *aargv[3];
3300
3301     entity = cl->entity;
3302     who = cl->client_id;
3303
3304     uid = atoi(argv[0]);
3305     login = argv[1];
3306     utype = atoi(argv[2]);
3307
3308     /* find user */
3309     EXEC SQL REPEATED SELECT users_id, status INTO :users_id, :ostatus
3310       FROM users
3311       WHERE uid = :uid AND (status=0 OR status=5 OR status=6);
3312
3313     if (sqlca.sqlerrd[2] == 0)
3314       return(MR_NO_MATCH);
3315     if (sqlca.sqlerrd[2] > 1)
3316       return(MR_NOT_UNIQUE);
3317
3318     /* check new login name */
3319     EXEC SQL REPEATED SELECT login INTO :cdummy FROM users
3320       WHERE login = LEFT(:login,SIZE(login)) AND users_id != :users_id;
3321     if (ingres_errno) return(mr_errcode);
3322     if (sqlca.sqlerrd[2] > 0) return(MR_IN_USE);
3323     EXEC SQL REPEATED SELECT name INTO :cdummy FROM list
3324       WHERE name = LEFT(:login,SIZE(name));
3325     if (ingres_errno) return(mr_errcode);
3326     if (sqlca.sqlerrd[2] > 0) return(MR_IN_USE);
3327     EXEC SQL REPEATED SELECT label INTO :cdummy FROM filesys
3328       WHERE label = LEFT(:login,SIZE(label));
3329     if (ingres_errno) return(mr_errcode);
3330     if (sqlca.sqlerrd[2] > 0) return(MR_IN_USE);
3331     com_err(whoami, 0, "login name OK");
3332
3333     /* choose place for pobox, put in mid */
3334     EXEC SQL DECLARE csr130 CURSOR FOR
3335       SELECT sh.mach_id, m.name FROM serverhosts sh, machine m
3336       WHERE sh.service='POP' AND sh.mach_id=m.mach_id
3337         AND sh.value2 - sh.value1 =
3338           (SELECT MAX(value2 - value1) FROM serverhosts
3339             WHERE service = 'POP');
3340     EXEC SQL OPEN csr130;
3341     EXEC SQL FETCH csr130 INTO :mid, :machname;
3342     if (sqlca.sqlerrd[2] == 0) {
3343         EXEC SQL CLOSE csr130;
3344         if (ingres_errno) return(mr_errcode);
3345         return(MR_NO_POBOX);
3346     } else {
3347         EXEC SQL CLOSE csr130;
3348         if (ingres_errno) return(mr_errcode);
3349     }
3350
3351     /* change login name, set pobox */
3352     sprintf(buffer, "u.users_id = %d", users_id);
3353     incremental_before("users", buffer, 0);
3354     nstatus = 2;
3355     if (ostatus == 5 || ostatus == 6)
3356       nstatus = 1;
3357     EXEC SQL REPEATED UPDATE users SET login = :login, status = :nstatus,
3358         modtime='now', modby = :who, modwith = :entity, potype='POP',
3359         pop_id = :mid, pmodtime='now', pmodby = :who, pmodwith = :entity
3360       WHERE users_id = :users_id;
3361
3362     if (ingres_errno) return(mr_errcode);
3363     if (sqlca.sqlerrd[2] != 1)
3364       return(MR_INTERNAL);
3365     set_pop_usage(mid, 1);
3366     com_err(whoami, 0, "set login name to %s and pobox to %s", login,
3367             strtrim(machname));
3368     incremental_after("users", buffer, 0);
3369
3370     /* create group list */
3371     if (set_next_object_id("gid", "list", 1))
3372       return(MR_NO_ID);
3373     if (set_next_object_id("list_id", "list", 0))
3374       return(MR_NO_ID);
3375     EXEC SQL REPEATED SELECT value INTO :list_id FROM numvalues
3376       WHERE name='list_id';
3377     if (ingres_errno) return(mr_errcode);
3378     if (sqlca.sqlerrd[2] != 1)
3379       return(MR_INTERNAL);
3380     incremental_clear_before();
3381     EXEC SQL SELECT value INTO :gidval FROM numvalues WHERE name = 'gid';
3382     EXEC SQL REPEATED INSERT INTO list
3383              (name, list_id, active, publicflg, hidden, maillist, grouplist,
3384               gid, description, acl_type, acl_id,
3385               modtime, modby, modwith)
3386       VALUES (:login, :list_id, 1, 0, 0, 0, 1,
3387               :gidval, 'User Group', 'USER', :users_id,
3388               'now', :who, :entity);
3389     if (ingres_errno) return(mr_errcode);
3390     if (sqlca.sqlerrd[2] != 1)
3391       return(MR_INTERNAL);
3392     sprintf(buffer, "l.list_id = %d", list_id);
3393     incremental_after("list", buffer, 0);
3394     aargv[0] = (char *) list_id;
3395     aargv[1] = "USER";
3396     aargv[2] = (char *) users_id;
3397     incremental_clear_before();
3398     EXEC SQL REPEATED INSERT INTO imembers
3399              (list_id, member_type, member_id, ref_count, direct)
3400       VALUES (:list_id, 'USER', :users_id, 1, 1);
3401     if (ingres_errno) return(mr_errcode);
3402     if (sqlca.sqlerrd[2] != 1)
3403       return(MR_INTERNAL);
3404     incremental_after("members", 0, aargv);
3405
3406     if (m_id == 0) {
3407         /* Cell Name (I know, it shouldn't be hard coded...) */
3408         strcpy(machname, "ATHENA.MIT.EDU");
3409         EXEC SQL SELECT mach_id INTO :m_id FROM machine 
3410           WHERE name = :machname;
3411     }
3412
3413     /* create filesystem */
3414     if (set_next_object_id("filsys_id", "filesys", 0))
3415       return(MR_NO_ID);
3416     incremental_clear_before();
3417     if (islower(login[0]) && islower(login[1])) {
3418         sprintf(directory, "/afs/athena.mit.edu/user/%c/%c/%s",
3419                 login[0], login[1], login);
3420     } else {
3421         sprintf(directory, "/afs/athena.mit.edu/user/other/%s", login);
3422     }
3423  
3424     EXEC SQL SELECT value INTO :fsidval FROM numvalues
3425       WHERE numvalues.name='filsys_id';
3426     EXEC SQL REPEATED INSERT INTO filesys
3427         (filsys_id, phys_id, label, type, mach_id, name,
3428          mount, access, comments, owner, owners, createflg,
3429          lockertype, modtime, modby, modwith)
3430       VALUES
3431         (:fsidval, 0, :login, 'AFS', :m_id, :directory,
3432          '/mit/'+:login, 'w', 'User Locker', :users_id, :list_id, 1,
3433          'HOMEDIR', 'now', :who, :entity);
3434
3435     if (ingres_errno) return(mr_errcode);
3436     if (sqlca.sqlerrd[2]  != 1)
3437       return(MR_INTERNAL);
3438     sprintf(buffer,"fs.filsys_id = %d",fsidval);
3439     incremental_after("filesys", buffer, 0);
3440
3441     /* set quota */
3442     if (def_quota == 0) {
3443         EXEC SQL REPEATED SELECT value INTO :def_quota FROM numvalues
3444           WHERE name='def_quota';
3445         if (ingres_errno) return(mr_errcode);
3446         if (sqlca.sqlerrd[2] != 1)
3447           return(MR_NO_QUOTA);
3448         
3449     }
3450     incremental_clear_before();
3451     EXEC SQL REPEATED INSERT INTO quota
3452         (entity_id, filsys_id, type, quota, phys_id, modtime, modby, modwith)
3453       VALUES
3454         (0, :fsidval, 'ANY', :def_quota, 0, 'now', :who, :entity);
3455     if (ingres_errno) return(mr_errcode);
3456     if (sqlca.sqlerrd[2] != 1)
3457       return(MR_INTERNAL);
3458     aargv[0] = login;
3459     aargv[1] = "ANY";
3460     aargv[2] = login;
3461     sprintf(buffer, "q.entity_id = 0 and q.filsys_id = %d and q.type = 'ANY'", fsidval);
3462     incremental_after("quota", buffer, aargv);
3463     com_err(whoami, 0, "quota of %d assigned", def_quota);
3464     if (ingres_errno) return(mr_errcode);
3465
3466     cache_entry(login, "USER", users_id);
3467
3468     EXEC SQL REPEATED UPDATE tblstats SET updates=updates+1, modtime='now'
3469       WHERE table_name='users';
3470     EXEC SQL REPEATED UPDATE tblstats SET appends=appends+1, modtime='now'
3471       WHERE table_name='list' OR table_name='filesys' OR table_name='quota';
3472     if (ingres_errno) return(mr_errcode);
3473     return(MR_SUCCESS);
3474 }
3475
3476
3477
3478 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
3479  **
3480  ** Inputs:
3481  **   id of machine
3482  **   delta (will be +/- 1)
3483  **
3484  ** Description:
3485  **   - incr/decr value field in serverhosts table for pop/mach_id
3486  **
3487  **/
3488
3489 static int set_pop_usage(id, cnt)
3490     EXEC SQL BEGIN DECLARE SECTION;
3491     int id;
3492     int cnt;
3493     EXEC SQL END DECLARE SECTION;
3494 {
3495     EXEC SQL REPEATED UPDATE serverhosts SET value1 = value1 + :cnt
3496       WHERE serverhosts.service = 'POP' AND serverhosts.mach_id = :id;
3497
3498     if (ingres_errno) return(mr_errcode);
3499     return(MR_SUCCESS);
3500 }
3501
3502
3503 \f
3504 /* Validation Routines */
3505
3506 validate_row(q, argv, v)
3507     register struct query *q;
3508     char *argv[];
3509     register struct validate *v;
3510 {
3511     EXEC SQL BEGIN DECLARE SECTION;
3512     char *name;
3513     char qual[128];
3514     int rowcount;
3515     EXEC SQL END DECLARE SECTION;
3516
3517     /* build where clause */
3518     build_qual(v->qual, v->argc, argv, qual);
3519
3520     if (log_flags & LOG_VALID)
3521         /* tell the logfile what we're doing */
3522         com_err(whoami, 0, "validating row: %s", qual);
3523
3524     /* look for the record */
3525     sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",q->rtable,qual);
3526     EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3527     if(sqlca.sqlcode)
3528       return(MR_INTERNAL);
3529     EXEC SQL DECLARE csr126 CURSOR FOR stmt;
3530     EXEC SQL OPEN csr126;
3531     EXEC SQL FETCH csr126 USING DESCRIPTOR :SQLDA;
3532     EXEC SQL CLOSE csr126;
3533     rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3534
3535     if (ingres_errno) return(mr_errcode);
3536     if (rowcount == 0) return(MR_NO_MATCH);
3537     if (rowcount > 1) return(MR_NOT_UNIQUE);
3538     return(MR_EXISTS);
3539 }
3540
3541 validate_fields(q, argv, vo, n)
3542     struct query *q;
3543     register char *argv[];
3544     register struct valobj *vo;
3545     register int n;
3546 {
3547     register int status;
3548
3549     while (--n >= 0) {
3550         switch (vo->type) {
3551         case V_NAME:
3552             if (log_flags & LOG_VALID)
3553                 com_err(whoami, 0, "validating %s in %s: %s",
3554                     vo->namefield, vo->table, argv[vo->index]);
3555             status = validate_name(argv, vo);
3556             break;
3557
3558         case V_ID:
3559             if (log_flags & LOG_VALID)
3560                 com_err(whoami, 0, "validating %s in %s: %s",
3561                     vo->idfield, vo->table, argv[vo->index]);
3562             status = validate_id(q, argv, vo);
3563             break;
3564
3565         case V_DATE:
3566             if (log_flags & LOG_VALID)
3567                 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
3568             status = validate_date(argv, vo);
3569             break;
3570
3571         case V_TYPE:
3572             if (log_flags & LOG_VALID)
3573                 com_err(whoami, 0, "validating %s type: %s",
3574                     vo->table, argv[vo->index]);
3575             status = validate_type(argv, vo);
3576             break;
3577
3578         case V_TYPEDATA:
3579             if (log_flags & LOG_VALID)
3580                 com_err(whoami, 0, "validating typed data (%s): %s",
3581                     argv[vo->index - 1], argv[vo->index]);
3582             status = validate_typedata(q, argv, vo);
3583             break;
3584
3585         case V_RENAME:
3586             if (log_flags & LOG_VALID)
3587                 com_err(whoami, 0, "validating rename %s in %s",
3588                         argv[vo->index], vo->table);
3589             status = validate_rename(argv, vo);
3590             break;
3591
3592         case V_CHAR:
3593             if (log_flags & LOG_VALID)
3594               com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
3595             status = validate_chars(argv[vo->index]);
3596             break;
3597
3598         case V_SORT:
3599             status = MR_EXISTS;
3600             break;
3601
3602         case V_LOCK:
3603             status = lock_table(vo);
3604             break;
3605
3606         case V_WILD:
3607             status = convert_wildcards(argv[vo->index]);
3608             break;
3609
3610         case V_UPWILD:
3611             status = convert_wildcards_uppercase(argv[vo->index]);
3612             break;
3613
3614         }
3615
3616         if (status != MR_EXISTS) return(status);
3617         vo++;
3618     }
3619
3620     if (ingres_errno) return(mr_errcode);
3621     return(MR_SUCCESS);
3622 }
3623
3624
3625 /* validate_chars: verify that there are no illegal characters in
3626  * the string.  Legal characters are printing chars other than
3627  * ", *, ?, \, [ and ].
3628  */
3629 static int illegalchars[] = {
3630     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
3631     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
3632     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
3633     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
3634     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
3635     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
3636     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
3637     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
3638     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3639     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3640     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3641     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3642     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3643     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3644     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3645     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3646 };
3647
3648 validate_chars(s)
3649 register char *s;
3650 {
3651     while (*s)
3652       if (illegalchars[*s++])
3653         return(MR_BAD_CHAR);
3654     return(MR_EXISTS);
3655 }
3656
3657
3658 validate_id(q, argv, vo)
3659     struct query *q;
3660     char *argv[];
3661     register struct valobj *vo;
3662 {
3663     EXEC SQL BEGIN DECLARE SECTION;
3664     char *name, *tbl, *namefield, *idfield;
3665     int id, rowcount;
3666     EXEC SQL END DECLARE SECTION;
3667     int status;
3668     register char *c;
3669
3670     name = argv[vo->index];
3671     tbl = vo->table;
3672     namefield = vo->namefield;
3673     idfield = vo->idfield;
3674
3675     if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
3676         !strcmp(tbl, "machine") ||
3677         !strcmp(tbl, "filesys") ||
3678         !strcmp(tbl, "list") ||
3679         !strcmp(tbl, "cluster") ||
3680         !strcmp(tbl, "strings")) {
3681         if (!strcmp(tbl, "machine"))
3682           for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3683         status = name_to_id(name, tbl, &id);
3684         if (status == 0) {
3685             *(int *)argv[vo->index] = id;
3686             return(MR_EXISTS);
3687         } else if (status == MR_NO_MATCH && !strcmp(tbl, "strings") &&
3688                    (q->type == APPEND || q->type == UPDATE)) {
3689             EXEC SQL SELECT value INTO :id FROM numvalues
3690               WHERE name = 'strings_id';
3691             id++;
3692             EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3693             EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3694             cache_entry(name, "STRING", id);
3695             *(int *)argv[vo->index] = id;
3696             return(MR_EXISTS);
3697         } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
3698           return(vo->error);
3699         else
3700           return(status);
3701     }
3702
3703     if (!strcmp(namefield, "uid")) {
3704         sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = %s",idfield,tbl,namefield,name);
3705     } else {
3706         sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",idfield,tbl,namefield,name);
3707     }
3708     EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3709     if(sqlca.sqlcode)
3710       return(MR_INTERNAL);
3711     EXEC SQL DECLARE csr127 CURSOR FOR stmt;
3712     EXEC SQL OPEN csr127;
3713     rowcount=0;
3714     EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3715     if(sqlca.sqlcode == 0) {
3716         rowcount++;
3717         EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3718         if(sqlca.sqlcode == 0) rowcount++;
3719     }
3720     EXEC SQL CLOSE csr127;
3721     if (ingres_errno)
3722       return(mr_errcode);
3723
3724     if (rowcount != 1) return(vo->error);
3725     bcopy(SQLDA->sqlvar[0].sqldata,argv[vo->index],sizeof(int));
3726     return(MR_EXISTS);
3727 }
3728
3729 validate_name(argv, vo)
3730     char *argv[];
3731     register struct valobj *vo;
3732 {
3733     EXEC SQL BEGIN DECLARE SECTION;
3734     char *name, *tbl, *namefield;
3735     int rowcount;
3736     EXEC SQL END DECLARE SECTION;
3737     register char *c;
3738
3739     name = argv[vo->index];
3740     tbl = vo->table;
3741     namefield = vo->namefield;
3742     if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
3743         for (c = name; *c; c++)
3744           if (islower(*c))
3745             *c = toupper(*c);
3746     }
3747     sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
3748             tbl,tbl,namefield,name);
3749     EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3750     if(sqlca.sqlcode)
3751       return(MR_INTERNAL);
3752     EXEC SQL DECLARE csr128 CURSOR FOR stmt;
3753     EXEC SQL OPEN csr128;
3754     EXEC SQL FETCH csr128 USING DESCRIPTOR :SQLDA;
3755     rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3756     EXEC SQL CLOSE csr128;
3757
3758     if (ingres_errno) return(mr_errcode);
3759     return ((rowcount == 1) ? MR_EXISTS : vo->error);
3760 }
3761
3762 validate_date(argv, vo)
3763     char *argv[];
3764     struct valobj *vo;
3765 {
3766     EXEC SQL BEGIN DECLARE SECTION;
3767     char *idate;
3768     double dd;
3769     int errorno;
3770     EXEC SQL END DECLARE SECTION;
3771
3772     idate = argv[vo->index];
3773     EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
3774
3775     if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
3776     return(MR_EXISTS);
3777 }
3778
3779
3780 validate_rename(argv, vo)
3781 char *argv[];
3782 struct valobj *vo;
3783 {
3784     EXEC SQL BEGIN DECLARE SECTION;
3785     char *name, *tbl, *namefield, *idfield;
3786     int id;
3787     EXEC SQL END DECLARE SECTION;
3788     int status;
3789     register char *c;
3790
3791     c = name = argv[vo->index];
3792     while (*c)
3793       if (illegalchars[*c++])
3794         return(MR_BAD_CHAR);
3795     tbl = vo->table;
3796     /* minor kludge to upcasify machine names */
3797     if (!strcmp(tbl, "machine"))
3798         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3799     namefield = vo->namefield;
3800     idfield = vo->idfield;
3801     id = -1;
3802     if (idfield == 0) {
3803         if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3804           return(MR_EXISTS);
3805         sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = LEFT('%s',SIZE(%s))",
3806                 namefield,tbl,namefield,name,namefield);
3807         EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3808         if(sqlca.sqlcode)
3809           return(MR_INTERNAL);
3810         EXEC SQL DECLARE csr129 CURSOR FOR stmt;
3811         EXEC SQL OPEN csr129;
3812         EXEC SQL FETCH csr129 USING DESCRIPTOR :SQLDA;
3813         if(sqlca.sqlcode == 0) id=1; else id=0;
3814         EXEC SQL CLOSE csr129;
3815
3816         if (ingres_errno) return(mr_errcode);
3817         if (id)
3818           return(vo->error);
3819         else
3820           return(MR_EXISTS);
3821     }
3822     status = name_to_id(name, tbl, &id);
3823     if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3824       return(MR_EXISTS);
3825     else
3826       return(vo->error);
3827 }
3828
3829
3830 validate_type(argv, vo)
3831     char *argv[];
3832     register struct valobj *vo;
3833 {
3834     EXEC SQL BEGIN DECLARE SECTION;
3835     char *typename;
3836     char *val;
3837     EXEC SQL END DECLARE SECTION;
3838     register char *c;
3839
3840     typename = vo->table;
3841     c = val = argv[vo->index];
3842     while (*c) {
3843         if (illegalchars[*c++])
3844           return(MR_BAD_CHAR);
3845     }
3846
3847     /* uppercase type fields */
3848     for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
3849
3850     EXEC SQL SELECT trans INTO :cdummy FROM alias
3851       WHERE name = :typename AND type='TYPE' AND trans = :val;
3852     if (ingres_errno) return(mr_errcode);
3853     return (sqlca.sqlerrd[2] ? MR_EXISTS : vo->error);
3854 }
3855
3856 /* validate member or type-specific data field */
3857
3858 validate_typedata(q, argv, vo)
3859     register struct query *q;
3860     register char *argv[];
3861     register struct valobj *vo;
3862 {
3863     EXEC SQL BEGIN DECLARE SECTION;
3864     char *name;
3865     char *field_type;
3866     char data_type[129];
3867     int id;
3868     EXEC SQL END DECLARE SECTION;
3869     int status;
3870     char *index();
3871     register char *c;
3872
3873     /* get named object */
3874     name = argv[vo->index];
3875
3876     /* get field type string (known to be at index-1) */
3877     field_type = argv[vo->index-1];
3878
3879     /* get corresponding data type associated with field type name */
3880     EXEC SQL SELECT trans INTO :data_type FROM alias
3881       WHERE name = :field_type AND type='TYPEDATA';
3882     if (ingres_errno) return(mr_errcode);
3883     if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
3884
3885     /* now retrieve the record id corresponding to the named object */
3886     if (index(data_type, ' '))
3887         *index(data_type, ' ') = 0;
3888     if (!strcmp(data_type, "user")) {
3889         /* USER */
3890         status = name_to_id(name, data_type, &id);
3891         if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3892           return(MR_USER);
3893         if (status) return(status);
3894     } else if (!strcmp(data_type, "list")) {
3895         /* LIST */
3896         status = name_to_id(name, data_type, &id);
3897         if (status && status == MR_NOT_UNIQUE)
3898           return(MR_LIST);
3899         if (status == MR_NO_MATCH) {
3900             /* if idfield is non-zero, then if argv[0] matches the string
3901              * that we're trying to resolve, we should get the value of
3902              * numvalues.[idfield] for the id.
3903              */
3904             if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3905                 set_next_object_id(q->validate->object_id, q->rtable, 0);
3906                 name = vo->idfield;
3907                 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
3908                   WHERE name = :name;
3909                 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
3910             } else
3911               return(MR_LIST);
3912         } else if (status) return(status);
3913     } else if (!strcmp(data_type, "machine")) {
3914         /* MACHINE */
3915         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3916         status = name_to_id(name, data_type, &id);
3917         if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3918           return(MR_MACHINE);
3919         if (status) return(status);
3920     } else if (!strcmp(data_type, "string")) {
3921         /* STRING */
3922         status = name_to_id(name, data_type, &id);
3923         if (status && status == MR_NOT_UNIQUE)
3924           return(MR_STRING);
3925         if (status == MR_NO_MATCH) {
3926             if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3927             EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
3928             id++;
3929             EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3930             EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3931             cache_entry(name, "STRING", id);
3932         } else if (status) return(status);
3933     } else if (!strcmp(data_type, "none")) {
3934         id = 0;
3935     } else {
3936         return(MR_TYPE);
3937     }
3938
3939     /* now set value in argv */
3940     *(int *)argv[vo->index] = id;
3941
3942     return (MR_EXISTS);
3943 }
3944
3945
3946 /* Lock the table named by the validation object */
3947
3948 lock_table(vo)
3949 struct valobj *vo;
3950 {
3951     sprintf(stmt_buf,"UPDATE %s SET modtime='now' WHERE %s.%s = 0",
3952             vo->table,vo->table,vo->idfield);
3953     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
3954     if (ingres_errno) return(mr_errcode);
3955     if (sqlca.sqlerrd[2] != 1)
3956       return(vo->error);
3957     else
3958       return(MR_EXISTS);
3959 }
3960
3961
3962 /* Check the database at startup time.  For now this just resets the
3963  * inprogress flags that the DCM uses.
3964  */
3965
3966 sanity_check_database()
3967 {
3968 }
3969
3970
3971 /* Dynamic SQL support routines */
3972 MR_SQLDA_T *mr_alloc_SQLDA()
3973 {
3974     MR_SQLDA_T *it;
3975     short *null_indicators;
3976     register int j;
3977
3978     if((it=(MR_SQLDA_T *)malloc(sizeof(MR_SQLDA_T)))==NULL) {
3979         com_err(whoami, MR_NO_MEM, "setting up SQLDA");
3980         exit(1);
3981     }
3982
3983     if((null_indicators=(short *)calloc(QMAXARGS,sizeof(short)))==NULL) {
3984         com_err(whoami, MR_NO_MEM, "setting up SQLDA null indicators");
3985         exit(1);
3986     }
3987
3988     for(j=0; j<QMAXARGS; j++) {
3989         if((it->sqlvar[j].sqldata=malloc(sizeof(short)+QMAXARGSIZE))==NULL) {
3990             com_err(whoami, MR_NO_MEM, "setting up SQLDA variables");
3991             exit(1);
3992         }
3993         it->sqlvar[j].sqllen=QMAXARGSIZE;
3994         it->sqlvar[j].sqlind=null_indicators+j;
3995         null_indicators[j]=0;
3996     }
3997     it->sqln=QMAXARGS;
3998     return it;
3999 }
4000
4001
4002 /* Use this after FETCH USING DESCRIPTOR one or more
4003  * result columns may contain NULLs.  This routine is
4004  * not currently needed, since db/schema creates all
4005  * columns with a NOT NULL WITH DEFAULT clause.
4006  *
4007  * This is currently dead flesh, since no Moira columns
4008  * allow null values; all use default values.
4009  */
4010 mr_fix_nulls_in_SQLDA(da)
4011     MR_SQLDA_T *da;
4012 {
4013     register IISQLVAR *var;
4014     register int j;
4015     int *intp;
4016
4017     for(j=0, var=da->sqlvar; j<da->sqld; j++, var++) {
4018         switch(var->sqltype) {
4019           case -IISQ_CHA_TYPE:
4020             if(*var->sqlind)
4021               *var->sqldata='\0';
4022             break;
4023           case -IISQ_INT_TYPE:
4024             if(*var->sqlind) {
4025                 intp=(int *)var->sqldata;
4026                 *intp=0;
4027             }
4028             break;
4029         }
4030     }
4031 }
4032
4033 /* prefetch_value():
4034  * This routine fetches an appropriate value from the numvalues table.
4035  * It is a little hack to get around the fact that SQL doesn't let you
4036  * do something like INSERT INTO table (foo) VALUES (other_table.bar).
4037  *
4038  * It is called from the query table as (*v->pre_rtn)(q,Argv,cl) or
4039  * from within a setup_...() routine with the appropriate arguments.
4040  *
4041  * Correct functioning of this routine may depend on the assumption
4042  * that this query is an APPEND.
4043  */
4044
4045 prefetch_value(q,argv,cl)
4046     struct query *q;
4047     char **argv;
4048     client *cl;
4049 {
4050     EXEC SQL BEGIN DECLARE SECTION;
4051     char *name = q->validate->object_id;
4052     int value;
4053     EXEC SQL END DECLARE SECTION;
4054     int status, limit, argc;
4055
4056     /* set next object id, limiting it if necessary */
4057     if(!strcmp(name, "uid") || !strcmp(name, "gid"))
4058       limit = 1; /* So far as I know, this isn't needed.  Just CMA. */
4059     else
4060       limit = 0;
4061     if((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
4062       return(status);
4063
4064     /* fetch object id */
4065     EXEC SQL SELECT value INTO :value FROM numvalues WHERE name=:name;
4066     if(ingres_errno) return(mr_errcode);
4067     if(sqlca.sqlerrd[2] != 1) return(MR_INTERNAL);
4068
4069     argc = q->argc + q->vcnt;   /* end of Argv for APPENDs */
4070     sprintf(argv[argc],"%d",value);  /** Could save this step by changing tlist from %s to %d **/
4071
4072     return(MR_SUCCESS);
4073 }
4074
4075 /* prefetch_filesys():
4076  * Fetches the phys_id from filesys based on the filsys_id in argv[0].
4077  * Appends the filsys_id and the phys_id to the argv so they can be
4078  * referenced in an INSERT into a table other than filesys.  Also
4079  * see comments at prefetch_value().
4080  *
4081  * Assumes the existence of a row where filsys_id = argv[0], since a
4082  * filesys label has already been resolved to a filsys_id.
4083  */
4084 prefetch_filesys(q,argv,cl)
4085     struct query *q;
4086     char **argv;
4087     client *cl;
4088 {
4089     EXEC SQL BEGIN DECLARE SECTION;
4090     int fid,phid;
4091     EXEC SQL END DECLARE SECTION;
4092     int argc;
4093
4094     fid = *(int *)argv[0];
4095     EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
4096     if(ingres_errno) return(mr_errcode);
4097
4098     argc=q->argc+q->vcnt;
4099     sprintf(argv[argc++],"%d",phid);
4100     sprintf(argv[argc],"%d",fid);
4101
4102     return(MR_SUCCESS);
4103 }
4104
4105 /* Convert normal Unix-style wildcards to SQL voodoo */
4106 convert_wildcards(arg)
4107     char *arg;
4108 {
4109     static char buffer[QMAXARGSIZE];
4110     register char *s, *d;
4111
4112     for(d=buffer,s=arg;*s;s++) {
4113         switch(*s) {
4114           case '*': *d++='%'; *d++='%'; break;
4115           case '?': *d++='_'; break;
4116           case '_':
4117           case '[':
4118           case ']': *d++='*'; *d++ = *s; break;
4119           case '%': *d++='*'; *d++='%'; *d++='%'; break;
4120           default: *d++ = *s; break;
4121         }
4122     }
4123     *d='\0';
4124
4125     /* Copy back into argv */
4126     strcpy(arg,buffer);
4127
4128     return(MR_EXISTS);
4129 }
4130
4131 /* This version includes uppercase conversion, for things like gmac.
4132  * This is necessary because "LIKE" doesn't work with "uppercase()".
4133  * Including it in a wildcard routine saves making two passes over
4134  * the argument string.
4135  */
4136 convert_wildcards_uppercase(arg)
4137     char *arg;
4138 {
4139     static char buffer[QMAXARGSIZE];
4140     register char *s, *d;
4141
4142     for(d=buffer,s=arg;*s;s++) {
4143         switch(*s) {
4144           case '*': *d++='%'; *d++='%'; break;
4145           case '?': *d++='_'; break;
4146           case '_':
4147           case '[':
4148           case ']': *d++='*'; *d++ = *s; break;
4149           case '%': *d++='*'; *d++='%'; *d++='%'; break;
4150           default: *d++=toupper(*s); break;       /* This is the only diff. */
4151         }
4152     }
4153     *d='\0';
4154
4155     /* Copy back into argv */
4156     strcpy(arg,buffer);
4157
4158     return(MR_EXISTS);
4159 }
4160
4161
4162 /* Looks like it's time to build an abstraction barrier, Yogi */
4163 mr_select_any(stmt)
4164     EXEC SQL BEGIN DECLARE SECTION; 
4165     char *stmt;
4166     EXEC SQL END DECLARE SECTION; 
4167 {
4168     int result=0;
4169
4170     EXEC SQL PREPARE stmt FROM :stmt;
4171     EXEC SQL DESCRIBE stmt INTO :SQLDA;
4172     if(SQLDA->sqld==0)                       /* Not a SELECT */
4173         return(MR_INTERNAL);        
4174     EXEC SQL DECLARE csr CURSOR FOR stmt;
4175     EXEC SQL OPEN csr;
4176     EXEC SQL FETCH csr USING DESCRIPTOR :SQLDA;
4177     if(sqlca.sqlcode==0) 
4178         result=MR_EXISTS;
4179     else if((sqlca.sqlcode<0) && mr_errcode)
4180         result=mr_errcode;
4181     else
4182         result=0;
4183     EXEC SQL CLOSE csr;
4184     return(result);
4185
4186
4187
4188 /* eof:qsupport.dc */
This page took 0.383834 seconds and 5 git commands to generate.