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