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