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