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