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