]> andersk Git - moira.git/blob - server/qsupport.dc
695d2c1e0e2a08779a2c7d0a1118330611d83211
[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     0, 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     EXEC SQL OPEN csr101;
917     while(1) {
918         EXEC SQL FETCH csr101 INTO :var_phys_id, :dir;
919         if(sqlca.sqlcode != 0) break;
920         cp1 = name;
921         cp2 = dir;
922         while (*cp2) {
923             if (*cp1++ != *cp2) break;
924             cp2++;
925         }
926         if (*cp2 == 0) {
927             status = MR_SUCCESS;
928             break;
929         }
930     }
931     EXEC SQL CLOSE csr101;
932     if (ingres_errno)
933         return(mr_errcode);
934     return(status);
935 }
936
937
938 /* setup_dfil: free any quota records and fsgroup info associated with
939  * a filesystem when it is deleted.  Also adjust the allocation numbers.
940  */
941
942 setup_dfil(q, argv, cl)
943     struct query  *q;
944     char **argv;
945     client *cl;
946 {
947     EXEC SQL BEGIN DECLARE SECTION;
948     int id, total, phys_id;
949     short int none;
950     EXEC SQL END DECLARE SECTION;
951
952     id = *(int *)argv[0];
953     EXEC SQL REPEATED SELECT SUM (quota) INTO :total:none FROM quota
954       WHERE filsys_id = :id;
955
956     if(none) total=0;
957
958     /** What if there are multiple phys_id's per f/s? (bad data) **/
959     EXEC SQL REPEATED SELECT phys_id INTO :phys_id FROM filesys
960       WHERE filsys_id = :id;
961     EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated - :total
962       WHERE nfsphys_id = :phys_id;
963
964     if(!none) {
965         EXEC SQL REPEATED DELETE FROM quota WHERE filsys_id = :id;
966     }
967     EXEC SQL REPEATED DELETE FROM fsgroup WHERE filsys_id = :id;
968     EXEC SQL REPEATED DELETE FROM fsgroup WHERE group_id = :id;
969     if (ingres_errno) return(mr_errcode);
970     return(MR_SUCCESS);
971 }
972
973
974 /* setup_dnfp: check to see that the nfs physical partition does not have
975  * any filesystems assigned to it before allowing it to be deleted.
976  */
977
978 setup_dnfp(q, argv, cl)
979     struct query  *q;
980     char **argv;
981     client *cl;
982 {
983     EXEC SQL BEGIN DECLARE SECTION;
984     int id, cnt;
985     char *dir;
986     EXEC SQL END DECLARE SECTION;
987
988     id = *(int *)argv[0];
989     dir = argv[1];
990     EXEC SQL REPEATED SELECT label INTO :cnt FROM filesys fs, nfsphys np
991       WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
992         AND np.mach_id = :id AND np.dir = :dir;
993     if (cnt > 0)
994       return(MR_IN_USE);
995     if (ingres_errno)
996       return(mr_errcode);
997     return(MR_SUCCESS);
998 }
999
1000
1001 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
1002  *   argv[0] = filsys_id
1003  *   argv[1] = type if "update_quota" or "delete_quota"
1004  *   argv[2 or 1] = users_id or list_id
1005  */
1006
1007 setup_dqot(q, argv, cl)
1008     struct query  *q;
1009     char **argv;
1010     client *cl;
1011 {
1012     EXEC SQL BEGIN DECLARE SECTION;
1013     int quota, fs, id, physid;
1014     char *qtype;
1015     EXEC SQL END DECLARE SECTION;
1016
1017     fs = *(int *)argv[0];
1018     if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
1019         qtype = argv[1];
1020         id = *(int *)argv[2];
1021     } else {
1022         qtype = "USER";
1023         id = *(int *)argv[1];
1024     }
1025
1026     EXEC SQL REPEATED SELECT quota INTO :quota FROM quota
1027       WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
1028     EXEC SQL REPEATED SELECT phys_id INTO :physid FROM filesys 
1029       WHERE filsys_id = :fs;
1030     EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated - :quota
1031       WHERE nfsphys_id = :physid;
1032
1033     if (ingres_errno) return(mr_errcode);
1034     return(MR_SUCCESS);
1035 }
1036
1037
1038 /* setup_sshi: don't exclusive lock the machine table during
1039  * set_server_host_internal.
1040  */
1041 /** Not allowed under (INGRES) SQL **/
1042 setup_sshi(q, argv, cl)
1043     struct query  *q;
1044     char **argv;
1045     client *cl;
1046 {
1047 #if 0
1048 #ifsql INGRES
1049     EXEC SQL set lockmode session where readlock = system;
1050 #endsql
1051 #endif
1052     return(MR_SUCCESS);
1053 }
1054
1055
1056 /* setup add_kerberos_user_mapping: add the string to the string
1057  * table if necessary.
1058  */
1059
1060 setup_akum(q, argv, cl)
1061 struct query *q;
1062 char **argv;
1063 client *cl;
1064 {
1065     EXEC SQL BEGIN DECLARE SECTION;
1066     int id, rowcount;
1067     char *name;
1068     EXEC SQL END DECLARE SECTION;
1069
1070     name = argv[1];
1071     if (name_to_id(name, "STRING", &id) != MR_SUCCESS) {
1072         if (q->type != APPEND) return(MR_STRING);
1073         EXEC SQL SELECT value INTO :id FROM numvalues
1074           WHERE name = 'strings_id';
1075         id++;
1076         EXEC SQL UPDATE numvalues SET value = :id
1077           WHERE name = 'strings_id';
1078         EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
1079         cache_entry(name, "STRING", id);
1080     }
1081     if (ingres_errno) return(mr_errcode);
1082     *(int *)argv[1] = id;
1083     return(MR_SUCCESS);
1084 }
1085
1086
1087 \f
1088 /* FOLLOWUP ROUTINES */
1089
1090 /* generic set_modtime routine.  This takes the table name from the query,
1091  * and will update the modtime, modby, and modwho fields in the entry in
1092  * the table whose name field matches argv[0].
1093  */
1094
1095 set_modtime(q, argv, cl)
1096     struct query *q;
1097     char *argv[];
1098     client *cl;
1099 {
1100     char *name, *entity, *table;
1101     int who;
1102
1103     entity = cl->entity;
1104     who = cl->client_id;
1105     table = q->rtable;
1106     name = argv[0];
1107
1108     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);
1109     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1110
1111     return(MR_SUCCESS);
1112 }
1113
1114 /* generic set_modtime_by_id routine.  This takes the table name from
1115  * the query, and the id name from the validate record,
1116  * and will update the modtime, modby, and modwho fields in the entry in
1117  * the table whose id matches argv[0].
1118  */
1119
1120 set_modtime_by_id(q, argv, cl)
1121     struct query *q;
1122     char **argv;
1123     client *cl;
1124 {
1125     char *entity, *table, *id_name;
1126     int who, id;
1127
1128     entity = cl->entity;
1129     who = cl->client_id;
1130     table = q->rtable;
1131     id_name = q->validate->object_id;
1132
1133     id = *(int *)argv[0];
1134     sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, \
1135 modwith = '%s' WHERE %s.%s = %d",table,who,entity,table,id_name,id);
1136     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1137     return(MR_SUCCESS);
1138 }
1139
1140
1141 /* Sets the finger modtime on a user record.  The users_id will be in argv[0].
1142  */
1143
1144 set_finger_modtime(q, argv, cl)
1145     struct query *q;
1146     char *argv[];
1147     client *cl;
1148 {
1149     EXEC SQL BEGIN DECLARE SECTION;
1150     int users_id, who;
1151     char *entity;
1152     EXEC SQL END DECLARE SECTION;
1153
1154     entity = cl->entity;
1155     who = cl->client_id;
1156     users_id = *(int *)argv[0];
1157
1158     EXEC SQL UPDATE users SET fmodtime='now', fmodby = :who, fmodwith = :entity
1159       WHERE users.users_id = :users_id;
1160
1161    return(MR_SUCCESS);
1162 }
1163
1164
1165 /* Sets the pobox modtime on a user record.  The users_id will be in argv[0].
1166  */
1167
1168 set_pobox_modtime(q, argv, cl)
1169     struct query *q;
1170     char **argv;
1171     client *cl;
1172 {
1173     EXEC SQL BEGIN DECLARE SECTION;
1174     int users_id, who;
1175     char *entity;
1176     EXEC SQL END DECLARE SECTION;
1177
1178     entity = cl->entity;
1179     who = cl->client_id;
1180     users_id = *(int *)argv[0];
1181
1182     EXEC SQL UPDATE users SET pmodtime='now', pmodby = :who, pmodwith = :entity
1183       WHERE users.users_id = :users_id;
1184
1185     return(MR_SUCCESS);
1186 }
1187
1188
1189 /* Like set_modtime, but uppercases the name first.
1190  */
1191
1192 set_uppercase_modtime(q, argv, cl)
1193     struct query *q;
1194     char **argv;
1195     client *cl;
1196 {
1197     char *name, *entity, *table;
1198     int who;
1199
1200     entity = cl->entity;
1201     who = cl->client_id;
1202     table = q->rtable;
1203     name = argv[0];
1204
1205     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);
1206     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1207
1208     return(MR_SUCCESS);
1209 }
1210
1211
1212 /* Sets the modtime on the machine whose mach_id is in argv[0].  This routine
1213  * is necessary for add_machine_to_cluster becuase the table that query
1214  * operates on is "mcm", not "machine".
1215  */
1216
1217 set_mach_modtime_by_id(q, argv, cl)
1218     struct query *q;
1219     char **argv;
1220     client *cl;
1221 {
1222     EXEC SQL BEGIN DECLARE SECTION;
1223     char *entity;
1224     int who, id;
1225     EXEC SQL END DECLARE SECTION;
1226
1227     entity = cl->entity;
1228     who = cl->client_id;
1229     id = *(int *)argv[0];
1230     EXEC SQL UPDATE machine SET modtime='now', modby = :who, modwith = :entity
1231       WHERE machine.mach_id = :id;
1232
1233     return(MR_SUCCESS);
1234 }
1235
1236
1237 /* Sets the modtime on the cluster whose mach_id is in argv[0].  This routine
1238  * is necessary for add_cluster_data and delete_cluster_data becuase the
1239  * table that query operates on is "svc", not "cluster".
1240  */
1241
1242 set_cluster_modtime_by_id(q, argv, cl)
1243     struct query *q;
1244     char **argv;
1245     client *cl;
1246 {
1247     EXEC SQL BEGIN DECLARE SECTION;
1248     char *entity;
1249     int who, id;
1250     EXEC SQL END DECLARE SECTION;
1251
1252     entity = cl->entity;
1253     who = cl->client_id;
1254
1255     id = *(int *)argv[0];
1256     EXEC SQL UPDATE cluster SET modtime='now', modby = :who, modwith = :entity
1257       WHERE cluster.clu_id = :id;
1258     return(MR_SUCCESS);
1259 }
1260
1261
1262 /* sets the modtime on the serverhost where the service name is in argv[0]
1263  * and the mach_id is in argv[1].
1264  */
1265
1266 set_serverhost_modtime(q, argv, cl)
1267     struct query *q;
1268     char **argv;
1269     client *cl;
1270 {
1271     EXEC SQL BEGIN DECLARE SECTION;
1272     char *entity, *serv;
1273     int who, id;
1274     EXEC SQL END DECLARE SECTION;
1275
1276     entity = cl->entity;
1277     who = cl->client_id;
1278
1279     serv = argv[0];
1280     id = *(int *)argv[1];
1281     EXEC SQL UPDATE serverhosts
1282       SET modtime = 'now', modby = :who, modwith = :entity
1283       WHERE service = :serv AND mach_id = :id;
1284     return(MR_SUCCESS);
1285 }
1286
1287
1288 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1289  * directory name is in argv[1].
1290  */
1291
1292 set_nfsphys_modtime(q, argv, cl)
1293     struct query *q;
1294     char **argv;
1295     client *cl;
1296 {
1297     EXEC SQL BEGIN DECLARE SECTION;
1298     char *entity, *dir;
1299     int who, id;
1300     EXEC SQL END DECLARE SECTION;
1301
1302     entity = cl->entity;
1303     who = cl->client_id;
1304
1305     id = *(int *)argv[0];
1306     dir = argv[1];
1307     EXEC SQL UPDATE nfsphys SET modtime = 'now', modby = :who, modwith = :entity
1308       WHERE dir = :dir AND mach_id = :id;
1309     return(MR_SUCCESS);
1310 }
1311
1312
1313 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1314  * label.
1315  */
1316
1317 set_filesys_modtime(q, argv, cl)
1318     struct query *q;
1319     char *argv[];
1320     client *cl;
1321 {
1322     EXEC SQL BEGIN DECLARE SECTION;
1323     char *label, *entity;
1324     int who;
1325     EXEC SQL END DECLARE SECTION;
1326
1327     entity = cl->entity;
1328     who = cl->client_id;
1329
1330     label = argv[0];
1331     if (!strcmp(q->shortname, "ufil"))
1332       label = argv[1];
1333
1334     EXEC SQL UPDATE filesys SET modtime = 'now', modby = :who,
1335         modwith = :entity, phys_id = :var_phys_id
1336       WHERE label = LEFT(:label,SIZE(label));
1337     return(MR_SUCCESS);
1338 }
1339
1340
1341 /* sets the modtime on a zephyr class, where argv[0] contains the class
1342  * name.
1343  */
1344
1345 set_zephyr_modtime(q, argv, cl)
1346     struct query *q;
1347     char *argv[];
1348     client *cl;
1349 {
1350     EXEC SQL BEGIN DECLARE SECTION;
1351     char *class, *entity;
1352     int who;
1353     EXEC SQL END DECLARE SECTION;
1354
1355     entity = cl->entity;
1356     who = cl->client_id;
1357
1358     class = argv[0];
1359
1360     EXEC SQL UPDATE zephyr SET modtime = 'now', modby = :who, modwith = :entity
1361       WHERE class = LEFT(:class,SIZE(class));
1362
1363     return(MR_SUCCESS);
1364 }
1365
1366
1367 /* fixes the modby field.  This will be the second to last thing in the
1368  * argv, the argv length is determined from the query structure.  It is
1369  * passed as a pointer to an integer.  This will either turn it into a
1370  * username, or # + the users_id.
1371  */
1372 followup_fix_modby(q, sq, v, action, actarg, cl)
1373     struct query *q;
1374     register struct save_queue *sq;
1375     struct validate *v;
1376     register int (*action)();
1377     register int actarg;
1378     client *cl;
1379 {
1380     register int i, j;
1381     char **argv, *malloc();
1382     int id, status;
1383
1384     i = q->vcnt - 2;
1385     while (sq_get_data(sq, &argv)) {
1386         id = atoi(argv[i]);
1387         if (id > 0)
1388           status = id_to_name(id, "USER", &argv[i]);
1389         else
1390           status = id_to_name(-id, "STRING", &argv[i]);
1391         if (status && status != MR_NO_MATCH)
1392           return(status);
1393         (*action)(q->vcnt, argv, actarg);
1394         for (j = 0; j < q->vcnt; j++)
1395           free(argv[j]);
1396         free(argv);
1397     }
1398     sq_destroy(sq);
1399     return(MR_SUCCESS);
1400 }
1401
1402
1403 /* After retrieving a user account, fix the modby field and signature.
1404  * The modby field is the second to last thing in the
1405  * argv, the argv length is determined from the query structure.  It is
1406  * passed as a pointer to an integer.  This will either turn it into a
1407  * username, or # + the users_id.  Only "gua*" queries have a signature,
1408  * these are ones with U_END return values.  "gub*" queries also use this
1409  * routine but don't have a signature.
1410  */
1411 followup_guax(q, sq, v, action, actarg, cl)
1412     struct query *q;
1413     register struct save_queue *sq;
1414     struct validate *v;
1415     register int (*action)();
1416     register int actarg;
1417     client *cl;
1418 {
1419     register int i, j;
1420     char **argv, *malloc();
1421 #ifdef GDSS
1422     unsigned char sigbuf[256];
1423     char *kname;
1424     SigInfo  si;
1425     EXEC SQL BEGIN DECLARE SECTION; 
1426     int timestamp, who;
1427     char *login;
1428     varchar struct { short data_size; char data_buf[257];} rsig;
1429     EXEC SQL END DECLARE SECTION; 
1430 #endif /* GDSS */
1431     int id, status;
1432
1433     i = q->vcnt - 2;
1434     while (sq_get_data(sq, &argv)) {
1435 #ifdef DEBUG
1436         com_err(whoami, 0, "argv[SIGNATURE] = \"%s\"", argv[U_SIGNATURE]);
1437 #endif /* DEBUG */
1438         id = atoi(argv[i]);
1439         if (id > 0)
1440           status = id_to_name(id, "USER", &argv[i]);
1441         else
1442           status = id_to_name(-id, "STRING", &argv[i]);
1443         if (status && status != MR_NO_MATCH)
1444           return(status);
1445 #ifdef GDSS
1446         if (q->vcnt == U_END && strlen(argv[U_SIGNATURE])) {
1447             login = argv[U_NAME];
1448             EXEC SQL REPEATED SELECT signature, sigdate, sigwho 
1449               INTO :rsig, :timestamp, :who FROM users
1450               WHERE login = :login;
1451             /** What about (INGRES) error handling? **/
1452             kname = malloc(1);
1453             status = id_to_name(who, "STRING", &kname);
1454             si.timestamp = timestamp;
1455             si.SigInfoVersion = 0; /* XXXXX this isn't used */
1456             kname_parse(si.pname, si.pinst, si.prealm, kname);
1457             free(kname);
1458             rsig.data_buf[rsig.data_size] = 0;
1459             si.rawsig = (unsigned char *)strsave(rsig.data_buf);
1460             if (log_flags & LOG_GDSS)
1461               com_err(whoami, 0, "rawsig length = %d, sig=\"%s\"", strlen(si.rawsig), si.rawsig);
1462             GDSS_Recompose(&si, sigbuf);
1463             free(si.rawsig);
1464             free(argv[U_SIGNATURE]);
1465             argv[U_SIGNATURE] = strsave(sigbuf);
1466             if (log_flags & LOG_GDSS)
1467               com_err(whoami, 0, "generated signature length %d", strlen(sigbuf));
1468         }
1469 #endif /* GDSS */
1470         (*action)(q->vcnt, argv, actarg);
1471         for (j = 0; j < q->vcnt; j++)
1472           free(argv[j]);
1473         free(argv);
1474     }
1475     sq_destroy(sq);
1476     return(MR_SUCCESS);
1477 }
1478
1479
1480 /**
1481  ** followup_ausr - add finger and pobox entries, set_user_modtime
1482  **
1483  ** Inputs:
1484  **     argv[0] - login (add_user)
1485  **     argv[3] - last name
1486  **     argv[4] - first name
1487  **     argv[5] - middle name
1488  **
1489  **/
1490
1491 followup_ausr(q, argv, cl)
1492     struct query *q;
1493     char *argv[];
1494     client *cl;
1495 {
1496     EXEC SQL BEGIN DECLARE SECTION;
1497     int who, status, id;
1498     char *login, *entity, *src, *dst, *name;
1499     char fullname[129];
1500     EXEC SQL END DECLARE SECTION;
1501 #ifdef GDSS
1502     char databuf[32], *kname_unparse();
1503     EXEC SQL BEGIN DECLARE SECTION;
1504     char rawsig[128];
1505     int sigwho, timestamp;
1506     EXEC SQL END DECLARE SECTION;
1507     SigInfo si;
1508 #endif /* GDSS */
1509
1510     /* build fullname */
1511     if (strlen(argv[4]) && strlen(argv[5]))
1512         sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1513     else if (strlen(argv[4]))
1514         sprintf(fullname, "%s %s", argv[4], argv[3]);
1515     else
1516         sprintf(fullname, "%s", argv[3]);
1517
1518 #ifdef GDSS
1519       if (q->vcnt == U_END && *argv[U_SIGNATURE]) {
1520         sprintf(databuf, "%s:%s", argv[U_NAME], argv[U_MITID]);
1521         /* skip bytes for timestamp & kname */
1522         si.rawsig = (unsigned char *) rawsig;
1523         status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE], &si);
1524         if (strlen(rawsig) > mr_sig_length) {
1525             com_err(whoami, 0, "GDSS signature would be truncated.");  /** untested **/
1526             return(MR_INTERNAL);
1527         }
1528         if (status == 0) {
1529             name = kname_unparse(si.pname, si.pinst, si.prealm);
1530             status = name_to_id(name, "STRING", &sigwho);
1531             if (status == MR_NO_MATCH) {
1532                 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1533                   WHERE name='strings_id';
1534                 sigwho++;
1535                 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1536                   WHERE name='strings_id';
1537                 EXEC SQL INSERT INTO strings (string_id, string) 
1538                   VALUES (:sigwho, :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;
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         login = malloc(1);
1615         status = id_to_name(id, "USER", &login);
1616         sprintf(databuf, "%s:%s", login, argv[U_MITID+1]);
1617         free(login);
1618         /* skip bytes for timestamp & kname */
1619         si.rawsig = (unsigned char *) rawsig;
1620 #ifdef DEBUG
1621         com_err(whoami, 0, "verifying sig");
1622 #endif /* DEBUG */
1623         status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE+1], &si);
1624 #ifdef DEBUG
1625         com_err(whoami, 0, "verified");
1626 #endif /* DEBUG */
1627         if (strlen(rawsig) > mr_sig_length) {
1628             com_err(whoami, 0, "GDSS signature would be truncated.");  /** untested **/
1629             return(MR_INTERNAL);
1630         }
1631         if (status == 0) {
1632             name = kname_unparse(si.pname, si.pinst, si.prealm);
1633             status = name_to_id(name, "STRING", &sigwho);
1634             if (status == MR_NO_MATCH) {
1635                 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1636                   WHERE name='strings_id';
1637                 sigwho++;
1638                 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1639                   WHERE name='strings_id';
1640                 EXEC SQL INSERT INTO strings (string_id, string) 
1641                   VALUES (:sigwho, :name);
1642             } else if (status)
1643               return(status);
1644             timestamp = si.timestamp;
1645         } else {
1646             if (log_flags & LOG_GDSS)
1647               hex_dump(argv[U_SIGNATURE+1]);
1648             return(gdss2et(status));
1649         }
1650     } else {
1651         rawsig[0] = 0;
1652         sigwho = 0;
1653         timestamp = 0;
1654     }
1655 #endif /* GDSS */
1656  
1657     /* create finger entry, pobox & set modtime on user */
1658
1659 #ifdef GDSS
1660     EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity,
1661         signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho
1662       WHERE users_id = :id;
1663 #else /* GDSS */
1664     EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity
1665       WHERE users_id = :id;
1666 #endif /* GDSS */
1667     return(MR_SUCCESS);
1668 }
1669  
1670  
1671 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1672  * type in argv[1].  Then completes the upcall to the user.
1673  *
1674  * argv[2] is of the form "123:234" where the first integer is the machine
1675  * ID if it is a pop box, and the second is the string ID if it is an SMTP
1676  * box.  argv[1] should be "POP", "SMTP", or "NONE".  Boxes of type NONE
1677  * are skipped.
1678  */
1679
1680 followup_gpob(q, sq, v, action, actarg, cl)
1681     register struct query *q;
1682     register struct save_queue *sq;
1683     register struct validate *v;
1684     register int (*action)();
1685     int actarg;
1686     client *cl;
1687 {
1688     char **argv, *index();
1689     char *ptype, *p;
1690     int mid, sid, status, i;
1691
1692     /* for each row */
1693     while (sq_get_data(sq, &argv)) {
1694         mr_trim_args(2, argv);
1695         ptype = argv[1];
1696         p = index(argv[2], ':');
1697         *p++ = 0;
1698         mid = atoi(argv[2]);
1699         sid = atoi(p);
1700
1701         if (!strcmp(ptype, "POP")) {
1702             status = id_to_name(mid, "MACHINE", &argv[2]);
1703             if (status == MR_NO_MATCH)
1704               return(MR_MACHINE);
1705         } else if (!strcmp(ptype, "SMTP")) {
1706             status = id_to_name(sid, "STRING", &argv[2]);
1707             if (status == MR_NO_MATCH)
1708               return(MR_STRING);
1709         } else /* ptype == "NONE" */ {
1710             goto skip;
1711         }
1712         if (status) return(status);
1713
1714         if (!strcmp(q->shortname, "gpob")) {
1715             sid = atoi(argv[4]);
1716             if (sid > 0)
1717               status = id_to_name(sid, "USER", &argv[4]);
1718             else
1719               status = id_to_name(-sid, "STRING", &argv[4]);
1720         }
1721         if (status && status != MR_NO_MATCH) return(status);
1722
1723         (*action)(q->vcnt, argv, actarg);
1724     skip:
1725         /* free saved data */
1726         for (i = 0; i < q->vcnt; i++)
1727             free(argv[i]);
1728         free(argv);
1729     }
1730
1731     sq_destroy(sq);
1732     return (MR_SUCCESS);
1733 }
1734
1735
1736 /* followup_glin: fix the ace_name in argv[8].  argv[7] will contain the
1737  * ace_type: "LIST", "USER", or "NONE".  Decode the id in argv[8] into the
1738  * proper name based on the type, and repace that string in the argv.
1739  * Also fixes the modby field by called followup_fix_modby.
1740  */
1741
1742 followup_glin(q, sq, v, action, actarg, cl)
1743     register struct query *q;
1744     register struct save_queue *sq;
1745     register struct validate *v;
1746     register int (*action)();
1747     int actarg;
1748     client *cl;
1749 {
1750     char **argv, *malloc(), *realloc(), *type;
1751     int id, i, idx, status;
1752
1753     idx = 8;
1754     if (!strcmp(q->shortname, "gsin"))
1755       idx = 12;
1756
1757     while (sq_get_data(sq, &argv)) {
1758         mr_trim_args(q->vcnt, argv);
1759
1760         id = atoi(argv[i = q->vcnt - 2]);
1761         if (id > 0)
1762           status = id_to_name(id, "USER", &argv[i]);
1763         else
1764           status = id_to_name(-id, "STRING", &argv[i]);
1765         if (status && status != MR_NO_MATCH)
1766           return(status);
1767
1768         id = atoi(argv[idx]);
1769         type = argv[idx - 1];
1770
1771         if (!strcmp(type, "LIST")) {
1772             status = id_to_name(id, "LIST", &argv[idx]);
1773         } else if (!strcmp(type, "USER")) {
1774             status = id_to_name(id, "USER", &argv[idx]);
1775         } else if (!strcmp(type, "KERBEROS")) {
1776             status = id_to_name(id, "STRING", &argv[idx]);
1777         } else if (!strcmp(type, "NONE")) {
1778             status = 0;
1779             free(argv[idx]);
1780             argv[idx] = strsave("NONE");
1781         } else {
1782             status = 0;
1783             free(argv[idx]);
1784             argv[idx] = strsave("???");
1785         }
1786         if (status && status != MR_NO_MATCH)
1787           return(status);
1788
1789         if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1790             argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1791             strcpy(argv[6], UNIQUE_GID);
1792         }
1793
1794         /* send the data */
1795         (*action)(q->vcnt, argv, actarg);
1796
1797         /* free saved data */
1798         for (i = 0; i < q->vcnt; i++)
1799             free(argv[i]);
1800         free(argv);
1801     }
1802
1803     sq_destroy(sq);
1804     return (MR_SUCCESS);
1805 }
1806
1807
1808 /* followup_gqot: Fix the entity name, directory name & modby fields
1809  *   argv[0] = filsys_id
1810  *   argv[1] = type
1811  *   argv[2] = entity_id
1812  *   argv[3] = ascii(quota)
1813  */
1814
1815 followup_gqot(q, sq, v, action, actarg, cl)
1816     struct query *q;
1817     register struct save_queue *sq;
1818     struct validate *v;
1819     register int (*action)();
1820     register int actarg;
1821     client *cl;
1822 {
1823     register int j;
1824     char **argv, *malloc();
1825     EXEC SQL BEGIN DECLARE SECTION;
1826     int id;
1827     char *name, *label;
1828     EXEC SQL END DECLARE SECTION;
1829     int status, idx;
1830
1831     if (!strcmp(q->name, "get_quota") ||
1832         !strcmp(q->name, "get_quota_by_filesys"))
1833       idx = 4;
1834     else
1835       idx = 3;
1836     while (sq_get_data(sq, &argv)) {
1837         if (idx == 4) {
1838             switch (argv[1][0]) {
1839             case 'U':
1840                 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1841                 break;
1842             case 'G':
1843             case 'L':
1844                 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1845                 break;
1846             case 'A':
1847                 free(argv[2]);
1848                 argv[2] = strsave("system:anyuser");
1849                 break;
1850             default:
1851                 id = atoi(argv[2]);
1852                 argv[2] = malloc(8);
1853                 sprintf(argv[2], "%d", id);
1854             }
1855         }
1856         id = atoi(argv[idx]);
1857         free(argv[idx]);
1858         argv[idx] = malloc(256);
1859         name = argv[idx];
1860         if (id == 0) {
1861             label = argv[0];
1862             EXEC SQL REPEATED SELECT name INTO :name FROM filesys
1863               WHERE label = :label;
1864         } else {
1865             EXEC SQL REPEATED SELECT dir INTO :name FROM nfsphys
1866               WHERE nfsphys_id = :id;
1867         }
1868         if (sqlca.sqlerrd[2] != 1) {
1869             sprintf(argv[idx], "#%d", id);
1870         }
1871
1872         id = atoi(argv[idx+3]);
1873         if (id > 0)
1874           status = id_to_name(id, "USER", &argv[idx+3]);
1875         else
1876           status = id_to_name(-id, "STRING", &argv[idx+3]);
1877         if (status && status != MR_NO_MATCH)
1878           return(status);
1879         (*action)(q->vcnt, argv, actarg);
1880         for (j = 0; j < q->vcnt; j++)
1881           free(argv[j]);
1882         free(argv);
1883     }
1884     sq_destroy(sq);
1885     return(MR_SUCCESS);
1886 }
1887
1888
1889 /* followup_aqot: Add allocation to nfsphys after creating quota.
1890  *   argv[0] = filsys_id
1891  *   argv[1] = type if "add_quota" or "update_quota"
1892  *   argv[2 or 1] = id
1893  *   argv[3 or 2] = ascii(quota)
1894  */
1895
1896 followup_aqot(q, argv, cl)
1897     struct query  *q;
1898     char **argv;
1899     client *cl;
1900 {
1901     EXEC SQL BEGIN DECLARE SECTION;
1902     int quota, id, fs, who, physid;
1903     char *entity, *qtype, *table_name;
1904     EXEC SQL END DECLARE SECTION;
1905     char incr_qual[60];
1906     char *incr_argv[2];
1907     int status;
1908
1909     table_name=q->rtable;
1910     fs = *(int *)argv[0];
1911     EXEC SQL REPEATED SELECT phys_id INTO :physid FROM filesys
1912       WHERE filsys_id = :fs;
1913     if(ingres_errno)
1914         return(mr_errcode);
1915
1916     if (!strcmp(q->shortname, "aqot") || !strcmp(q->shortname, "uqot")) {
1917         qtype = argv[1];
1918         id = *(int *)argv[2];
1919         quota = atoi(argv[3]);
1920         sprintf(incr_qual,"q.filsys_id = %d",fs);
1921     } else {
1922         qtype = "USER";
1923         id = *(int *)argv[1];
1924         quota = atoi(argv[2]);
1925         sprintf(incr_qual,"q.filsys_id=%d AND q.type='%s' AND q.entity_id=%d",
1926                 fs,qtype,id);
1927     }
1928
1929     /* quota case of incremental_{before|after} only looks at slot 1 */
1930     incr_argv[1]=qtype;
1931
1932     /* Follows one of many possible gross hacks to fix these particular
1933      * conflicts between what is possible in the query table and what 
1934      * is possible in SQL.    
1935      */
1936     if(q->type==APPEND) {
1937         incremental_clear_before();
1938         EXEC SQL INSERT INTO quota 
1939             (filsys_id, type, entity_id, quota, phys_id) 
1940           VALUES (:fs, :qtype, :id, :quota, :physid);
1941         incremental_after(table_name, incr_qual, incr_argv);    
1942     } else {
1943         incremental_before(table_name, incr_qual, incr_argv);
1944         EXEC SQL UPDATE quota SET quota = :quota
1945           WHERE filsys_id = :fs AND type = :qtype AND entity_id = :id;
1946         status = mr_errcode;
1947         incremental_after(table_name, incr_qual, incr_argv);
1948     }
1949
1950     if (ingres_errno)
1951         return(mr_errcode);
1952     flush_name(argv[0], q->rtable);  
1953     if(q->type==APPEND) {
1954         EXEC SQL UPDATE tblstats SET appends = appends + 1, modtime = 'now'
1955           WHERE table_name = :table_name;
1956     } else {
1957         EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = 'now'
1958           WHERE table_name = :table_name;
1959     }
1960         
1961     /* Proceed with original followup */
1962     who = cl->client_id;
1963     entity = cl->entity;
1964
1965     EXEC SQL REPEATED UPDATE quota
1966       SET modtime = 'now', modby = :who, modwith = :entity
1967       WHERE filsys_id = :fs and type = :qtype and entity_id = :id;
1968     EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated + :quota
1969       WHERE nfsphys_id = :physid;
1970     if (ingres_errno) return(mr_errcode);
1971     return(MR_SUCCESS);
1972 }
1973
1974
1975 /* Necessitated by the requirement of a correlation name by the incremental
1976  * routines, since query table deletes don't provide one. 
1977  */
1978 followup_dqot(q,argv,cl)
1979     struct query *q;
1980     char **argv;
1981     struct client *cl;
1982 {
1983     char *qtype;
1984     int id, fs;
1985     char *incr_argv[2];
1986     EXEC SQL BEGIN DECLARE SECTION; 
1987     char incr_qual[80];
1988     char *tblname;
1989     EXEC SQL END DECLARE SECTION; 
1990
1991     fs = *(int *)argv[0];
1992     if (!strcmp(q->shortname, "dqot")) {
1993         qtype = argv[1];
1994         id = *(int *)argv[2];
1995     } else {
1996         qtype = "USER";
1997         id = *(int *)argv[1];
1998     }
1999     sprintf(incr_qual,"q.filsys_id=%d AND q.type='%s' AND q.entity_id=%d",
2000             fs,qtype,id);
2001
2002     /* quota case of incremental_{before|after} only looks at slot 1 */
2003     incr_argv[1]=qtype;
2004
2005     incremental_before(q->rtable, incr_qual, incr_argv);
2006     EXEC SQL DELETE FROM quota q WHERE :incr_qual;
2007     incremental_clear_after();
2008
2009     if (ingres_errno) 
2010         return(mr_errcode);
2011     flush_name(argv[0], q->rtable);
2012
2013     tblname = q->rtable;
2014     EXEC SQL UPDATE tblstats SET deletes = deletes + 1, modtime = 'now'
2015       WHERE table_name = :tblname;
2016     return(MR_SUCCESS);
2017 }
2018
2019
2020 followup_gpce(q, sq, v, action, actarg, cl)
2021     struct query *q;
2022     register struct save_queue *sq;
2023     struct validate *v;
2024     register int (*action)();
2025     register int actarg;
2026     client *cl;
2027 {
2028     register int i, j;
2029     char **argv, *malloc();
2030     int id, status;
2031
2032     i = q->vcnt - 2;
2033     while (sq_get_data(sq, &argv)) {
2034         id = atoi(argv[PCAP_QSERVER]);
2035         status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
2036         if (status) return (status);
2037         id = atoi(argv[i]);
2038         if (id > 0)
2039           status = id_to_name(id, "USER", &argv[i]);
2040         else
2041           status = id_to_name(-id, "STRING", &argv[i]);
2042         if (status && status != MR_NO_MATCH)
2043           return(status);
2044         (*action)(q->vcnt, argv, actarg);
2045         for (j = 0; j < q->vcnt; j++)
2046           free(argv[j]);
2047         free(argv);
2048     }
2049     sq_destroy(sq);
2050     return(MR_SUCCESS);
2051 }
2052
2053
2054 /* followup_gzcl:
2055  */
2056
2057 followup_gzcl(q, sq, v, action, actarg, cl)
2058     register struct query *q;
2059     register struct save_queue *sq;
2060     register struct validate *v;
2061     register int (*action)();
2062     int actarg;
2063     client *cl;
2064 {
2065     int id, i, status;
2066     char **argv;
2067
2068     while (sq_get_data(sq, &argv)) {
2069         mr_trim_args(q->vcnt, argv);
2070
2071         id = atoi(argv[i = q->vcnt - 2]);
2072         if (id > 0)
2073           status = id_to_name(id, "USER", &argv[i]);
2074         else
2075           status = id_to_name(-id, "STRING", &argv[i]);
2076         if (status && status != MR_NO_MATCH)
2077           return(status);
2078
2079         for (i = 1; i < 8; i+=2) {
2080             id = atoi(argv[i+1]);
2081             if (!strcmp(argv[i], "LIST")) {
2082                 status = id_to_name(id, "LIST", &argv[i+1]);
2083             } else if (!strcmp(argv[i], "USER")) {
2084                 status = id_to_name(id, "USER", &argv[i+1]);
2085             } else if (!strcmp(argv[i], "KERBEROS")) {
2086                 status = id_to_name(id, "STRING", &argv[i+1]);
2087             } else if (!strcmp(argv[i], "NONE")) {
2088                 status = 0;
2089                 free(argv[i+1]);
2090                 argv[i+1] = strsave("NONE");
2091             } else {
2092                 status = 0;
2093                 free(argv[i+1]);
2094                 argv[i+1] = strsave("???");
2095             }
2096             if (status && status != MR_NO_MATCH)
2097               return(status);
2098         }
2099
2100         /* send the data */
2101         (*action)(q->vcnt, argv, actarg);
2102
2103         /* free saved data */
2104         for (i = 0; i < q->vcnt; i++)
2105             free(argv[i]);
2106         free(argv);
2107     }
2108     sq_destroy(sq);
2109     return(MR_SUCCESS);
2110 }
2111
2112
2113 /* followup_gsha:
2114  */
2115
2116 followup_gsha(q, sq, v, action, actarg, cl)
2117     register struct query *q;
2118     register struct save_queue *sq;
2119     register struct validate *v;
2120     register int (*action)();
2121     int actarg;
2122     client *cl;
2123 {
2124     char **argv;
2125     int i, id, status;
2126
2127     while (sq_get_data(sq, &argv)) {
2128         mr_trim_args(q->vcnt, argv);
2129
2130         id = atoi(argv[4]);
2131         if (id > 0)
2132           status = id_to_name(id, "USER", &argv[4]);
2133         else
2134           status = id_to_name(-id, "STRING", &argv[4]);
2135         if (status && status != MR_NO_MATCH)
2136           return(status);
2137
2138         id = atoi(argv[2]);
2139         if (!strcmp(argv[1], "LIST")) {
2140             status = id_to_name(id, "LIST", &argv[2]);
2141         } else if (!strcmp(argv[1], "USER")) {
2142             status = id_to_name(id, "USER", &argv[2]);
2143         } else if (!strcmp(argv[1], "KERBEROS")) {
2144             status = id_to_name(id, "STRING", &argv[2]);
2145         } else if (!strcmp(argv[1], "NONE")) {
2146             status = 0;
2147             free(argv[2]);
2148             argv[2] = strsave("NONE");
2149         } else {
2150             status = 0;
2151             free(argv[2]);
2152             argv[2] = strsave("???");
2153         }
2154         if (status && status != MR_NO_MATCH)
2155           return(status);
2156
2157         /* send the data */
2158         (*action)(q->vcnt, argv, actarg);
2159
2160         /* free saved data */
2161         for (i = 0; i < q->vcnt; i++)
2162             free(argv[i]);
2163         free(argv);
2164     }
2165     sq_destroy(sq);
2166     return(MR_SUCCESS);
2167 }
2168
2169
2170 \f
2171 /* Special query routines */
2172
2173 /* set_pobox - this does all of the real work.
2174  *       argv = user_id, type, box
2175  * if type is POP, then box should be a machine, and its ID should be put in
2176  * pop_id.  If type is SMTP, then box should be a string and its ID should
2177  * be put in box_id.  If type is NONE, then box doesn't matter.
2178  */
2179
2180 int set_pobox(q, argv, cl)
2181     struct query *q;
2182     char **argv;
2183     client *cl;
2184 {
2185     EXEC SQL BEGIN DECLARE SECTION;
2186     int user, id;
2187     char *box, potype[9];
2188     EXEC SQL END DECLARE SECTION;
2189     int status;
2190
2191     box = argv[2];
2192     user = *(int *)argv[0];
2193
2194     EXEC SQL REPEATED SELECT pop_id, potype INTO :id, :potype FROM users
2195       WHERE users_id = :user;
2196     if (ingres_errno) return(mr_errcode);
2197     if (!strcmp(strtrim(potype), "POP"))
2198       set_pop_usage(id, -1);
2199
2200     if (!strcmp(argv[1], "POP")) {
2201         status = name_to_id(box, "MACHINE", &id);
2202         if (status == MR_NO_MATCH)
2203           return(MR_MACHINE);
2204         else if (status)
2205           return(status);
2206         EXEC SQL REPEATED UPDATE users SET potype = 'POP', pop_id = :id
2207           WHERE users_id = :user;
2208         set_pop_usage(id, 1);
2209     } else if (!strcmp(argv[1], "SMTP")) {
2210         if (index(box, '/') || index(box, '|'))
2211           return(MR_BAD_CHAR);
2212         status = name_to_id(box, "STRING", &id);
2213         if (status == MR_NO_MATCH) {
2214             EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
2215               WHERE name='strings_id';
2216             id++;
2217             EXEC SQL REPEATED UPDATE numvalues SET value = :id
2218               WHERE name='strings_id';
2219             EXEC SQL INSERT INTO strings (string_id, string)
2220               VALUES (:id, :box);
2221         } else if (status)
2222           return(status);
2223         EXEC SQL REPEATED UPDATE users SET potype='SMTP', box_id = :id
2224           WHERE users_id = :user;
2225     } else /* argv[1] == "NONE" */ {
2226         EXEC SQL REPEATED UPDATE users SET potype='NONE'
2227           WHERE users_id = :user;
2228     }
2229
2230     set_pobox_modtime(q, argv, cl);
2231     EXEC SQL REPEATED UPDATE tblstats SET updates = updates+1, modtime='now'
2232       WHERE table_name='users';
2233     if (ingres_errno) return(mr_errcode);
2234     return(MR_SUCCESS);
2235 }
2236
2237
2238 /* get_list_info:  passed a wildcard list name, returns lots of stuff about
2239  * each list.  This is tricky:  first build a queue of all requested
2240  * data.  Rest of processing consists of fixing gid, ace_name, and modby.
2241  */
2242
2243 get_list_info(q, aargv, cl, action, actarg)
2244     register struct query *q;
2245     char **aargv;
2246     client *cl;
2247     register int (*action)();
2248     int actarg;
2249 {
2250     char *argv[13], *malloc(), *realloc();
2251     EXEC SQL BEGIN DECLARE SECTION;
2252     char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
2253     char maillist[5], grouplist[5], gid_str[6], acl_name[256], desc[256];
2254     char modtime[27], modby[256], modwith[9];
2255     int id, rowcount, acl_id, hid, modby_id;
2256     char qual[80];
2257     EXEC SQL END DECLARE SECTION;
2258     int returned, status;
2259     struct save_queue *sq, *sq_create();
2260
2261     returned = rowcount = 0;
2262     name = aargv[0];
2263     convert_wildcards(name);
2264
2265     sq = sq_create();
2266     sprintf(qual,"name LIKE '%s' ESCAPE '*'",name);
2267     optimize_sql_stmt(qual);
2268     EXEC SQL DECLARE csr102 CURSOR FOR SELECT list_id FROM list
2269       WHERE :qual;
2270     EXEC SQL OPEN csr102;
2271     while(1)
2272     {
2273         EXEC SQL FETCH csr102 INTO :id;
2274         if(sqlca.sqlcode!=0) break;
2275         sq_save_data(sq, id);
2276         rowcount++;
2277     }
2278     EXEC SQL CLOSE csr102;
2279
2280     if (ingres_errno) return(mr_errcode);
2281     if (rowcount == 0)
2282       return(MR_NO_MATCH);
2283
2284     argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
2285     argv[4] = maillist; argv[5] = grouplist; argv[6] = gid_str;
2286     argv[7] = acl_type; argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
2287
2288     while (sq_get_data(sq, &id)) {
2289         if (id == 0)
2290           continue;
2291         argv[6] = gid_str;
2292         EXEC SQL REPEATED SELECT name, CHAR(active), CHAR(publicflg),
2293             CHAR(hidden), hidden, CHAR(maillist), CHAR(grouplist), CHAR(gid),
2294             TRIM(acl_type), acl_id, description, CHAR(modtime), modby, modwith
2295           INTO :listname, :active, :public, :hidden, :hid, :maillist,
2296             :grouplist, :gid_str, :acl_type, :acl_id, :desc,
2297             :modtime, :modby_id, :modwith
2298           FROM list WHERE list_id = :id;
2299
2300         if (ingres_errno) return(mr_errcode);
2301
2302         if (atoi(gid_str) == -1)
2303             argv[6] = UNIQUE_GID;
2304
2305         argv[8] = malloc(0);
2306         if (!strcmp(acl_type, "LIST")) {
2307             status = id_to_name(acl_id, "LIST", &argv[8]);
2308         } else if (!strcmp(acl_type, "USER")) {
2309             status = id_to_name(acl_id, "USER", &argv[8]);
2310         } else if (!strcmp(acl_type, "KERBEROS")) {
2311             status = id_to_name(acl_id, "STRING", &argv[8]);
2312         } else if (!strcmp(acl_type, "NONE")) {
2313             status = 0;
2314             free(argv[8]);
2315             argv[8] = strsave("NONE");
2316         } else {
2317             status = 0;
2318             free(argv[8]);
2319             argv[8] = strsave("???");
2320         }
2321         if (status && status != MR_NO_MATCH) return(status);
2322
2323         argv[11] = malloc(0);
2324         if (modby_id > 0)
2325           status = id_to_name(modby_id, "USER", &argv[11]);
2326         else
2327           status = id_to_name(-modby_id, "STRING", &argv[11]);
2328         if (status && status != MR_NO_MATCH) return(status);
2329
2330         mr_trim_args(q->vcnt, argv);
2331         returned++;
2332         (*action)(q->vcnt, argv, actarg);
2333         free(argv[8]);
2334         free(argv[11]);
2335     }
2336
2337     sq_destroy(sq);
2338     if (ingres_errno) return(mr_errcode);
2339     return (MR_SUCCESS);
2340 }
2341
2342
2343 /* Add_member_to_list: do list flattening as we go!  MAXLISTDEPTH is
2344  * how many different ancestors a member is allowed to have.
2345  */
2346
2347 #define MAXLISTDEPTH    1024
2348
2349 int add_member_to_list(q, argv, cl)
2350     struct query *q;
2351     char **argv;
2352     client *cl;
2353 {
2354     EXEC SQL BEGIN DECLARE SECTION;
2355     int id, lid, mid, error, who, ref, rowcnt;
2356     char *mtype, dtype[9], *entity;
2357     EXEC SQL END DECLARE SECTION;
2358     int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2359     int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2360     int status;
2361     char *dtypes[MAXLISTDEPTH];
2362     char *iargv[3], *buf;
2363
2364     lid = *(int *)argv[0];
2365     mtype = argv[1];
2366     mid = *(int *)argv[2];
2367     /* if the member is already a direct member of the list, punt */
2368     EXEC SQL REPEATED SELECT COUNT(list_id) INTO :rowcnt FROM imembers
2369       WHERE list_id = :lid AND member_id = :mid
2370         AND member_type = :mtype AND direct = 1;
2371     if (rowcnt > 0)
2372       return(MR_EXISTS);
2373     if (!strcasecmp(mtype, "STRING")) {
2374         buf = malloc(0);
2375         status = id_to_name(mid, "STRING", &buf);
2376         if (status) return(status);
2377         if (index(buf, '/') || index(buf, '|')) {
2378             free(buf);
2379             return(MR_BAD_CHAR);
2380         }
2381         free(buf);
2382     }
2383
2384     ancestors[0] = lid;
2385     aref[0] = 1;
2386     acount = 1;
2387     EXEC SQL DECLARE csr103 CURSOR FOR
2388       SELECT list_id, ref_count FROM imembers
2389         WHERE member_id = :lid AND member_type='LIST';
2390     EXEC SQL OPEN csr103;
2391     while(1) {
2392         EXEC SQL FETCH csr103 INTO :id, :ref;
2393         if(sqlca.sqlcode != 0) break;
2394         aref[acount] = ref;
2395         ancestors[acount++] = id;
2396         if (acount >= MAXLISTDEPTH) break;
2397     }
2398     EXEC SQL CLOSE csr103;
2399     if (ingres_errno) return(mr_errcode);
2400     if (acount >= MAXLISTDEPTH) {
2401         return(MR_INTERNAL);
2402     }
2403     descendants[0] = mid;
2404     dtypes[0] = mtype;
2405     dref[0] = 1;
2406     dcount = 1;
2407     error = 0;
2408     if (!strcmp(mtype, "LIST")) {
2409         EXEC SQL DECLARE csr104 CURSOR FOR
2410           SELECT member_id, member_type, ref_count
2411           FROM imembers
2412           WHERE list_id = :mid;
2413         EXEC SQL OPEN csr104;
2414         while(1) {
2415             EXEC SQL FETCH csr104 INTO :id, :dtype, :ref;
2416             if(sqlca.sqlcode != 0) break;
2417             switch (dtype[0]) {
2418             case 'L':
2419                 dtypes[dcount] = "LIST";
2420                 break;
2421             case 'U':
2422                 dtypes[dcount] = "USER";
2423                 break;
2424             case 'S':
2425                 dtypes[dcount] = "STRING";
2426                 break;
2427             case 'K':
2428                 dtypes[dcount] = "KERBEROS";
2429                 break;
2430             default:
2431                 error++;
2432                 break;
2433             }
2434             dref[dcount] = ref;
2435             descendants[dcount++] = id;
2436             if (dcount >= MAXLISTDEPTH) {
2437                 error++;
2438                 break;
2439             }
2440         }
2441         EXEC SQL CLOSE csr104;
2442         if (ingres_errno) return(mr_errcode);
2443         if (error)
2444           return(MR_INTERNAL);
2445     }
2446     for (a = 0; a < acount; a++) {
2447         lid = ancestors[a];
2448         for (d = 0; d < dcount; d++) {
2449             mid = descendants[d];
2450             mtype = dtypes[d];
2451             if (mid == lid && !strcmp(mtype, "LIST")) {
2452                 return(MR_LISTLOOP);
2453             }
2454             EXEC SQL REPEATED SELECT COUNT(ref_count) INTO :rowcnt 
2455                 FROM imembers
2456               WHERE list_id = :lid AND member_id = :mid
2457                 AND member_type = :mtype;
2458             ref = aref[a] * dref[d];
2459             if (rowcnt > 0) {
2460                 if (a == 0 && d == 0) {
2461                     EXEC SQL UPDATE imembers
2462                       SET ref_count = ref_count+:ref, direct=1
2463                       WHERE list_id = :lid AND member_id = :mid
2464                         AND member_type = :mtype;
2465                 } else {
2466                     EXEC SQL UPDATE imembers
2467                       SET ref_count = ref_count+:ref
2468                       WHERE list_id = :lid AND member_id = :mid
2469                         AND member_type = :mtype;
2470                 }
2471             } else {
2472                 incremental_clear_before();
2473                 if (a == 0 && d == 0) {
2474                     EXEC SQL INSERT INTO imembers
2475                       (list_id, member_id, direct, member_type, ref_count)
2476                       VALUES (:lid, :mid, 1, :mtype, 1);
2477                 } else {
2478                     EXEC SQL INSERT INTO imembers
2479                       (list_id, member_id, member_type, ref_count)
2480                       VALUES (:lid, :mid, :mtype, 1);
2481                 }
2482                 iargv[0] = (char *)lid;
2483                 iargv[1] = mtype;
2484                 iargv[2] = (char *)mid;
2485                 incremental_after("members", 0, iargv);
2486             }
2487         }
2488     }
2489     lid = *(int *)argv[0];
2490     entity = cl->entity;
2491     who = cl->client_id;
2492     EXEC SQL REPEATED UPDATE list
2493       SET modtime='now', modby = :who, modwith = :entity
2494       WHERE list_id = :lid;
2495     if (ingres_errno) return(mr_errcode);
2496     return(MR_SUCCESS);
2497 }
2498
2499
2500 /* Delete_member_from_list: do list flattening as we go!
2501  */
2502
2503 int delete_member_from_list(q, argv, cl)
2504     struct query *q;
2505     char **argv;
2506     client *cl;
2507 {
2508     EXEC SQL BEGIN DECLARE SECTION;
2509     int id, lid, mid, cnt, error, who, ref;
2510     char *mtype, dtype[9], *entity;
2511     EXEC SQL END DECLARE SECTION;
2512     int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2513     int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2514     char *dtypes[MAXLISTDEPTH];
2515     char *iargv[3];
2516
2517     lid = *(int *)argv[0];
2518     mtype = argv[1];
2519     mid = *(int *)argv[2];
2520     /* if the member is not a direct member of the list, punt */
2521     EXEC SQL REPEATED SELECT COUNT(list_id) INTO :cnt FROM imembers
2522       WHERE list_id = :lid AND member_id = :mid
2523         AND member_type = :mtype AND direct = 1;
2524     if (ingres_errno) return(mr_errcode);
2525     if (cnt == 0)
2526       return(MR_NO_MATCH);
2527     ancestors[0] = lid;
2528     aref[0] = 1;
2529     acount = 1;
2530     EXEC SQL DECLARE csr105 CURSOR FOR
2531       SELECT list_id, ref_count FROM imembers
2532         WHERE member_id = :lid AND member_type = 'LIST';
2533     EXEC SQL OPEN csr105;
2534     while(1) {
2535         EXEC SQL FETCH csr105 INTO :id, :ref;
2536         if(sqlca.sqlcode!=0) break;
2537         aref[acount] = ref;
2538         ancestors[acount++] = id;
2539         if (acount >= MAXLISTDEPTH) break;
2540     }
2541     EXEC SQL CLOSE csr105;
2542     if (ingres_errno)
2543       return(mr_errcode);
2544     if (acount >= MAXLISTDEPTH)
2545       return(MR_INTERNAL);
2546     descendants[0] = mid;
2547     dtypes[0] = mtype;
2548     dref[0] = 1;
2549     dcount = 1;
2550     error = 0;
2551     if (!strcmp(mtype, "LIST")) {
2552         EXEC SQL DECLARE csr106 CURSOR FOR
2553           SELECT member_id, member_type, ref_count FROM imembers
2554             WHERE list_id = :mid;
2555         EXEC SQL OPEN csr106;
2556         while(1) {
2557             EXEC SQL FETCH csr106 INTO :id, :dtype, :ref;
2558             if(sqlca.sqlcode!=0) break;
2559             switch (dtype[0]) {
2560             case 'L':
2561                 dtypes[dcount] = "LIST";
2562                 break;
2563             case 'U':
2564                 dtypes[dcount] = "USER";
2565                 break;
2566             case 'S':
2567                 dtypes[dcount] = "STRING";
2568                 break;
2569             case 'K':
2570                 dtypes[dcount] = "KERBEROS";
2571                 break;
2572             default:
2573                 error++;
2574                 break;
2575             }
2576             dref[dcount] = ref;
2577             descendants[dcount++] = id;
2578             if (dcount >= MAXLISTDEPTH) break;
2579         }
2580         EXEC SQL CLOSE csr106;
2581         if (ingres_errno)
2582           return(mr_errcode);
2583         if (error)
2584           return(MR_INTERNAL);
2585     }
2586     for (a = 0; a < acount; a++) {
2587         lid = ancestors[a];
2588         for (d = 0; d < dcount; d++) {
2589             mid = descendants[d];
2590             mtype = dtypes[d];
2591             if (mid == lid && !strcmp(mtype, "LIST")) {
2592                 return(MR_LISTLOOP);
2593             }
2594             EXEC SQL REPEATED SELECT ref_count INTO :cnt FROM imembers
2595               WHERE list_id = :lid AND member_id = :mid AND member_type = :mtype;
2596             ref = aref[a] * dref[d];
2597             if (cnt <= ref) {
2598                 iargv[0] = (char *)lid;
2599                 iargv[1] = mtype;
2600                 iargv[2] = (char *)mid;
2601                 incremental_before("members", 0, iargv);
2602                 EXEC SQL DELETE FROM imembers
2603                   WHERE list_id = :lid AND member_id = :mid
2604                     AND member_type= :mtype;
2605                 incremental_clear_after();
2606             } else if (a == 0 && d == 0) {
2607                 EXEC SQL UPDATE imembers
2608                   SET ref_count = ref_count - :ref, direct = 0
2609                   WHERE list_id = :lid AND member_id = :mid
2610                     AND member_type = :mtype;
2611             } else {
2612                 EXEC SQL UPDATE imembers
2613                   SET ref_count = ref_count - :ref
2614                   WHERE list_id = :lid AND member_id = :mid
2615                     AND member_type = :mtype;
2616             }
2617         }
2618     }
2619     lid = *(int *)argv[0];
2620     entity = cl->entity;
2621     who = cl->client_id;
2622     EXEC SQL UPDATE list SET modtime = 'now', modby = :who, modwith = :entity
2623       WHERE list_id = :lid;
2624     if (ingres_errno) return(mr_errcode);
2625     return(MR_SUCCESS);
2626 }
2627
2628
2629 /* get_ace_use - given a type and a name, return a type and a name.
2630  * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2631  * and argv[1] will contain the ID of the entity in question.  The R*
2632  * types mean to recursively look at every containing list, not just
2633  * when the object in question is a direct member.  On return, the
2634  * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2635  */
2636
2637 int get_ace_use(q, argv, cl, action, actarg)
2638     struct query *q;
2639     char *argv[];
2640     client *cl;
2641     int (*action)();
2642     int actarg;
2643 {
2644     int found = 0;
2645     EXEC SQL BEGIN DECLARE SECTION;
2646     char *atype;
2647     int aid, listid, id;
2648     EXEC SQL END DECLARE SECTION;
2649     struct save_queue *sq, *sq_create();
2650
2651     atype = argv[0];
2652     aid = *(int *)argv[1];
2653     if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2654         !strcmp(atype, "KERBEROS")) {
2655         return(get_ace_internal(atype, aid, action, actarg));
2656     }
2657
2658     sq = sq_create();
2659     if (!strcmp(atype, "RLIST")) {
2660         sq_save_data(sq, aid);
2661         /* get all the list_id's of containing lists */
2662         EXEC SQL DECLARE csr107 CURSOR FOR
2663           SELECT list_id FROM imembers
2664             WHERE member_type='LIST' AND member_id = :aid;
2665         EXEC SQL OPEN csr107;
2666         while(1) {
2667             EXEC SQL FETCH csr107 INTO :listid;
2668             if(sqlca.sqlcode != 0) break;
2669             sq_save_unique_data(sq, listid);
2670         }
2671         EXEC SQL CLOSE csr107;
2672         /* now process each one */
2673         while (sq_get_data(sq, &id)) {
2674             if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2675               found++;
2676         }
2677     }
2678
2679     if (!strcmp(atype, "RUSER")) {
2680         EXEC SQL DECLARE csr108 CURSOR FOR
2681           SELECT list_id FROM imembers
2682             WHERE member_type='USER' AND member_id = :aid;
2683         EXEC SQL OPEN csr108;
2684         while(1) {
2685             EXEC SQL FETCH csr108 INTO :listid;
2686             if(sqlca.sqlcode != 0) break;
2687             sq_save_data(sq, listid);
2688         }
2689         EXEC SQL CLOSE csr108;
2690         /* now process each one */
2691         while (sq_get_data(sq, &id)) {
2692             if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2693               found++;
2694         }
2695         if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2696           found++;
2697     }
2698
2699     if (!strcmp(atype, "RKERBERO")) {
2700         EXEC SQL DECLARE csr109 CURSOR FOR
2701           SELECT list_id FROM imembers
2702             WHERE member_type='KERBEROS' AND member_id = :aid;
2703         EXEC SQL OPEN csr109;
2704         while(1) {
2705             EXEC SQL FETCH csr109 INTO :listid;
2706             if(sqlca.sqlcode != 0) break;
2707             sq_save_data(sq, listid);
2708         }
2709         EXEC SQL CLOSE csr109;
2710         /* now process each one */
2711         while (sq_get_data(sq, &id)) {
2712             if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2713               found++;
2714         }
2715         if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2716           found++;
2717     }
2718
2719     sq_destroy(sq);
2720     if (ingres_errno) return(mr_errcode);
2721     if (!found) return(MR_NO_MATCH);
2722     return(MR_SUCCESS);
2723 }
2724
2725
2726 /* This looks up a single list or user for ace use.  atype must be "USER"
2727  * or "LIST", and aid is the ID of the corresponding object.  This is used
2728  * by get_ace_use above.
2729  */
2730
2731 get_ace_internal(atype, aid, action, actarg)
2732     EXEC SQL BEGIN DECLARE SECTION;
2733     char *atype;
2734     int aid;
2735     EXEC SQL END DECLARE SECTION;
2736     int (*action)();
2737     int actarg;
2738 {
2739     char *rargv[2];
2740     int found = 0;
2741     EXEC SQL BEGIN DECLARE SECTION;
2742     char name[33];
2743     EXEC SQL END DECLARE SECTION;
2744
2745     rargv[1] = name;
2746     if (!strcmp(atype, "LIST")) {
2747         rargv[0] = "FILESYS";
2748         EXEC SQL DECLARE csr110 CURSOR FOR
2749           SELECT label FROM filesys
2750             WHERE owners = :aid;
2751         EXEC SQL OPEN csr110;
2752         while(1) {
2753             EXEC SQL FETCH csr110 INTO :name;
2754             if(sqlca.sqlcode != 0) break;
2755             (*action)(2, rargv, actarg);
2756             found++;
2757         }
2758         EXEC SQL CLOSE csr110;
2759
2760         rargv[0] = "QUERY";
2761         EXEC SQL DECLARE csr111 CURSOR FOR
2762           SELECT capability FROM capacls
2763             WHERE list_id = :aid ;
2764         EXEC SQL OPEN csr111;
2765         while(1) {
2766             EXEC SQL FETCH csr111 INTO :name ;
2767             if(sqlca.sqlcode != 0) break;
2768             (*action)(2, rargv, actarg);
2769             found++;
2770         }
2771         EXEC SQL CLOSE csr111;
2772     } else if (!strcmp(atype, "USER")) {
2773         rargv[0] = "FILESYS";
2774         EXEC SQL DECLARE csr112 CURSOR FOR
2775           SELECT label FROM filesys
2776             WHERE owner = :aid;
2777         EXEC SQL OPEN csr112;
2778         while(1) {
2779             EXEC SQL FETCH csr112 INTO :name ;
2780             if(sqlca.sqlcode != 0) break;
2781             (*action)(2, rargv, actarg);
2782             found++;
2783         }
2784         EXEC SQL CLOSE csr112;
2785     }
2786
2787     rargv[0] = "LIST";
2788     EXEC SQL DECLARE csr113 CURSOR FOR
2789       SELECT name FROM list
2790         WHERE acl_type = :atype AND acl_id = :aid;
2791     EXEC SQL OPEN csr113;
2792     while(1) {
2793         EXEC SQL FETCH csr113 INTO :name;
2794         if(sqlca.sqlcode != 0) break;
2795         (*action)(2, rargv, actarg);
2796         found++;
2797     }
2798     EXEC SQL CLOSE csr113;
2799
2800     rargv[0] = "SERVICE";
2801     EXEC SQL DECLARE csr114 CURSOR FOR
2802       SELECT name FROM servers
2803         WHERE acl_type = :atype AND acl_id = :aid;
2804     EXEC SQL OPEN csr114;
2805     while(1) {
2806         EXEC SQL FETCH csr114 INTO :name;
2807         if(sqlca.sqlcode != 0) break;
2808         (*action)(2, rargv, actarg);
2809         found++;
2810     }
2811     EXEC SQL CLOSE csr114;
2812
2813     rargv[0] = "HOSTACCESS";
2814     EXEC SQL DECLARE csr115 CURSOR FOR
2815       SELECT name FROM machine m, hostaccess ha
2816         WHERE m.mach_id = ha.mach_id AND ha.acl_type = :atype
2817           AND ha.acl_id = :aid;
2818     EXEC SQL OPEN csr115;
2819     while(1) {
2820         EXEC SQL FETCH csr115 INTO :name;
2821         if(sqlca.sqlcode != 0) break;
2822         (*action)(2, rargv, actarg);
2823         found++;
2824     }
2825     EXEC SQL CLOSE csr115;
2826
2827     rargv[0] = "ZEPHYR";
2828     EXEC SQL DECLARE csr116 CURSOR FOR
2829       SELECT class FROM zephyr z
2830         WHERE z.xmt_type = :atype AND z.xmt_id = :aid
2831           OR z.sub_type = :atype AND z.sub_id = :aid
2832           OR z.iws_type = :atype AND z.iws_id = :aid
2833           OR z.iui_type = :atype AND z.iui_id = :aid;
2834     EXEC SQL OPEN csr116;
2835     while(1) {
2836         EXEC SQL FETCH csr116 INTO :name;
2837         if(sqlca.sqlcode != 0) break;
2838         (*action)(2, rargv, actarg);
2839         found++;
2840     }
2841     EXEC SQL CLOSE csr116;
2842
2843     if (!found) return(MR_NO_MATCH);
2844     return(MR_SUCCESS);
2845 }
2846
2847
2848 /* get_lists_of_member - given a type and a name, return the name and flags
2849  * of all of the lists of the given member.  The member_type is one of
2850  * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2851  * and argv[1] will contain the ID of the entity in question.  The R*
2852  * types mean to recursively look at every containing list, not just
2853  * when the object in question is a direct member.
2854  */
2855
2856 int get_lists_of_member(q, argv, cl, action, actarg)
2857     struct query *q;
2858     char *argv[];
2859     client *cl;
2860     int (*action)();
2861     int actarg;
2862 {
2863     int found = 0, direct = 1;
2864     char *rargv[6];
2865     EXEC SQL BEGIN DECLARE SECTION;
2866     char *atype;
2867     int aid, listid, id;
2868     char name[33], active[5], public[5], hidden[5], maillist[5], grouplist[5];
2869     EXEC SQL END DECLARE SECTION;
2870
2871     atype = argv[0];
2872     aid = *(int *)argv[1];
2873     if (!strcmp(atype, "RLIST")) {
2874         atype = "LIST";
2875         direct = 0;
2876     }
2877     if (!strcmp(atype, "RUSER")) {
2878         atype = "USER";
2879         direct = 0;
2880     }
2881     if (!strcmp(atype, "RSTRING")) {
2882         atype = "STRING";
2883         direct = 0;
2884     }
2885     if (!strcmp(atype, "RKERBEROS")) {
2886         atype = "KERBEROS";
2887         direct = 0;
2888     }
2889
2890     rargv[0] = name;
2891     rargv[1] = active;
2892     rargv[2] = public;
2893     rargv[3] = hidden;
2894     rargv[4] = maillist;
2895     rargv[5] = grouplist;
2896     if (direct) {
2897         EXEC SQL DECLARE csr117a CURSOR FOR
2898           SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2899               CHAR(l.maillist), CHAR(l.grouplist)
2900             FROM list l, imembers im
2901             WHERE l.list_id = im.list_id AND im.direct = 1
2902               AND im.member_type = :atype AND im.member_id = :aid;
2903         EXEC SQL OPEN csr117a;
2904         while(1) {
2905             EXEC SQL FETCH csr117a
2906               INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2907             if(sqlca.sqlcode != 0) break;
2908             (*action)(6, rargv, actarg);
2909             found++;
2910         }
2911         EXEC SQL CLOSE csr117a;
2912     } else {
2913         EXEC SQL DECLARE csr117b CURSOR FOR
2914           SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2915               CHAR(l.maillist), CHAR(l.grouplist)
2916             FROM list l, imembers im
2917             WHERE l.list_id = im.list_id
2918               AND im.member_type = :atype AND im.member_id = :aid;
2919         EXEC SQL OPEN csr117b;
2920         while(1) {
2921             EXEC SQL FETCH csr117b
2922               INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2923             if(sqlca.sqlcode != 0) break;
2924             (*action)(6, rargv, actarg);
2925             found++;
2926         }
2927         EXEC SQL CLOSE csr117b;
2928     }
2929
2930     if (ingres_errno) return(mr_errcode);
2931     if (!found) return(MR_NO_MATCH);
2932     return(MR_SUCCESS);
2933 }
2934
2935
2936 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2937  * the five flags associated with each list.  It will return the name of
2938  * each list that meets the quailifications.  It does this by building a
2939  * where clause based on the arguments, then doing a retrieve.
2940  */
2941
2942 static char *lflags[5] = { "active", "publicflg", "hidden", "maillist", "grouplist" };
2943
2944 int qualified_get_lists(q, argv, cl, action, actarg)
2945     struct query *q;
2946     char *argv[];
2947     client *cl;
2948     int (*action)();
2949     int actarg;
2950 {
2951     return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2952                          "l", "name", lflags));
2953 }
2954
2955
2956 /* get_members_of_list - this gets only direct members */
2957  
2958 get_members_of_list(q, argv, cl, action, actarg)
2959     struct query *q;
2960     char *argv[];
2961     client *cl;
2962     int (*action)();
2963     int actarg;
2964 {
2965     return(gmol_internal(q, argv, cl, action, actarg, 1));
2966 }
2967  
2968 /* get_end_members_of_list - this gets direct or indirect members */
2969  
2970 get_end_members_of_list(q, argv, cl, action, actarg)
2971     struct query *q;
2972     char *argv[];
2973     client *cl;
2974     int (*action)();
2975     int actarg;
2976 {
2977     return(gmol_internal(q, argv, cl, action, actarg, 0));
2978 }
2979  
2980 /** gmol_internal - optimized query for retrieval of list members
2981  **   used by both get_members_of_list and get_end_members_of_list
2982  **
2983  ** Inputs:
2984  **   argv[0] - list_id
2985  **
2986  ** Description:
2987  **   - retrieve USER members, then LIST members, then STRING members
2988  **/
2989
2990 gmol_internal(q, argv, cl, action, actarg, flag)
2991     struct query *q;
2992     char *argv[];
2993     client *cl;
2994     int (*action)();
2995     int actarg;
2996     int flag;
2997 {
2998     EXEC SQL BEGIN DECLARE SECTION;
2999     int list_id, member_id, direct;
3000     char member_name[129], member_type[9];
3001     EXEC SQL END DECLARE SECTION;
3002     char *targv[2];
3003     int members;
3004     struct save_queue *sq;
3005
3006     /* true/false flag indicates whether to display only direct members. */
3007     if (flag)
3008       direct = 0;
3009     else
3010       direct = -1;
3011
3012     list_id = *(int *)argv[0];
3013     members = 0;
3014     sq = sq_create();
3015
3016     EXEC SQL DECLARE csr118 CURSOR FOR
3017       SELECT member_type, member_id FROM imembers
3018         WHERE list_id = :list_id AND direct > :direct;
3019     EXEC SQL OPEN csr118;
3020     while(1) {
3021         EXEC SQL FETCH csr118 INTO :member_type, :member_id;
3022         if (sqlca.sqlcode != 0) break;
3023         if (members++ > 49)
3024           break;
3025         sq_save_data(sq, ((int)member_type[0] << 24) | (member_id & 0xffffff));
3026     }
3027     EXEC SQL CLOSE csr118;
3028
3029     if (members <= 49) {
3030         targv[1] = malloc(0);
3031         while (sq_remove_data(sq, &member_id)) {
3032             switch (member_id >> 24) {
3033             case 'U':
3034                 targv[0] = "USER";
3035                 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
3036                 (*action)(2, targv, actarg);
3037                 break;
3038             case 'L':
3039                 targv[0] = "LIST";
3040                 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
3041                 (*action)(2, targv, actarg);
3042                 break;
3043             case 'S':
3044                 targv[0] = "STRING";
3045                 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
3046                 (*action)(2, targv, actarg);
3047                 break;
3048             case 'K':
3049                 targv[0] = "KERBEROS";
3050                 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
3051                 (*action)(2, targv, actarg);
3052                 break;
3053             default:
3054                 sq_destroy(sq);
3055                 return(MR_INTERNAL);
3056             }
3057         }
3058         free(targv[1]);
3059         sq_destroy(sq);
3060         return(MR_SUCCESS);
3061     }
3062     sq_destroy(sq);
3063
3064     targv[1] = member_name;
3065     targv[0] = "USER";
3066     EXEC SQL DECLARE csr119 CURSOR FOR
3067       SELECT u.login FROM users u, imembers im
3068         WHERE im.list_id = :list_id AND im.member_type = 'USER'
3069           AND im.member_id = u.users_id AND im.direct > :direct
3070         ORDER BY 1;
3071     EXEC SQL OPEN csr119;
3072     while(1) {
3073         EXEC SQL FETCH csr119 INTO :member_name;
3074         if(sqlca.sqlcode != 0) break;
3075         (*action)(2, targv, actarg);
3076     }
3077     EXEC SQL CLOSE csr119;
3078     if (ingres_errno) return(mr_errcode);
3079
3080     targv[0] = "LIST";
3081     EXEC SQL DECLARE csr120 CURSOR FOR
3082       SELECT l.name FROM list l, imembers im
3083         WHERE im.list_id = :list_id AND im.member_type='LIST'
3084           AND im.member_id = l.list_id AND im.direct > :direct
3085         ORDER BY 1;
3086     EXEC SQL OPEN csr120;
3087     while(1) {
3088         EXEC SQL FETCH csr120 INTO :member_name;
3089         if(sqlca.sqlcode != 0) break;
3090         (*action)(2, targv, actarg);
3091     }
3092     EXEC SQL CLOSE csr120;
3093     if (ingres_errno) return(mr_errcode);
3094
3095     targv[0] = "STRING";
3096     EXEC SQL DECLARE csr121 CURSOR FOR
3097       SELECT CHAR(str.string) FROM strings str, imembers im
3098         WHERE im.list_id = :list_id AND im.member_type='STRING'
3099           AND im.member_id = str.string_id AND im.direct > :direct
3100         ORDER BY 1;
3101     EXEC SQL OPEN csr121;
3102     while(1) {
3103         EXEC SQL FETCH csr121 INTO :member_name;
3104         if(sqlca.sqlcode != 0) break;
3105         (*action)(2, targv, actarg);
3106     }
3107     EXEC SQL CLOSE csr121;
3108     if (ingres_errno) return(mr_errcode);
3109
3110     targv[0] = "KERBEROS";
3111     EXEC SQL DECLARE csr122 CURSOR FOR
3112       SELECT CHAR(str.string) FROM strings str, imembers im
3113         WHERE im.list_id = :list_id AND im.member_type='KERBEROS'
3114           AND im.member_id = str.string_id 
3115           AND im.direct > :direct
3116         ORDER BY 1;
3117     EXEC SQL OPEN csr122;
3118     while(1) {
3119         EXEC SQL FETCH csr122 INTO :member_name;
3120         if(sqlca.sqlcode != 0) break;
3121         (*action)(2, targv, actarg);
3122     }
3123     EXEC SQL CLOSE csr122;
3124     if (ingres_errno) return(mr_errcode);
3125
3126     return(MR_SUCCESS);
3127 }
3128
3129
3130 /* count_members_of_list: this is a simple query, but it cannot be done
3131  * through the dispatch table.
3132  */
3133
3134 int count_members_of_list(q, argv, cl, action, actarg)
3135     struct query *q;
3136     char *argv[];
3137     client *cl;
3138     int (*action)();
3139     int actarg;
3140 {
3141     EXEC SQL BEGIN DECLARE SECTION;
3142     int  list, ct = 0;
3143     EXEC SQL END DECLARE SECTION;
3144     char *rargv[1], countbuf[5];
3145
3146     list = *(int *)argv[0];
3147     rargv[0] = countbuf;
3148     EXEC SQL REPEATED SELECT count (*) INTO :ct FROM imembers
3149       WHERE list_id = :list AND direct=1;
3150     if (ingres_errno) return(mr_errcode);
3151     sprintf(countbuf, "%d", ct);
3152     (*action)(1, rargv, actarg);
3153     return(MR_SUCCESS);
3154 }
3155
3156
3157 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
3158  * the three flags associated with each service.  It will return the name of
3159  * each service that meets the quailifications.  It does this by building a
3160  * where clause based on the arguments, then doing a retrieve.
3161  */
3162
3163 static char *sflags[3] = { "enable", "inprogress", "harderror" };
3164
3165 int qualified_get_server(q, argv, cl, action, actarg)
3166     struct query *q;
3167     char *argv[];
3168     client *cl;
3169     int (*action)();
3170     int actarg;
3171 {
3172     return(qualified_get(q, argv, action, actarg, "s.name != ''",
3173                          "s", "name", sflags));
3174 }
3175
3176
3177 /* generic qualified get routine, used by qualified_get_lists,
3178  * qualified_get_server, and qualified_get_serverhost.
3179  *   Args:
3180  *      start - a simple where clause, must not be empty
3181  *      range - the name of the range variable
3182  *      field - the field to return
3183  *      flags - an array of strings, names of the flag variables
3184  */
3185
3186 int qualified_get(q, argv, action, actarg, start, range, field, flags)
3187     struct query *q;
3188     char *argv[];
3189     int (*action)();
3190     int actarg;
3191     char *start;
3192     char *range;
3193     char *field;
3194     char *flags[];
3195 {
3196     char name[33], qual[256];
3197     int rowcount=0, i;
3198     char *rargv[1], buf[32];
3199
3200     strcpy(qual, start);
3201     for (i = 0; i < q->argc; i++) {
3202         if (!strcmp(argv[i], "TRUE")) {
3203             sprintf(buf, " AND %s.%s != 0", range, flags[i]);
3204             (void) strcat(qual, buf);
3205         } else if (!strcmp(argv[i], "FALSE")) {
3206             sprintf(buf, " AND %s.%s = 0", range, flags[i]);
3207             (void) strcat(qual, buf);
3208         }
3209     }
3210
3211     rargv[0] = SQLDA->sqlvar[0].sqldata;
3212     sprintf(stmt_buf,"SELECT CHAR(%s.%s) FROM %s %s WHERE %s",range,field,q->rtable,range,qual);
3213     EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3214     if(sqlca.sqlcode)
3215       return(MR_INTERNAL);
3216     EXEC SQL DECLARE csr123 CURSOR FOR stmt;
3217     EXEC SQL OPEN csr123;
3218     while(1) {
3219         EXEC SQL FETCH csr123 USING DESCRIPTOR :SQLDA;
3220         if(sqlca.sqlcode != 0) break;
3221         rowcount++;
3222         (*action)(1, rargv, actarg);
3223     }
3224     EXEC SQL CLOSE csr123;
3225     if (ingres_errno) return(mr_errcode);
3226     if (rowcount == 0)
3227       return(MR_NO_MATCH);
3228     return(MR_SUCCESS);
3229 }
3230
3231
3232 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
3233  * the five flags associated with each serverhost.  It will return the name of
3234  * each service and host that meets the quailifications.  It does this by
3235  * building a where clause based on the arguments, then doing a retrieve.
3236  */
3237
3238 static char *shflags[6] = { "service", "enable", "override", "success",
3239                             "inprogress", "hosterror" };
3240
3241 int qualified_get_serverhost(q, argv, cl, action, actarg)
3242     struct query *q;
3243     char *argv[];
3244     client *cl;
3245     int (*action)();
3246     int actarg;
3247 {
3248     EXEC SQL BEGIN DECLARE SECTION;
3249     char sname[33], mname[33], qual[256];
3250     EXEC SQL END DECLARE SECTION;
3251     char *rargv[2], buf[32];
3252     int i, rowcount;
3253
3254     sprintf(qual, "m.mach_id = sh.mach_id AND sh.service = uppercase('%s')",
3255             argv[0]);
3256     for (i = 1; i < q->argc; i++) {
3257         if (!strcmp(argv[i], "TRUE")) {
3258             sprintf(buf, " AND sh.%s != 0", shflags[i]);
3259             strcat(qual, buf);
3260         } else if (!strcmp(argv[i], "FALSE")) {
3261             sprintf(buf, " AND sh.%s = 0", shflags[i]);
3262             strcat(qual, buf);
3263         }
3264     }
3265
3266     rargv[0] = sname;
3267     rargv[1] = mname;
3268     EXEC SQL DECLARE csr124 CURSOR FOR
3269       SELECT sh.service, m.name FROM serverhosts sh, machine m
3270         WHERE :qual;
3271     EXEC SQL OPEN csr124;
3272     while(1) {
3273         EXEC SQL FETCH csr124 INTO :sname, :mname;
3274         if(sqlca.sqlcode != 0) break;
3275         rowcount++;
3276         (*action)(2, rargv, actarg);
3277     }
3278     EXEC SQL CLOSE csr124;
3279
3280     if (ingres_errno) return(mr_errcode);
3281     if (rowcount == 0)
3282       return(MR_NO_MATCH);
3283     return(MR_SUCCESS);
3284 }
3285
3286
3287 /* register_user - change user's login name and allocate a pobox, group,
3288  * filesystem, and quota for them.  The user's status must start out as 0,
3289  * and is left as 2.  Arguments are: user's UID, new login name, and user's
3290  * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY,
3291  * MR_FS_STAFF, MR_FS_MISC).
3292  */
3293
3294 register_user(q, argv, cl)
3295     struct query *q;
3296     char **argv;
3297     client *cl;
3298 {
3299     EXEC SQL BEGIN DECLARE SECTION;
3300     char *login, dir[65], *entity, directory[129], machname[33];
3301     int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
3302     int size, alloc, pid, ostatus, nstatus, gidval, fsidval, npidval;
3303     static int m_id = 0, def_quota = 0;
3304     EXEC SQL END DECLARE SECTION;
3305     char buffer[256], *aargv[3];
3306
3307     entity = cl->entity;
3308     who = cl->client_id;
3309
3310     uid = atoi(argv[0]);
3311     login = argv[1];
3312     utype = atoi(argv[2]);
3313
3314     /* find user */
3315     EXEC SQL REPEATED SELECT users_id, status INTO :users_id, :ostatus
3316       FROM users
3317       WHERE uid = :uid AND (status=0 OR status=5 OR status=6);
3318
3319     if (sqlca.sqlerrd[2] == 0)
3320       return(MR_NO_MATCH);
3321     if (sqlca.sqlerrd[2] > 1)
3322       return(MR_NOT_UNIQUE);
3323
3324     /* check new login name */
3325     EXEC SQL REPEATED SELECT COUNT(login) INTO :rowcount FROM users
3326       WHERE login = LEFT(:login,SIZE(login)) AND users_id != :users_id;
3327     if (ingres_errno) return(mr_errcode);
3328     if (rowcount > 0) return(MR_IN_USE);
3329     EXEC SQL REPEATED SELECT COUNT(name) INTO :rowcount FROM list
3330       WHERE name = LEFT(:login,SIZE(name));
3331     if (ingres_errno) return(mr_errcode);
3332     if (rowcount > 0) return(MR_IN_USE);
3333     EXEC SQL REPEATED SELECT COUNT(label) INTO :rowcount FROM filesys
3334       WHERE label = LEFT(:login,SIZE(label));
3335     if (ingres_errno) return(mr_errcode);
3336     if (rowcount > 0) return(MR_IN_USE);
3337     com_err(whoami, 0, "login name OK");
3338
3339     /* choose place for pobox, put in mid */
3340     EXEC SQL DECLARE csr130 CURSOR FOR
3341       SELECT sh.mach_id, m.name FROM serverhosts sh, machine m
3342       WHERE sh.service='POP' AND sh.mach_id=m.mach_id
3343         AND sh.value2 - sh.value1 =
3344           (SELECT MAX(value2 - value1) FROM serverhosts
3345             WHERE service = 'POP');
3346     EXEC SQL OPEN csr130;
3347     EXEC SQL FETCH csr130 INTO :mid, :machname;
3348     if (sqlca.sqlerrd[2] == 0) {
3349         EXEC SQL CLOSE csr130;
3350         if (ingres_errno) return(mr_errcode);
3351         return(MR_NO_POBOX);
3352     } else {
3353         EXEC SQL CLOSE csr130;
3354         if (ingres_errno) return(mr_errcode);
3355     }
3356
3357     /* change login name, set pobox */
3358     sprintf(buffer, "u.users_id = %d", users_id);
3359     incremental_before("users", buffer, 0);
3360     nstatus = 2;
3361     if (ostatus == 5 || ostatus == 6)
3362       nstatus = 1;
3363     EXEC SQL REPEATED UPDATE users SET login = :login, status = :nstatus,
3364         modtime='now', modby = :who, modwith = :entity, potype='POP',
3365         pop_id = :mid, pmodtime='now', pmodby = :who, pmodwith = :entity
3366       WHERE users_id = :users_id;
3367
3368     if (ingres_errno) return(mr_errcode);
3369     if (sqlca.sqlerrd[2] != 1)
3370       return(MR_INTERNAL);
3371     set_pop_usage(mid, 1);
3372     com_err(whoami, 0, "set login name to %s and pobox to %s", login,
3373             strtrim(machname));
3374     incremental_after("users", buffer, 0);
3375
3376     /* create group list */
3377     if (set_next_object_id("gid", "list", 1))
3378       return(MR_NO_ID);
3379     if (set_next_object_id("list_id", "list", 0))
3380       return(MR_NO_ID);
3381     EXEC SQL REPEATED SELECT value INTO :list_id FROM numvalues
3382       WHERE name='list_id';
3383     if (ingres_errno) return(mr_errcode);
3384     if (sqlca.sqlerrd[2] != 1)
3385       return(MR_INTERNAL);
3386     incremental_clear_before();
3387     EXEC SQL SELECT value INTO :gidval FROM numvalues WHERE name = 'gid';
3388     EXEC SQL REPEATED INSERT INTO list
3389              (name, list_id, active, publicflg, hidden, maillist, grouplist,
3390               gid, description, acl_type, acl_id,
3391               modtime, modby, modwith)
3392       VALUES (:login, :list_id, 1, 0, 0, 0, 1,
3393               :gidval, 'User Group', 'USER', :users_id,
3394               'now', :who, :entity);
3395     if (ingres_errno) return(mr_errcode);
3396     if (sqlca.sqlerrd[2] != 1)
3397       return(MR_INTERNAL);
3398     sprintf(buffer, "l.list_id = %d", list_id);
3399     incremental_after("list", buffer, 0);
3400     aargv[0] = (char *) list_id;
3401     aargv[1] = "USER";
3402     aargv[2] = (char *) users_id;
3403     incremental_clear_before();
3404     EXEC SQL REPEATED INSERT INTO imembers
3405              (list_id, member_type, member_id, ref_count, direct)
3406       VALUES (:list_id, 'USER', :users_id, 1, 1);
3407     if (ingres_errno) return(mr_errcode);
3408     if (sqlca.sqlerrd[2] != 1)
3409       return(MR_INTERNAL);
3410     incremental_after("members", 0, aargv);
3411
3412     if (m_id == 0) {
3413         /* Cell Name (I know, it shouldn't be hard coded...) */
3414         strcpy(machname, "ATHENA.MIT.EDU");
3415         EXEC SQL SELECT mach_id INTO :m_id FROM machine 
3416           WHERE name = :machname;
3417     }
3418
3419     /* create filesystem */
3420     if (set_next_object_id("filsys_id", "filesys", 0))
3421       return(MR_NO_ID);
3422     incremental_clear_before();
3423     if (islower(login[0]) && islower(login[1])) {
3424         sprintf(directory, "/afs/athena.mit.edu/user/%c/%c/%s",
3425                 login[0], login[1], login);
3426     } else {
3427         sprintf(directory, "/afs/athena.mit.edu/user/other/%s", login);
3428     }
3429  
3430     EXEC SQL SELECT value INTO :fsidval FROM numvalues
3431       WHERE numvalues.name='filsys_id';
3432     EXEC SQL REPEATED INSERT INTO filesys
3433         (filsys_id, phys_id, label, type, mach_id, name,
3434          mount, access, comments, owner, owners, createflg,
3435          lockertype, modtime, modby, modwith)
3436       VALUES
3437         (:fsidval, 0, :login, 'AFS', :m_id, :directory,
3438          '/mit/'+:login, 'w', 'User Locker', :users_id, :list_id, 1,
3439          'HOMEDIR', 'now', :who, :entity);
3440
3441     if (ingres_errno) return(mr_errcode);
3442     if (sqlca.sqlerrd[2]  != 1)
3443       return(MR_INTERNAL);
3444     sprintf(buffer,"fs.filsys_id = %d",fsidval);
3445     incremental_after("filesys", buffer, 0);
3446
3447     /* set quota */
3448     if (def_quota == 0) {
3449         EXEC SQL REPEATED SELECT value INTO :def_quota FROM numvalues
3450           WHERE name='def_quota';
3451         if (ingres_errno) return(mr_errcode);
3452         if (sqlca.sqlerrd[2] != 1)
3453           return(MR_NO_QUOTA);
3454         
3455     }
3456     incremental_clear_before();
3457     EXEC SQL REPEATED INSERT INTO quota
3458         (entity_id, filsys_id, type, quota, phys_id, modtime, modby, modwith)
3459       VALUES
3460         (0, :fsidval, 'ANY', :def_quota, 0, 'now', :who, :entity);
3461     if (ingres_errno) return(mr_errcode);
3462     if (sqlca.sqlerrd[2] != 1)
3463       return(MR_INTERNAL);
3464     aargv[0] = login;
3465     aargv[1] = "ANY";
3466     aargv[2] = login;
3467     sprintf(buffer, "q.entity_id = 0 and q.filsys_id = %d and q.type = 'ANY'", fsidval);
3468     incremental_after("quota", buffer, aargv);
3469     com_err(whoami, 0, "quota of %d assigned", def_quota);
3470     if (ingres_errno) return(mr_errcode);
3471
3472     cache_entry(login, "USER", users_id);
3473
3474     EXEC SQL REPEATED UPDATE tblstats SET updates=updates+1, modtime='now'
3475       WHERE table_name='users';
3476     EXEC SQL REPEATED UPDATE tblstats SET appends=appends+1, modtime='now'
3477       WHERE table_name='list' OR table_name='filesys' OR table_name='quota';
3478     if (ingres_errno) return(mr_errcode);
3479     return(MR_SUCCESS);
3480 }
3481
3482
3483
3484 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
3485  **
3486  ** Inputs:
3487  **   id of machine
3488  **   delta (will be +/- 1)
3489  **
3490  ** Description:
3491  **   - incr/decr value field in serverhosts table for pop/mach_id
3492  **
3493  **/
3494
3495 static int set_pop_usage(id, cnt)
3496     EXEC SQL BEGIN DECLARE SECTION;
3497     int id;
3498     int cnt;
3499     EXEC SQL END DECLARE SECTION;
3500 {
3501     EXEC SQL REPEATED UPDATE serverhosts SET value1 = value1 + :cnt
3502       WHERE serverhosts.service = 'POP' AND serverhosts.mach_id = :id;
3503
3504     if (ingres_errno) return(mr_errcode);
3505     return(MR_SUCCESS);
3506 }
3507
3508 int _sdl_followup(q, argv, cl)
3509     struct query *q;
3510     char **argv;
3511     client *cl;
3512 {
3513     int i;
3514     i = atoi(argv[0]);
3515     log_flags = i;
3516     if (i & LOG_SQL) {
3517         EXEC SQL set printqry;
3518     } else {
3519         EXEC SQL set noprintqry;
3520     }
3521     return(MR_SUCCESS);
3522 }
3523
3524
3525 \f
3526 /* Validation Routines */
3527
3528 validate_row(q, argv, v)
3529     register struct query *q;
3530     char *argv[];
3531     register struct validate *v;
3532 {
3533     EXEC SQL BEGIN DECLARE SECTION;
3534     char *name;
3535     char qual[128];
3536     int rowcount;
3537     EXEC SQL END DECLARE SECTION;
3538
3539     /* build where clause */
3540     build_qual(v->qual, v->argc, argv, qual);
3541
3542     if (log_flags & LOG_VALID)
3543         /* tell the logfile what we're doing */
3544         com_err(whoami, 0, "validating row: %s", qual);
3545
3546     /* look for the record */
3547     sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",q->rtable,qual);
3548     EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3549     if(sqlca.sqlcode)
3550       return(MR_INTERNAL);
3551     EXEC SQL DECLARE csr126 CURSOR FOR stmt;
3552     EXEC SQL OPEN csr126;
3553     EXEC SQL FETCH csr126 USING DESCRIPTOR :SQLDA;
3554     EXEC SQL CLOSE csr126;
3555     rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3556
3557     if (ingres_errno) return(mr_errcode);
3558     if (rowcount == 0) return(MR_NO_MATCH);
3559     if (rowcount > 1) return(MR_NOT_UNIQUE);
3560     return(MR_EXISTS);
3561 }
3562
3563 validate_fields(q, argv, vo, n)
3564     struct query *q;
3565     register char *argv[];
3566     register struct valobj *vo;
3567     register int n;
3568 {
3569     register int status;
3570
3571     while (--n >= 0) {
3572         switch (vo->type) {
3573         case V_NAME:
3574             if (log_flags & LOG_VALID)
3575                 com_err(whoami, 0, "validating %s in %s: %s",
3576                     vo->namefield, vo->table, argv[vo->index]);
3577             status = validate_name(argv, vo);
3578             break;
3579
3580         case V_ID:
3581             if (log_flags & LOG_VALID)
3582                 com_err(whoami, 0, "validating %s in %s: %s",
3583                     vo->idfield, vo->table, argv[vo->index]);
3584             status = validate_id(q, argv, vo);
3585             break;
3586
3587         case V_DATE:
3588             if (log_flags & LOG_VALID)
3589                 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
3590             status = validate_date(argv, vo);
3591             break;
3592
3593         case V_TYPE:
3594             if (log_flags & LOG_VALID)
3595                 com_err(whoami, 0, "validating %s type: %s",
3596                     vo->table, argv[vo->index]);
3597             status = validate_type(argv, vo);
3598             break;
3599
3600         case V_TYPEDATA:
3601             if (log_flags & LOG_VALID)
3602                 com_err(whoami, 0, "validating typed data (%s): %s",
3603                     argv[vo->index - 1], argv[vo->index]);
3604             status = validate_typedata(q, argv, vo);
3605             break;
3606
3607         case V_RENAME:
3608             if (log_flags & LOG_VALID)
3609                 com_err(whoami, 0, "validating rename %s in %s",
3610                         argv[vo->index], vo->table);
3611             status = validate_rename(argv, vo);
3612             break;
3613
3614         case V_CHAR:
3615             if (log_flags & LOG_VALID)
3616               com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
3617             status = validate_chars(argv[vo->index]);
3618             break;
3619
3620         case V_SORT:
3621             status = MR_EXISTS;
3622             break;
3623
3624         case V_LOCK:
3625             status = lock_table(vo);
3626             break;
3627
3628         case V_WILD:
3629             status = convert_wildcards(argv[vo->index]);
3630             break;
3631
3632         case V_UPWILD:
3633             status = convert_wildcards_uppercase(argv[vo->index]);
3634             break;
3635
3636         }
3637
3638         if (status != MR_EXISTS) return(status);
3639         vo++;
3640     }
3641
3642     if (ingres_errno) return(mr_errcode);
3643     return(MR_SUCCESS);
3644 }
3645
3646
3647 /* validate_chars: verify that there are no illegal characters in
3648  * the string.  Legal characters are printing chars other than
3649  * ", *, ?, \, [ and ].
3650  */
3651 static int illegalchars[] = {
3652     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
3653     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
3654     0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
3655     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
3656     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
3657     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
3658     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
3659     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
3660     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3661     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3662     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3663     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3664     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3665     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3666     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3667     1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3668 };
3669
3670 validate_chars(s)
3671 register char *s;
3672 {
3673     while (*s)
3674       if (illegalchars[*s++])
3675         return(MR_BAD_CHAR);
3676     return(MR_EXISTS);
3677 }
3678
3679
3680 validate_id(q, argv, vo)
3681     struct query *q;
3682     char *argv[];
3683     register struct valobj *vo;
3684 {
3685     EXEC SQL BEGIN DECLARE SECTION;
3686     char *name, *tbl, *namefield, *idfield;
3687     int id, rowcount;
3688     EXEC SQL END DECLARE SECTION;
3689     int status;
3690     register char *c;
3691
3692     name = argv[vo->index];
3693     tbl = vo->table;
3694     namefield = vo->namefield;
3695     idfield = vo->idfield;
3696
3697     if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
3698         !strcmp(tbl, "machine") ||
3699         !strcmp(tbl, "filesys") ||
3700         !strcmp(tbl, "list") ||
3701         !strcmp(tbl, "cluster") ||
3702         !strcmp(tbl, "strings")) {
3703         if (!strcmp(tbl, "machine"))
3704           for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3705         status = name_to_id(name, tbl, &id);
3706         if (status == 0) {
3707             *(int *)argv[vo->index] = id;
3708             return(MR_EXISTS);
3709         } else if (status == MR_NO_MATCH && !strcmp(tbl, "strings") &&
3710                    (q->type == APPEND || q->type == UPDATE)) {
3711             EXEC SQL SELECT value INTO :id FROM numvalues
3712               WHERE name = 'strings_id';
3713             id++;
3714             EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3715             EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3716             cache_entry(name, "STRING", id);
3717             *(int *)argv[vo->index] = id;
3718             return(MR_EXISTS);
3719         } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
3720           return(vo->error);
3721         else
3722           return(status);
3723     }
3724
3725     if (!strcmp(namefield, "uid")) {
3726         sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = %s",idfield,tbl,namefield,name);
3727     } else {
3728         sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",idfield,tbl,namefield,name);
3729     }
3730     EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3731     if(sqlca.sqlcode)
3732       return(MR_INTERNAL);
3733     EXEC SQL DECLARE csr127 CURSOR FOR stmt;
3734     EXEC SQL OPEN csr127;
3735     rowcount=0;
3736     EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3737     if(sqlca.sqlcode == 0) {
3738         rowcount++;
3739         EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3740         if(sqlca.sqlcode == 0) rowcount++;
3741     }
3742     EXEC SQL CLOSE csr127;
3743     if (ingres_errno)
3744       return(mr_errcode);
3745
3746     if (rowcount != 1) return(vo->error);
3747     bcopy(SQLDA->sqlvar[0].sqldata,argv[vo->index],sizeof(int));
3748     return(MR_EXISTS);
3749 }
3750
3751 validate_name(argv, vo)
3752     char *argv[];
3753     register struct valobj *vo;
3754 {
3755     EXEC SQL BEGIN DECLARE SECTION;
3756     char *name, *tbl, *namefield;
3757     int rowcount;
3758     EXEC SQL END DECLARE SECTION;
3759     register char *c;
3760
3761     name = argv[vo->index];
3762     tbl = vo->table;
3763     namefield = vo->namefield;
3764     if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
3765         for (c = name; *c; c++)
3766           if (islower(*c))
3767             *c = toupper(*c);
3768     }
3769     sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
3770             tbl,tbl,namefield,name);
3771     EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3772     if(sqlca.sqlcode)
3773       return(MR_INTERNAL);
3774     EXEC SQL DECLARE csr128 CURSOR FOR stmt;
3775     EXEC SQL OPEN csr128;
3776     EXEC SQL FETCH csr128 USING DESCRIPTOR :SQLDA;
3777     rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3778     EXEC SQL CLOSE csr128;
3779
3780     if (ingres_errno) return(mr_errcode);
3781     return ((rowcount == 1) ? MR_EXISTS : vo->error);
3782 }
3783
3784 validate_date(argv, vo)
3785     char *argv[];
3786     struct valobj *vo;
3787 {
3788     EXEC SQL BEGIN DECLARE SECTION;
3789     char *idate;
3790     double dd;
3791     int errorno;
3792     EXEC SQL END DECLARE SECTION;
3793
3794     idate = argv[vo->index];
3795     EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
3796
3797     if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
3798     return(MR_EXISTS);
3799 }
3800
3801
3802 validate_rename(argv, vo)
3803 char *argv[];
3804 struct valobj *vo;
3805 {
3806     EXEC SQL BEGIN DECLARE SECTION;
3807     char *name, *tbl, *namefield, *idfield;
3808     int id;
3809     EXEC SQL END DECLARE SECTION;
3810     int status;
3811     register char *c;
3812
3813     c = name = argv[vo->index];
3814     while (*c)
3815       if (illegalchars[*c++])
3816         return(MR_BAD_CHAR);
3817     tbl = vo->table;
3818     /* minor kludge to upcasify machine names */
3819     if (!strcmp(tbl, "machine"))
3820         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3821     namefield = vo->namefield;
3822     idfield = vo->idfield;
3823     id = -1;
3824     if (idfield == 0) {
3825         if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3826           return(MR_EXISTS);
3827         sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = LEFT('%s',SIZE(%s))",
3828                 namefield,tbl,namefield,name,namefield);
3829         EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3830         if(sqlca.sqlcode)
3831           return(MR_INTERNAL);
3832         EXEC SQL DECLARE csr129 CURSOR FOR stmt;
3833         EXEC SQL OPEN csr129;
3834         EXEC SQL FETCH csr129 USING DESCRIPTOR :SQLDA;
3835         if(sqlca.sqlcode == 0) id=1; else id=0;
3836         EXEC SQL CLOSE csr129;
3837
3838         if (ingres_errno) return(mr_errcode);
3839         if (id)
3840           return(vo->error);
3841         else
3842           return(MR_EXISTS);
3843     }
3844     status = name_to_id(name, tbl, &id);
3845     if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3846       return(MR_EXISTS);
3847     else
3848       return(vo->error);
3849 }
3850
3851
3852 validate_type(argv, vo)
3853     char *argv[];
3854     register struct valobj *vo;
3855 {
3856     EXEC SQL BEGIN DECLARE SECTION;
3857     char *typename;
3858     char *val;
3859     int cnt;
3860     EXEC SQL END DECLARE SECTION;
3861     register char *c;
3862
3863     typename = vo->table;
3864     c = val = argv[vo->index];
3865     while (*c) {
3866         if (illegalchars[*c++])
3867           return(MR_BAD_CHAR);
3868     }
3869
3870     /* uppercase type fields */
3871     for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
3872
3873     EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
3874       WHERE name = :typename AND type='TYPE' AND trans = :val;
3875     if (ingres_errno) return(mr_errcode);
3876     return (cnt ? MR_EXISTS : vo->error);
3877 }
3878
3879 /* validate member or type-specific data field */
3880
3881 validate_typedata(q, argv, vo)
3882     register struct query *q;
3883     register char *argv[];
3884     register struct valobj *vo;
3885 {
3886     EXEC SQL BEGIN DECLARE SECTION;
3887     char *name;
3888     char *field_type;
3889     char data_type[129];
3890     int id;
3891     EXEC SQL END DECLARE SECTION;
3892     int status;
3893     char *index();
3894     register char *c;
3895
3896     /* get named object */
3897     name = argv[vo->index];
3898
3899     /* get field type string (known to be at index-1) */
3900     field_type = argv[vo->index-1];
3901
3902     /* get corresponding data type associated with field type name */
3903     EXEC SQL SELECT trans INTO :data_type FROM alias
3904       WHERE name = :field_type AND type='TYPEDATA';
3905     if (ingres_errno) return(mr_errcode);
3906     if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
3907
3908     /* now retrieve the record id corresponding to the named object */
3909     if (index(data_type, ' '))
3910         *index(data_type, ' ') = 0;
3911     if (!strcmp(data_type, "user")) {
3912         /* USER */
3913         status = name_to_id(name, data_type, &id);
3914         if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3915           return(MR_USER);
3916         if (status) return(status);
3917     } else if (!strcmp(data_type, "list")) {
3918         /* LIST */
3919         status = name_to_id(name, data_type, &id);
3920         if (status && status == MR_NOT_UNIQUE)
3921           return(MR_LIST);
3922         if (status == MR_NO_MATCH) {
3923             /* if idfield is non-zero, then if argv[0] matches the string
3924              * that we're trying to resolve, we should get the value of
3925              * numvalues.[idfield] for the id.
3926              */
3927             if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3928                 set_next_object_id(q->validate->object_id, q->rtable, 0);
3929                 name = vo->idfield;
3930                 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
3931                   WHERE name = :name;
3932                 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
3933             } else
3934               return(MR_LIST);
3935         } else if (status) return(status);
3936     } else if (!strcmp(data_type, "machine")) {
3937         /* MACHINE */
3938         for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3939         status = name_to_id(name, data_type, &id);
3940         if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3941           return(MR_MACHINE);
3942         if (status) return(status);
3943     } else if (!strcmp(data_type, "string")) {
3944         /* STRING */
3945         status = name_to_id(name, data_type, &id);
3946         if (status && status == MR_NOT_UNIQUE)
3947           return(MR_STRING);
3948         if (status == MR_NO_MATCH) {
3949             if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3950             EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
3951             id++;
3952             EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3953             EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3954             cache_entry(name, "STRING", id);
3955         } else if (status) return(status);
3956     } else if (!strcmp(data_type, "none")) {
3957         id = 0;
3958     } else {
3959         return(MR_TYPE);
3960     }
3961
3962     /* now set value in argv */
3963     *(int *)argv[vo->index] = id;
3964
3965     return (MR_EXISTS);
3966 }
3967
3968
3969 /* Lock the table named by the validation object */
3970
3971 lock_table(vo)
3972 struct valobj *vo;
3973 {
3974     sprintf(stmt_buf,"UPDATE %s SET modtime='now' WHERE %s.%s = 0",
3975             vo->table,vo->table,vo->idfield);
3976     EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
3977     if (ingres_errno) return(mr_errcode);
3978     if (sqlca.sqlerrd[2] != 1)
3979       return(vo->error);
3980     else
3981       return(MR_EXISTS);
3982 }
3983
3984
3985 /* Check the database at startup time.  For now this just resets the
3986  * inprogress flags that the DCM uses.
3987  */
3988
3989 sanity_check_database()
3990 {
3991 }
3992
3993
3994 /* Dynamic SQL support routines */
3995 MR_SQLDA_T *mr_alloc_SQLDA()
3996 {
3997     MR_SQLDA_T *it;
3998     short *null_indicators;
3999     register int j;
4000
4001     if((it=(MR_SQLDA_T *)malloc(sizeof(MR_SQLDA_T)))==NULL) {
4002         com_err(whoami, MR_NO_MEM, "setting up SQLDA");
4003         exit(1);
4004     }
4005
4006     if((null_indicators=(short *)calloc(QMAXARGS,sizeof(short)))==NULL) {
4007         com_err(whoami, MR_NO_MEM, "setting up SQLDA null indicators");
4008         exit(1);
4009     }
4010
4011     for(j=0; j<QMAXARGS; j++) {
4012         if((it->sqlvar[j].sqldata=malloc(sizeof(short)+QMAXARGSIZE))==NULL) {
4013             com_err(whoami, MR_NO_MEM, "setting up SQLDA variables");
4014             exit(1);
4015         }
4016         it->sqlvar[j].sqllen=QMAXARGSIZE;
4017         it->sqlvar[j].sqlind=null_indicators+j;
4018         null_indicators[j]=0;
4019     }
4020     it->sqln=QMAXARGS;
4021     return it;
4022 }
4023
4024
4025 /* Use this after FETCH USING DESCRIPTOR one or more
4026  * result columns may contain NULLs.  This routine is
4027  * not currently needed, since db/schema creates all
4028  * columns with a NOT NULL WITH DEFAULT clause.
4029  *
4030  * This is currently dead flesh, since no Moira columns
4031  * allow null values; all use default values.
4032  */
4033 mr_fix_nulls_in_SQLDA(da)
4034     MR_SQLDA_T *da;
4035 {
4036     register IISQLVAR *var;
4037     register int j;
4038     int *intp;
4039
4040     for(j=0, var=da->sqlvar; j<da->sqld; j++, var++) {
4041         switch(var->sqltype) {
4042           case -IISQ_CHA_TYPE:
4043             if(*var->sqlind)
4044               *var->sqldata='\0';
4045             break;
4046           case -IISQ_INT_TYPE:
4047             if(*var->sqlind) {
4048                 intp=(int *)var->sqldata;
4049                 *intp=0;
4050             }
4051             break;
4052         }
4053     }
4054 }
4055
4056 /* prefetch_value():
4057  * This routine fetches an appropriate value from the numvalues table.
4058  * It is a little hack to get around the fact that SQL doesn't let you
4059  * do something like INSERT INTO table (foo) VALUES (other_table.bar).
4060  *
4061  * It is called from the query table as (*v->pre_rtn)(q,Argv,cl) or
4062  * from within a setup_...() routine with the appropriate arguments.
4063  *
4064  * Correct functioning of this routine may depend on the assumption
4065  * that this query is an APPEND.
4066  */
4067
4068 prefetch_value(q,argv,cl)
4069     struct query *q;
4070     char **argv;
4071     client *cl;
4072 {
4073     EXEC SQL BEGIN DECLARE SECTION;
4074     char *name = q->validate->object_id;
4075     int value;
4076     EXEC SQL END DECLARE SECTION;
4077     int status, limit, argc;
4078
4079     /* set next object id, limiting it if necessary */
4080     if(!strcmp(name, "uid") || !strcmp(name, "gid"))
4081       limit = 1; /* So far as I know, this isn't needed.  Just CMA. */
4082     else
4083       limit = 0;
4084     if((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
4085       return(status);
4086
4087     /* fetch object id */
4088     EXEC SQL SELECT value INTO :value FROM numvalues WHERE name=:name;
4089     if(ingres_errno) return(mr_errcode);
4090     if(sqlca.sqlerrd[2] != 1) return(MR_INTERNAL);
4091
4092     argc = q->argc + q->vcnt;   /* end of Argv for APPENDs */
4093     sprintf(argv[argc],"%d",value);  /** Could save this step by changing tlist from %s to %d **/
4094
4095     return(MR_SUCCESS);
4096 }
4097
4098 /* prefetch_filesys():
4099  * Fetches the phys_id from filesys based on the filsys_id in argv[0].
4100  * Appends the filsys_id and the phys_id to the argv so they can be
4101  * referenced in an INSERT into a table other than filesys.  Also
4102  * see comments at prefetch_value().
4103  *
4104  * Assumes the existence of a row where filsys_id = argv[0], since a
4105  * filesys label has already been resolved to a filsys_id.
4106  */
4107 prefetch_filesys(q,argv,cl)
4108     struct query *q;
4109     char **argv;
4110     client *cl;
4111 {
4112     EXEC SQL BEGIN DECLARE SECTION;
4113     int fid,phid;
4114     EXEC SQL END DECLARE SECTION;
4115     int argc;
4116
4117     fid = *(int *)argv[0];
4118     EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
4119     if(ingres_errno) return(mr_errcode);
4120
4121     argc=q->argc+q->vcnt;
4122     sprintf(argv[argc++],"%d",phid);
4123     sprintf(argv[argc],"%d",fid);
4124
4125     return(MR_SUCCESS);
4126 }
4127
4128 /* Convert normal Unix-style wildcards to SQL voodoo */
4129 convert_wildcards(arg)
4130     char *arg;
4131 {
4132     static char buffer[QMAXARGSIZE];
4133     register char *s, *d;
4134
4135     for(d=buffer,s=arg;*s;s++) {
4136         switch(*s) {
4137           case '*': *d++='%'; *d++='%'; break;
4138           case '?': *d++='_'; break;
4139           case '_':
4140           case '[':
4141           case ']': *d++='*'; *d++ = *s; break;
4142           case '%': *d++='*'; *d++='%'; *d++='%'; break;
4143           default: *d++ = *s; break;
4144         }
4145     }
4146     *d='\0';
4147
4148     /* Copy back into argv */
4149     strcpy(arg,buffer);
4150
4151     return(MR_EXISTS);
4152 }
4153
4154 /* This version includes uppercase conversion, for things like gmac.
4155  * This is necessary because "LIKE" doesn't work with "uppercase()".
4156  * Including it in a wildcard routine saves making two passes over
4157  * the argument string.
4158  */
4159 convert_wildcards_uppercase(arg)
4160     char *arg;
4161 {
4162     static char buffer[QMAXARGSIZE];
4163     register char *s, *d;
4164
4165     for(d=buffer,s=arg;*s;s++) {
4166         switch(*s) {
4167           case '*': *d++='%'; *d++='%'; break;
4168           case '?': *d++='_'; break;
4169           case '_':
4170           case '[':
4171           case ']': *d++='*'; *d++ = *s; break;
4172           case '%': *d++='*'; *d++='%'; *d++='%'; break;
4173           default: *d++=toupper(*s); break;       /* This is the only diff. */
4174         }
4175     }
4176     *d='\0';
4177
4178     /* Copy back into argv */
4179     strcpy(arg,buffer);
4180
4181     return(MR_EXISTS);
4182 }
4183
4184
4185 /* Looks like it's time to build an abstraction barrier, Yogi */
4186 mr_select_any(stmt)
4187     EXEC SQL BEGIN DECLARE SECTION; 
4188     char *stmt;
4189     EXEC SQL END DECLARE SECTION; 
4190 {
4191     int result=0;
4192
4193     EXEC SQL PREPARE stmt FROM :stmt;
4194     EXEC SQL DESCRIBE stmt INTO :SQLDA;
4195     if(SQLDA->sqld==0)                       /* Not a SELECT */
4196         return(MR_INTERNAL);        
4197     EXEC SQL DECLARE csr CURSOR FOR stmt;
4198     EXEC SQL OPEN csr;
4199     EXEC SQL FETCH csr USING DESCRIPTOR :SQLDA;
4200     if(sqlca.sqlcode==0) 
4201         result=MR_EXISTS;
4202     else if((sqlca.sqlcode<0) && mr_errcode)
4203         result=mr_errcode;
4204     else
4205         result=0;
4206     EXEC SQL CLOSE csr;
4207     return(result);
4208
4209
4210
4211
4212 static hex_dump(p)
4213 unsigned  char *p;
4214 {
4215     char buf[BUFSIZ];
4216     int i;
4217
4218     fprintf(stderr, "Size: %d\n", strlen(p));
4219     while (strlen(p) >= 8) {
4220         fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
4221                 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
4222         p += 8;
4223     }
4224     switch (strlen(p)) {
4225     case 7:
4226         fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x\n",
4227                 p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
4228         break;
4229     case 6:
4230         fprintf(stderr, "%02x %02x %02x %02x %02x %02x\n",
4231                 p[0], p[1], p[2], p[3], p[4], p[5]);
4232         break;
4233     case 5:
4234         fprintf(stderr, "%02x %02x %02x %02x %02x\n",
4235                 p[0], p[1], p[2], p[3], p[4]);
4236         break;
4237     case 4:
4238         fprintf(stderr, "%02x %02x %02x %02x\n",
4239                 p[0], p[1], p[2], p[3]);
4240         break;
4241     case 3:
4242         fprintf(stderr, "%02x %02x %02x\n",
4243                 p[0], p[1], p[2]);
4244         break;
4245     case 2:
4246         fprintf(stderr, "%02x %02x\n",
4247                 p[0], p[1]);
4248         break;
4249     case 1:
4250         fprintf(stderr, "%02x\n",
4251                 p[0]);
4252         break;
4253     default:
4254         return;
4255     }
4256 }
4257
4258 /* eof:qsupport.dc */
This page took 0.36176 seconds and 3 git commands to generate.