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