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