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