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