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