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