6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
13 static char *rcsid_qsupport_dc = "$Header$";
16 #include <mit-copyright.h>
18 #include "mr_server.h"
23 EXEC SQL INCLUDE sqlca;
24 EXEC SQL INCLUDE sqlda;
27 extern char *whoami, *strsave();
28 extern int ingres_errno, mr_errcode;
30 EXEC SQL BEGIN DECLARE SECTION;
31 extern char stmt_buf[];
34 EXEC SQL END DECLARE SECTION;
36 /* Specialized Access Routines */
38 /* access_user - verify that client name equals specified login name
40 * - since field validation routines are called first, a users_id is
41 * now in argv[0] instead of the login name.
44 EXEC SQL WHENEVER SQLERROR CALL ingerr;
46 access_user(q, argv, cl)
51 if (cl->users_id != *(int *)argv[0])
59 /* access_login - verify that client name equals specified login name
61 * argv[0...n] contain search info. q->
64 access_login(q, argv, cl)
69 EXEC SQL BEGIN DECLARE SECTION;
72 EXEC SQL END DECLARE SECTION;
74 build_qual(q->qual, q->argc, argv, qual);
75 if (!strncmp(q->name,"get_user_account",strlen("get_user_account"))) {
76 EXEC SQL SELECT users_id INTO :id FROM users u, strings str WHERE :qual;
78 EXEC SQL SELECT users_id INTO :id FROM users u WHERE :qual;
81 if (sqlca.sqlerrd[2] != 1 || id != cl->users_id)
89 /* access_list - check access for most list operations
91 * Inputs: argv[0] - list_id
93 * argv[2] - member ID (only for queries "amtl" and "dmfl")
94 * argv[7] - group IID (only for query "ulis")
97 * - check that client is a member of the access control list
98 * - OR, if the query is add_member_to_list or delete_member_from_list
99 * and the list is public, allow access if client = member
102 access_list(q, argv, cl)
107 EXEC SQL BEGIN DECLARE SECTION;
108 int list_id, acl_id, flags, gid;
110 EXEC SQL END DECLARE SECTION;
112 int client_id, status;
114 list_id = *(int *)argv[0];
115 EXEC SQL SELECT acl_id, acl_type, gid, publicflg
116 INTO :acl_id, :acl_type, :gid, :flags
118 WHERE list_id = :list_id;
120 if (sqlca.sqlerrd[2] != 1)
123 /* parse client structure */
124 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
127 /* if amtl or dmfl and list is public allow client to add or delete self */
128 if (((!strcmp("amtl", q->shortname) && flags) ||
129 (!strcmp("dmfl", q->shortname))) &&
130 (!strcmp("USER", argv[1]))) {
131 if (*(int *)argv[2] == client_id) return(MR_SUCCESS);
132 /* if update_list, don't allow them to change the GID */
133 } else if (!strcmp("ulis", q->shortname)) {
134 if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
135 (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
139 /* check for client in access control list */
140 status = find_member(acl_type, acl_id, client_type, client_id, 0);
141 if (!status) return(MR_PERM);
147 /* access_visible_list - allow access to list only if it is not hidden,
148 * or if the client is on the ACL
150 * Inputs: argv[0] - list_id
151 * cl - client identifier
154 access_visible_list(q, argv, cl)
159 EXEC SQL BEGIN DECLARE SECTION;
160 int list_id, acl_id, flags ;
162 EXEC SQL END DECLARE SECTION;
164 int client_id, status;
166 list_id = *(int *)argv[0];
167 EXEC SQL SELECT hidden, acl_id, acl_type
168 INTO :flags, :acl_id, :acl_type
170 WHERE list_id = :list_id;
171 if (sqlca.sqlerrd[2] != 1)
176 /* parse client structure */
177 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
180 /* check for client in access control list */
181 status = find_member(acl_type, acl_id, client_type, client_id, 0);
189 /* access_vis_list_by_name - allow access to list only if it is not hidden,
190 * or if the client is on the ACL
192 * Inputs: argv[0] - list name
193 * cl - client identifier
196 access_vis_list_by_name(q, argv, cl)
201 EXEC SQL BEGIN DECLARE SECTION;
202 int acl_id, flags, rowcount;
203 char acl_type[9], *listname;
204 EXEC SQL END DECLARE SECTION;
206 int client_id, status;
209 EXEC SQL SELECT hidden, acl_id, acl_type INTO :flags, :acl_id, :acl_type
210 FROM list WHERE name = :listname;
212 rowcount=sqlca.sqlerrd[2];
220 /* parse client structure */
221 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
224 /* check for client in access control list */
225 status = find_member(acl_type, acl_id, client_type, client_id, 0);
233 /* access_member - allow user to access member of type "USER" and name matches
234 * username, or to access member of type "LIST" and list is one that user is
235 * on the acl of, or the list is visible.
238 access_member(q, argv, cl)
243 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
244 return(access_visible_list(q, &argv[1], cl));
246 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
247 if (cl->users_id == *(int *)argv[1])
251 if (!strcmp(argv[0], "KERBEROS") || !strcmp(argv[0], "RKERBERO")) {
252 if (cl->client_id == *(int *)argv[1])
260 /* access_qgli - special access routine for Qualified_get_lists. Allows
261 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
264 access_qgli(q, argv, cl)
269 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
275 /* access_service - allow access if user is on ACL of service. Don't
276 * allow access if a wildcard is used.
279 access_service(q, argv, cl)
284 EXEC SQL BEGIN DECLARE SECTION;
286 char *name, acl_type[9];
287 EXEC SQL END DECLARE SECTION;
288 int client_id, status;
289 char *client_type, *c;
292 for(c=name;*c;c++) if(islower(*c)) *c = toupper(*c); /* uppercasify */
293 EXEC SQL SELECT acl_id, acl_type INTO :acl_id, :acl_type FROM servers
295 if (sqlca.sqlerrd[2] > 1)
298 /* parse client structure */
299 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
302 /* check for client in access control list */
303 status = find_member(acl_type, acl_id, client_type, client_id, 0);
304 if (!status) return(MR_PERM);
310 /* access_filesys - verify that client is owner or on owners list of filesystem
314 access_filesys(q, argv, cl)
319 EXEC SQL BEGIN DECLARE SECTION;
320 int users_id, list_id;
322 EXEC SQL END DECLARE SECTION;
323 int status, client_id;
327 EXEC SQL SELECT owner, owners INTO :users_id, :list_id FROM filesys
330 if (sqlca.sqlerrd[2] != 1)
332 if (users_id == cl->users_id)
334 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
336 status = find_member("LIST", list_id, client_type, client_id, 0);
347 /* Setup routine for add_user
349 * Inputs: argv[0] - login
354 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
355 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
358 setup_ausr(q, argv, cl)
360 register char *argv[];
364 EXEC SQL BEGIN DECLARE SECTION;
366 EXEC SQL END DECLARE SECTION;
368 if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
372 if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1) {
373 if (set_next_object_id("uid", "users", 1))
374 return(MR_INGRES_ERR);
375 EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'uid';
376 if (sqlca.sqlerrd[2] != 1)
378 sprintf(argv[row], "%d", nuid);
381 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1) {
382 sprintf(argv[0], "#%s", argv[row]);
385 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
392 /* setup_dusr - verify that the user is no longer being referenced
393 * and may safely be deleted.
396 int setup_dusr(q, argv)
400 EXEC SQL BEGIN DECLARE SECTION;
402 EXEC SQL END DECLARE SECTION;
404 id = *(int *)argv[0];
406 /* For now, only allow users to be deleted if their status is 0 */
407 EXEC SQL REPEATED SELECT status INTO :flag FROM users
408 WHERE users_id = :id;
409 if (flag != 0 && flag != 4)
412 EXEC SQL REPEATED DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
413 EXEC SQL REPEATED DELETE FROM krbmap WHERE users_id = :id;
414 EXEC SQL REPEATED SELECT member_id INTO :idummy FROM imembers
415 WHERE member_id = :id AND member_type = 'USER';
416 if (sqlca.sqlerrd[2] > 0)
418 EXEC SQL REPEATED SELECT label INTO :cdummy FROM filesys WHERE owner = :id;
419 if (sqlca.sqlerrd[2]> 0)
421 EXEC SQL REPEATED SELECT name INTO :cdummy FROM list
422 WHERE acl_id = :id AND acl_type = 'USER';
423 if (sqlca.sqlerrd[2] > 0)
425 EXEC SQL REPEATED SELECT name INTO :cdummy FROM servers
426 WHERE acl_id = :id AND acl_type = 'USER';
427 if (sqlca.sqlerrd[2] > 0)
429 EXEC SQL REPEATED SELECT acl_id INTO :idummy FROM hostaccess
430 WHERE acl_id = :id AND acl_type = 'USER';
431 if (sqlca.sqlerrd[2] > 0)
439 /* setup_spop: verify that there is already a valid POP machine_id in the
440 * pop_id field. Also take care of keeping track of the post office usage.
442 int setup_spop(q, argv)
446 EXEC SQL BEGIN DECLARE SECTION;
449 EXEC SQL END DECLARE SECTION;
451 id = *(int *)argv[0];
452 EXEC SQL REPEATED SELECT potype, pop_id INTO :type, :mid FROM users
453 WHERE users_id = :id;
454 if(sqlca.sqlerrd[2] = 0)
456 EXEC SQL REPEATED SELECT mach_id INTO :mid FROM machine
457 WHERE mach_id = :mid;
458 if (sqlca.sqlerrd[2] = 0)
460 if (strcmp(strtrim(type), "POP"))
461 set_pop_usage(mid, 1);
466 /* setup_dpob: Take care of keeping track of the post office usage.
468 int setup_dpob(q, argv)
472 EXEC SQL BEGIN DECLARE SECTION;
475 EXEC SQL END DECLARE SECTION;
477 user = *(int *)argv[0];
478 EXEC SQL REPEATED SELECT potype, pop_id INTO :type, :id FROM users
479 WHERE users_id = :user;
480 if (ingres_errno) return(mr_errcode);
482 if (!strcmp(strtrim(type), "POP"))
483 set_pop_usage(id, -1);
488 /* setup_dmac - verify that the machine is no longer being referenced
489 * and may safely be deleted.
492 int setup_dmac(q, argv)
496 EXEC SQL BEGIN DECLARE SECTION;
498 EXEC SQL END DECLARE SECTION;
500 id = *(int *)argv[0];
501 EXEC SQL REPEATED SELECT login INTO :cdummy FROM users
502 WHERE potype='POP' AND pop_id = :id;
503 if (sqlca.sqlerrd[2] > 0)
505 EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM serverhosts
507 if (sqlca.sqlerrd[2] > 0)
509 EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM nfsphys
511 if (sqlca.sqlerrd[2] > 0)
513 EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM hostaccess
515 if (sqlca.sqlerrd[2] > 0)
517 EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM printcap
519 if (sqlca.sqlerrd[2] > 0)
521 EXEC SQL REPEATED SELECT quotaserver INTO :idummy FROM printcap
522 WHERE quotaserver = :id;
523 if (sqlca.sqlerrd[2] > 0)
525 EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM palladium
527 if (sqlca.sqlerrd[2] > 0)
530 EXEC SQL REPEATED DELETE FROM mcmap WHERE mach_id = :id;
531 if (ingres_errno) return(mr_errcode);
536 /* setup_dclu - verify that the cluster is no longer being referenced
537 * and may safely be deleted.
540 int setup_dclu(q, argv)
544 EXEC SQL BEGIN DECLARE SECTION;
546 EXEC SQL END DECLARE SECTION;
548 id = *(int *)argv[0];
549 EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM mcmap
551 if (sqlca.sqlerrd[2] > 0)
553 EXEC SQL REPEATED SELECT clu_id INTO :idummy FROM svc
555 if (sqlca.sqlerrd[2] > 0)
563 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
564 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
565 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
566 * a -1 there. Remember that this is also used for ulis, with the indexes
567 * at 6 & 7. Also check that the list name does not contain uppercase
568 * characters, control characters, @, or :.
571 static int badlistchars[] = {
572 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
573 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
574 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
575 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
576 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
577 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, /* P - _ */
578 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
579 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
580 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
581 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
582 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
583 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
584 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
585 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
586 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
587 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
590 int setup_alis(q, argv, cl)
595 EXEC SQL BEGIN DECLARE SECTION;
597 EXEC SQL END DECLARE SECTION;
602 if (!strcmp(q->shortname, "alis"))
604 else if (!strcmp(q->shortname, "ulis"))
607 for (p = (unsigned char *) argv[idx]; *p; p++)
608 if (badlistchars[*p])
611 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1) {
612 if (atoi(argv[5 + idx])) {
613 if (set_next_object_id("gid", "list", 1))
614 return(MR_INGRES_ERR);
615 EXEC SQL REPEATED SELECT value INTO :ngid FROM numvalues
617 if (ingres_errno) return(mr_errcode);
618 sprintf(argv[6 + idx], "%d", ngid);
620 strcpy(argv[6 + idx], "-1");
624 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
631 /* setup_dlis - verify that the list is no longer being referenced
632 * and may safely be deleted.
635 int setup_dlis(q, argv)
641 id = *(int *)argv[0];
642 sprintf(stmt_buf,"SELECT member_id FROM imembers WHERE member_id = %d AND member_type='LIST'",id);
643 if(ec=mr_select_any(stmt_buf)) {
644 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
647 sprintf(stmt_buf,"SELECT member_id FROM imembers WHERE list_id = %d",id);
648 if(ec=mr_select_any(stmt_buf)) {
649 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
652 sprintf(stmt_buf,"SELECT label FROM filesys WHERE owners = %d",id);
653 if(ec=mr_select_any(stmt_buf)) {
654 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
657 sprintf(stmt_buf,"SELECT tag FROM capacls WHERE list_id = %d",id);
658 if(ec=mr_select_any(stmt_buf)) {
659 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
662 sprintf(stmt_buf,"SELECT name FROM list WHERE acl_id = %d AND acl_type='LIST' AND list_id != %d",id,id);
663 if(ec=mr_select_any(stmt_buf)) {
664 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
667 sprintf(stmt_buf,"SELECT name FROM servers WHERE acl_id = %d AND acl_type='LIST'",id);
668 if(ec=mr_select_any(stmt_buf)) {
669 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
672 sprintf(stmt_buf,"SELECT entity_id FROM quota WHERE entity_id = %d AND type='GROUP'",id);
673 if(ec=mr_select_any(stmt_buf)) {
674 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
677 sprintf(stmt_buf,"SELECT acl_id FROM hostaccess WHERE acl_id = %d AND acl_type='LIST'",id);
678 if(ec=mr_select_any(stmt_buf)) {
679 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
682 sprintf(stmt_buf,"SELECT class FROM zephyr z \
683 WHERE z.xmt_type = 'LIST' AND z.xmt_id = %d \
684 OR z.sub_type = 'LIST' AND z.sub_id = %d \
685 OR z.iws_type = 'LIST' AND z.iws_id = %d \
686 OR z.iui_type = 'LIST' AND z.iui_id = %d",id,id,id,id);
687 if(ec=mr_select_any(stmt_buf)) {
688 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
695 /* setup_dsin - verify that the service is no longer being referenced
696 * and may safely be deleted.
699 int setup_dsin(q, argv)
705 sprintf(stmt_buf,"SELECT service FROM serverhosts WHERE service = UPPERCASE('%s')",argv[0]);
706 if(ec=mr_select_any(stmt_buf)) {
707 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
710 sprintf(stmt_buf,"SELECT inprogress FROM servers WHERE name = UPPERCASE('%s')",argv[0]);
711 if(ec=mr_select_any(stmt_buf)) {
712 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
719 /* setup_dshi - verify that the service-host is no longer being referenced
720 * and may safely be deleted.
723 int setup_dshi(q, argv)
727 EXEC SQL BEGIN DECLARE SECTION;
729 EXEC SQL END DECLARE SECTION;
731 id = *(int *)argv[1];
733 sprintf(stmt_buf,"SELECT inprogress FROM serverhosts \
734 WHERE service = UPPERCASE('%s') AND mach_id = %d",argv[0],id);
735 if(ec=mr_select_any(stmt_buf)) {
736 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
744 ** setup_add_filesys - verify existance of referenced file systems
756 ** * extract directory prefix from name
757 ** * verify mach_id/dir in nfsphys
758 ** * verify access in {r, w, R, W}
760 ** Side effect: sets variable var_phys_id to the ID of the physical
761 ** filesystem (nfsphys_id for NFS, 0 for RVD)
764 ** MR_NFS - specified directory not exported
765 ** MR_FILESYS_ACCESS - invalid filesys access
769 EXEC SQL BEGIN DECLARE SECTION;
770 static int var_phys_id;
771 EXEC SQL END DECLARE SECTION;
773 setup_afil(q, argv, cl)
780 EXEC SQL BEGIN DECLARE SECTION;
782 char ftype[32], *access;
783 EXEC SQL END DECLARE SECTION;
786 mach_id = *(int *)argv[2];
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; /** Use mr_select_any() */
794 if (ingres_errno) return(mr_errcode);
795 if (sqlca.sqlerrd[2] == 0) return(MR_FILESYS_ACCESS);
797 if (!strcmp(type, "NFS"))
798 return (check_nfs(mach_id, name, access));
800 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
807 /* Verify the arguments, depending on the FStype. Also, if this is an
808 * NFS filesystem, then update any quotas for that filesystem to reflect
812 setup_ufil(q, argv, cl)
819 EXEC SQL BEGIN DECLARE SECTION;
821 char *entity, ftype[32], *access;
823 EXEC SQL END DECLARE SECTION;
826 mach_id = *(int *)argv[3];
829 fid = *(int *)argv[0];
833 sprintf(ftype, "fs_access_%s", type);
834 EXEC SQL SELECT trans INTO :cdummy FROM alias
835 WHERE name = :ftype AND type='TYPE' AND trans = :access;
836 if (ingres_errno) return(mr_errcode);
837 if (sqlca.sqlerrd[2] == 0) return(MR_FILESYS_ACCESS);
839 if (!strcmp(type, "NFS")) {
840 status = check_nfs(mach_id, name, access);
841 EXEC SQL UPDATE quota SET phys_id = :var_phys_id
842 WHERE filsys_id = :fid;
843 if (ingres_errno) return(mr_errcode);
845 } else if (!strcmp(type, "AFS")) {
847 EXEC SQL REPEATED DELETE FROM quota
848 WHERE type = 'ANY' AND filsys_id = :fid;
849 EXEC SQL SELECT SUM (quota) INTO :total FROM quota
850 WHERE filsys_id = :fid AND phys_id != 0;
851 if (ingres_errno) return(mr_errcode);
854 * append quota (quota = total, filsys_id = fid,
855 * phys_id = 0, entity_id = 0, type = "ANY",
856 * modtime = "now", modby = who, modwith = entity)
858 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
859 type, modtime, modby, modwith)
860 VALUES (:total, :fid, 0, 0,
861 'ANY', 'now', :who, :entity) ;
862 if (ingres_errno) return(mr_errcode);
865 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
866 if (ingres_errno) return(mr_errcode);
872 /* Find the NFS physical partition that the named directory is on.
873 * This is done by comparing the dir against the mount point of the
874 * partition. To make sure we get the correct match when there is
875 * more than one, we sort the query in reverse order by dir name.
878 check_nfs(mach_id, name, access)
879 EXEC SQL BEGIN DECLARE SECTION;
881 EXEC SQL END DECLARE SECTION;
885 EXEC SQL BEGIN DECLARE SECTION;
887 EXEC SQL END DECLARE SECTION;
894 EXEC SQL DECLARE csr101 CURSOR FOR
895 SELECT nfsphys_id, TRIM (dir) FROM nfsphys
896 WHERE mach_id = :mach_id
898 EXEC SQL OPEN csr101;
900 EXEC SQL FETCH csr101 INTO :var_phys_id, :dir;
901 if(sqlca.sqlcode != 0) break;
905 if (*cp1++ != *cp2) break;
913 EXEC SQL CLOSE csr101;
920 /* setup_dfil: free any quota records and fsgroup info associated with
921 * a filesystem when it is deleted. Also adjust the allocation numbers.
924 setup_dfil(q, argv, cl)
929 EXEC SQL BEGIN DECLARE SECTION;
931 EXEC SQL END DECLARE SECTION;
933 id = *(int *)argv[0];
934 EXEC SQL REPEATED SELECT SUM (quota) INTO :total FROM quota
935 WHERE filsys_id = :id;
936 EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated - :total
937 WHERE nfsphys_id = filesys.phys_id AND filesys.filsys_id = :id;
938 /** Is SQL smart enough to do the PRODUCT above? */
939 /** Or should we code it using another SELECT? */
941 EXEC SQL REPEATED DELETE FROM quota WHERE filsys_id = :id;
942 EXEC SQL REPEATED DELETE FROM fsgroup WHERE filsys_id = :id;
943 EXEC SQL REPEATED DELETE FROM fsgroup WHERE group_id = :id;
944 if (ingres_errno) return(mr_errcode);
949 /* setup_dnfp: check to see that the nfs physical partition does not have
950 * any filesystems assigned to it before allowing it to be deleted.
953 setup_dnfp(q, argv, cl)
958 EXEC SQL BEGIN DECLARE SECTION;
961 EXEC SQL END DECLARE SECTION;
963 id = *(int *)argv[0];
965 EXEC SQL REPEATED SELECT label INTO :cdummy FROM filesys fs, nfsphys np
966 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
967 AND np.mach_id = :id AND np.dir = :dir;
968 if (sqlca.sqlerrd[2] > 0)
976 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
977 * argv[0] = filsys_id
978 * argv[1] = type if "update_quota" or "delete_quota"
979 * argv[2 or 1] = users_id or list_id
982 setup_dqot(q, argv, cl)
987 EXEC SQL BEGIN DECLARE SECTION;
988 int quota, fs, id, physid;
990 EXEC SQL END DECLARE SECTION;
992 fs = *(int *)argv[0];
993 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
995 id = *(int *)argv[2];
998 id = *(int *)argv[1];
1001 EXEC SQL REPEATED SELECT quota INTO :quota FROM quota
1002 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
1003 EXEC SQL REPEATED SELECT phys_id INTO :physid FROM filesys
1004 WHERE filsys_id = :fs;
1005 EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated - :quota
1006 WHERE nfsphys_id = :physid;
1008 if (ingres_errno) return(mr_errcode);
1013 /* setup_sshi: don't exclusive lock the machine table during
1014 * set_server_host_internal.
1017 setup_sshi(q, argv, cl)
1023 EXEC SQL set lockmode session where readlock = system;
1028 /* setup add_kerberos_user_mapping: add the string to the string
1029 * table if necessary.
1032 setup_akum(q, argv, cl)
1037 EXEC SQL BEGIN DECLARE SECTION;
1040 EXEC SQL END DECLARE SECTION;
1043 if (name_to_id(name, "STRING", &id) != MR_SUCCESS) {
1044 if (q->type != APPEND) return(MR_STRING);
1045 EXEC SQL SELECT value INTO :id FROM numvalues
1046 WHERE name = 'strings_id';
1048 EXEC SQL UPDATE numvalues SET value = :id
1049 WHERE name = 'strings_id';
1050 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
1051 cache_entry(name, "STRING", id);
1053 if (ingres_errno) return(mr_errcode);
1054 *(int *)argv[1] = id;
1060 /* FOLLOWUP ROUTINES */
1062 /* generic set_modtime routine. This takes the table name from the query,
1063 * and will update the modtime, modby, and modwho fields in the entry in
1064 * the table whose name field matches argv[0].
1067 set_modtime(q, argv, cl)
1072 char *name, *entity, *table;
1075 entity = cl->entity;
1076 who = cl->client_id;
1080 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, modwith = '%s' WHERE %s.name = LEFT('%s',SIZE(%s.name))",table,who,entity,table,name,table);
1081 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1086 /* generic set_modtime_by_id routine. This takes the table name from
1087 * the query, and the id name from the validate record,
1088 * and will update the modtime, modby, and modwho fields in the entry in
1089 * the table whose id matches argv[0].
1092 set_modtime_by_id(q, argv, cl)
1097 char *entity, *table, *id_name;
1100 entity = cl->entity;
1101 who = cl->client_id;
1103 id_name = q->validate->object_id;
1105 id = *(int *)argv[0];
1106 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, \
1107 modwith = '%s' WHERE %s.%s = %d",table,who,entity,table,id_name,id);
1108 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1113 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
1116 set_finger_modtime(q, argv, cl)
1121 EXEC SQL BEGIN DECLARE SECTION;
1124 EXEC SQL END DECLARE SECTION;
1126 entity = cl->entity;
1127 who = cl->client_id;
1128 users_id = *(int *)argv[0];
1130 EXEC SQL UPDATE users SET fmodtime='now', fmodby = :who, fmodwith = :entity
1131 WHERE users.users_id = :users_id;
1137 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
1140 set_pobox_modtime(q, argv, cl)
1145 EXEC SQL BEGIN DECLARE SECTION;
1148 EXEC SQL END DECLARE SECTION;
1150 entity = cl->entity;
1151 who = cl->client_id;
1152 users_id = *(int *)argv[0];
1154 EXEC SQL UPDATE users SET pmodtime='now', pmodby = :who, pmodwith = :entity
1155 WHERE users.users_id = :users_id;
1161 /* Like set_modtime, but uppercases the name first.
1164 set_uppercase_modtime(q, argv, cl)
1169 char *name, *entity, *table;
1172 entity = cl->entity;
1173 who = cl->client_id;
1177 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, modwith = '%s' WHERE %s.name = UPPERCASE(LEFT('%s',SIZE(%s.name)))",table,who,entity,table,name,table);
1178 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1184 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
1185 * is necessary for add_machine_to_cluster becuase the table that query
1186 * operates on is "mcm", not "machine".
1189 set_mach_modtime_by_id(q, argv, cl)
1194 EXEC SQL BEGIN DECLARE SECTION;
1197 EXEC SQL END DECLARE SECTION;
1199 entity = cl->entity;
1200 who = cl->client_id;
1201 id = *(int *)argv[0];
1202 EXEC SQL UPDATE machine SET modtime='now', modby = :who, modwith = :entity
1203 WHERE machine.mach_id = :id;
1209 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
1210 * is necessary for add_cluster_data and delete_cluster_data becuase the
1211 * table that query operates on is "svc", not "cluster".
1214 set_cluster_modtime_by_id(q, argv, cl)
1219 EXEC SQL BEGIN DECLARE SECTION;
1222 EXEC SQL END DECLARE SECTION;
1224 entity = cl->entity;
1225 who = cl->client_id;
1227 id = *(int *)argv[0];
1228 EXEC SQL UPDATE cluster SET modtime='now', modby = :who, modwith = :entity
1229 WHERE cluster.clu_id = :id;
1234 /* sets the modtime on the serverhost where the service name is in argv[0]
1235 * and the mach_id is in argv[1].
1238 set_serverhost_modtime(q, argv, cl)
1243 EXEC SQL BEGIN DECLARE SECTION;
1244 char *entity, *serv;
1246 EXEC SQL END DECLARE SECTION;
1248 entity = cl->entity;
1249 who = cl->client_id;
1252 id = *(int *)argv[1];
1253 EXEC SQL UPDATE serverhosts
1254 SET modtime = 'now', modby = :who, modwith = :entity
1255 WHERE service = :serv AND mach_id = :id;
1260 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1261 * directory name is in argv[1].
1264 set_nfsphys_modtime(q, argv, cl)
1269 EXEC SQL BEGIN DECLARE SECTION;
1272 EXEC SQL END DECLARE SECTION;
1274 entity = cl->entity;
1275 who = cl->client_id;
1277 id = *(int *)argv[0];
1279 EXEC SQL UPDATE nfsphys SET modtime = 'now', modby = :who, modwith = :entity
1280 WHERE dir = :dir AND mach_id = :id;
1285 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1289 set_filesys_modtime(q, argv, cl)
1294 EXEC SQL BEGIN DECLARE SECTION;
1295 char *label, *entity;
1297 EXEC SQL END DECLARE SECTION;
1299 entity = cl->entity;
1300 who = cl->client_id;
1303 if (!strcmp(q->shortname, "ufil"))
1306 EXEC SQL UPDATE filesys SET modtime = 'now', modby = :who,
1307 modwith = :entity, phys_id = :var_phys_id
1308 WHERE label = LEFT(:label,SIZE(label));
1313 /* sets the modtime on a zephyr class, where argv[0] contains the class
1317 set_zephyr_modtime(q, argv, cl)
1322 EXEC SQL BEGIN DECLARE SECTION;
1323 char *class, *entity;
1325 EXEC SQL END DECLARE SECTION;
1327 entity = cl->entity;
1328 who = cl->client_id;
1332 EXEC SQL UPDATE zephyr SET modtime = 'now', modby = :who, modwith = :entity
1333 WHERE class = LEFT(:class,SIZE(class));
1339 /* fixes the modby field. This will be the second to last thing in the
1340 * argv, the argv length is determined from the query structure. It is
1341 * passed as a pointer to an integer. This will either turn it into a
1342 * username, or # + the users_id.
1344 followup_fix_modby(q, sq, v, action, actarg, cl)
1346 register struct save_queue *sq;
1348 register int (*action)();
1349 register int actarg;
1353 char **argv, *malloc();
1357 while (sq_get_data(sq, &argv)) {
1360 status = id_to_name(id, "USER", &argv[i]);
1362 status = id_to_name(-id, "STRING", &argv[i]);
1363 if (status && status != MR_NO_MATCH)
1365 (*action)(q->vcnt, argv, actarg);
1366 for (j = 0; j < q->vcnt; j++)
1375 /* After retrieving a user account, fix the modby field and signature.
1376 * The modby field is the second to last thing in the
1377 * argv, the argv length is determined from the query structure. It is
1378 * passed as a pointer to an integer. This will either turn it into a
1379 * username, or # + the users_id. Only "gua*" queries have a signature,
1380 * these are ones with U_END return values. "gub*" queries also use this
1381 * routine but don't have a signature.
1383 followup_guax(q, sq, v, action, actarg, cl)
1385 register struct save_queue *sq;
1387 register int (*action)();
1388 register int actarg;
1392 char **argv, *malloc();
1394 unsigned char sigbuf[256];
1397 EXEC SQL BEGIN DECLARE SECTION;
1400 EXEC SQL END DECLARE SECTION;
1405 while (sq_get_data(sq, &argv)) {
1408 status = id_to_name(id, "USER", &argv[i]);
1410 status = id_to_name(-id, "STRING", &argv[i]);
1411 if (status && status != MR_NO_MATCH)
1414 if (q->vcnt == U_END && strlen(argv[U_SIGNATURE])) {
1415 login = argv[U_NAME];
1416 EXEC SQL REPEATED SELECT sigdate, sigwho
1417 INTO :timestamp, :who FROM users
1418 WHERE login = LEFT(:login,SIZE(login));
1419 /** What about (INGRES) error handling? **/
1421 status = id_to_name(who, "STRING", &kname);
1422 si.timestamp = timestamp;
1423 si.SigInfoVersion = 0; /* XXXXX this isn't used */
1424 kname_parse(si.pname, si.pinst, si.prealm, kname);
1426 si.rawsig = (unsigned char *)argv[U_SIGNATURE];
1427 GDSS_Recompose(&si, sigbuf);
1428 argv[U_SIGNATURE] = strsave(sigbuf);
1431 (*action)(q->vcnt, argv, actarg);
1432 for (j = 0; j < q->vcnt; j++)
1442 ** followup_ausr - add finger and pobox entries, set_user_modtime
1445 ** argv[0] - login (add_user)
1446 ** argv[3] - last name
1447 ** argv[4] - first name
1448 ** argv[5] - middle name
1452 followup_ausr(q, argv, cl)
1457 EXEC SQL BEGIN DECLARE SECTION;
1458 int who, status, id;
1459 char *login, *entity, *src, *dst, *name;
1461 EXEC SQL END DECLARE SECTION;
1463 char databuf[32], *kname_unparse();
1464 EXEC SQL BEGIN DECLARE SECTION;
1466 int sigwho, timestamp;
1467 EXEC SQL END DECLARE SECTION;
1471 /* build fullname */
1472 if (strlen(argv[4]) && strlen(argv[5]))
1473 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1474 else if (strlen(argv[4]))
1475 sprintf(fullname, "%s %s", argv[4], argv[3]);
1477 sprintf(fullname, "%s", argv[3]);
1480 if (q->vcnt == U_END && *argv[U_SIGNATURE]) {
1481 sprintf(databuf, "%s:%s", argv[U_NAME], argv[U_MITID]);
1482 /* skip bytes for timestamp & kname */
1483 si.rawsig = (unsigned char *) rawsig;
1484 status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE], &si);
1485 if (strlen(rawsig) > mr_sig_length) {
1486 com_err(whoami, 0, "GDSS signature would be truncated."); /** untested **/
1487 return(MR_INTERNAL);
1490 name = kname_unparse(si.pname, si.pinst, si.prealm);
1491 status = name_to_id(name, "STRING", &sigwho);
1492 if (status == MR_NO_MATCH) {
1493 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1494 WHERE name='strings_id';
1496 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1497 WHERE name='strings_id';
1498 INSERT INTO strings (string_id, string)
1499 VALUES (:sigwho, :name);
1501 return(gdss2et(status));
1502 timestamp = si.timestamp;
1504 return(gdss2et(status));
1513 who = cl->client_id;
1514 entity = cl->entity;
1516 /* create finger entry, pobox & set modtime on user */
1518 EXEC SQL REPEATED UPDATE users
1519 SET modtime='now', modby=:who, modwith = :entity,
1520 fullname = :fullname, affiliation = type,
1521 signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho,
1522 fmodtime='now', fmodby = :who, fmodwith = :entity,
1523 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1524 WHERE login = :login;
1526 EXEC SQL REPEATED UPDATE users
1527 SET modtime='now', modby=:who, modwith = :entity,
1528 fullname = :fullname, affiliation = type,
1529 fmodtime='now', fmodby = :who, fmodwith = :entity,
1530 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1531 WHERE login = :login;
1539 ** followup_uusr - do signature, set_user_modtime
1542 ** argv[0] - login (add_user)
1543 ** argv[U_SIGNATURE] - sig
1547 followup_uuac(q, argv, cl)
1552 EXEC SQL BEGIN DECLARE SECTION;
1553 int who, status, id;
1554 char *entity, *name;
1555 EXEC SQL END DECLARE SECTION;
1557 char databuf[32], *kname_unparse();
1558 EXEC SQL BEGIN DECLARE SECTION;
1561 int sigwho, timestamp;
1562 EXEC SQL END DECLARE SECTION;
1566 id = *(int *)argv[0];
1567 who = cl->client_id;
1568 entity = cl->entity;
1571 if (q->vcnt == U_MODTIME && *argv[U_SIGNATURE + 1]) {
1573 status = id_to_name(id, "USER", &login);
1574 sprintf(databuf, "%s:%s", login, argv[U_MITID+1]);
1576 /* skip bytes for timestamp & kname */
1577 si.rawsig = (unsigned char *) rawsig;
1578 status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE+1], &si);
1579 if (strlen(rawsig) > mr_sig_length) {
1580 com_err(whoami, 0, "GDSS signature would be truncated."); /** untested **/
1581 return(MR_INTERNAL);
1584 name = kname_unparse(si.pname, si.pinst, si.prealm);
1585 status = name_to_id(name, "STRING", &sigwho);
1586 if (status == MR_NO_MATCH) {
1587 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1588 WHERE name='strings_id';
1590 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1591 WHERE name='strings_id';
1592 INSERT INTO strings (string_id, string)
1593 VALUES (:sigwho, :name);
1595 return(gdss2et(status));
1596 timestamp = si.timestamp;
1598 return(gdss2et(status));
1606 /* create finger entry, pobox & set modtime on user */
1609 EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity,
1610 signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho
1611 WHERE users_id = :id;
1613 EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity
1614 WHERE users_id = :id;
1620 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1621 * type in argv[1]. Then completes the upcall to the user.
1623 * argv[2] is of the form "123:234" where the first integer is the machine
1624 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1625 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1629 followup_gpob(q, sq, v, action, actarg, cl)
1630 register struct query *q;
1631 register struct save_queue *sq;
1632 register struct validate *v;
1633 register int (*action)();
1637 char **argv, *index();
1639 int mid, sid, status, i;
1642 while (sq_get_data(sq, &argv)) {
1643 mr_trim_args(2, argv);
1645 p = index(argv[2], ':');
1647 mid = atoi(argv[2]);
1650 if (!strcmp(ptype, "POP")) {
1651 status = id_to_name(mid, "MACHINE", &argv[2]);
1652 if (status == MR_NO_MATCH)
1654 } else if (!strcmp(ptype, "SMTP")) {
1655 status = id_to_name(sid, "STRING", &argv[2]);
1656 if (status == MR_NO_MATCH)
1658 } else /* ptype == "NONE" */ {
1661 if (status) return(status);
1663 if (!strcmp(q->shortname, "gpob")) {
1664 sid = atoi(argv[4]);
1666 status = id_to_name(sid, "USER", &argv[4]);
1668 status = id_to_name(-sid, "STRING", &argv[4]);
1670 if (status && status != MR_NO_MATCH) return(status);
1672 (*action)(q->vcnt, argv, actarg);
1674 /* free saved data */
1675 for (i = 0; i < q->vcnt; i++)
1681 return (MR_SUCCESS);
1685 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1686 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1687 * proper name based on the type, and repace that string in the argv.
1688 * Also fixes the modby field by called followup_fix_modby.
1691 followup_glin(q, sq, v, action, actarg, cl)
1692 register struct query *q;
1693 register struct save_queue *sq;
1694 register struct validate *v;
1695 register int (*action)();
1699 char **argv, *malloc(), *realloc(), *type;
1700 int id, i, idx, status;
1703 if (!strcmp(q->shortname, "gsin"))
1706 while (sq_get_data(sq, &argv)) {
1707 mr_trim_args(q->vcnt, argv);
1709 id = atoi(argv[i = q->vcnt - 2]);
1711 status = id_to_name(id, "USER", &argv[i]);
1713 status = id_to_name(-id, "STRING", &argv[i]);
1714 if (status && status != MR_NO_MATCH)
1717 id = atoi(argv[idx]);
1718 type = argv[idx - 1];
1720 if (!strcmp(type, "LIST")) {
1721 status = id_to_name(id, "LIST", &argv[idx]);
1722 } else if (!strcmp(type, "USER")) {
1723 status = id_to_name(id, "USER", &argv[idx]);
1724 } else if (!strcmp(type, "KERBEROS")) {
1725 status = id_to_name(id, "STRING", &argv[idx]);
1726 } else if (!strcmp(type, "NONE")) {
1729 argv[idx] = strsave("NONE");
1733 argv[idx] = strsave("???");
1735 if (status && status != MR_NO_MATCH)
1738 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1739 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1740 strcpy(argv[6], UNIQUE_GID);
1744 (*action)(q->vcnt, argv, actarg);
1746 /* free saved data */
1747 for (i = 0; i < q->vcnt; i++)
1753 return (MR_SUCCESS);
1757 /* followup_gqot: Fix the entity name, directory name & modby fields
1758 * argv[0] = filsys_id
1760 * argv[2] = entity_id
1761 * argv[3] = ascii(quota)
1764 followup_gqot(q, sq, v, action, actarg, cl)
1766 register struct save_queue *sq;
1768 register int (*action)();
1769 register int actarg;
1773 char **argv, *malloc();
1774 EXEC SQL BEGIN DECLARE SECTION;
1777 EXEC SQL END DECLARE SECTION;
1780 if (!strcmp(q->name, "get_quota") ||
1781 !strcmp(q->name, "get_quota_by_filesys"))
1785 while (sq_get_data(sq, &argv)) {
1787 switch (argv[1][0]) {
1789 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1793 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1797 argv[2] = strsave("system:anyuser");
1801 argv[2] = malloc(8);
1802 sprintf(argv[2], "%d", id);
1805 id = atoi(argv[idx]);
1807 argv[idx] = malloc(256);
1811 EXEC SQL REPEATED SELECT name INTO :name FROM filesys
1812 WHERE label = :label;
1814 EXEC SQL REPEATED SELECT dir INTO :name FROM nfsphys
1815 WHERE nfsphys_id = :id;
1817 if (sqlca.sqlerrd[2] != 1) {
1818 sprintf(argv[idx], "#%d", id);
1821 id = atoi(argv[idx+3]);
1823 status = id_to_name(id, "USER", &argv[idx+3]);
1825 status = id_to_name(-id, "STRING", &argv[idx+3]);
1826 if (status && status != MR_NO_MATCH)
1828 (*action)(q->vcnt, argv, actarg);
1829 for (j = 0; j < q->vcnt; j++)
1838 /* followup_aqot: Add allocation to nfsphys after creating quota.
1839 * argv[0] = filsys_id
1840 * argv[1] = type if "add_quota" or "update_quota"
1842 * argv[3 or 2] = ascii(quota)
1845 followup_aqot(q, argv, cl)
1850 EXEC SQL BEGIN DECLARE SECTION;
1851 int quota, id, fs, who, physid;
1852 char *entity, *qtype;
1853 EXEC SQL END DECLARE SECTION;
1855 fs = *(int *)argv[0];
1856 if (!strcmp(q->name, "add_quota") || !strcmp(q->name, "update_quota")) {
1858 id = *(int *)argv[2];
1859 quota = atoi(argv[3]);
1862 id = *(int *)argv[1];
1863 quota = atoi(argv[2]);
1865 who = cl->client_id;
1866 entity = cl->entity;
1868 EXEC SQL REPEATED UPDATE quota
1869 SET modtime = 'now', modby = :who, modwith = :entity
1870 WHERE filsys_id = :fs and type = :qtype and entity_id = :id;
1871 EXEC SQL REPEATED SELECT phys_id INTO :physid FROM filesys
1872 WHERE filsys_id = :fs;
1873 EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated + :quota
1874 WHERE nfsphys_id = :physid;
1875 if (ingres_errno) return(mr_errcode);
1880 followup_gpce(q, sq, v, action, actarg, cl)
1882 register struct save_queue *sq;
1884 register int (*action)();
1885 register int actarg;
1889 char **argv, *malloc();
1893 while (sq_get_data(sq, &argv)) {
1894 id = atoi(argv[PCAP_QSERVER]);
1895 status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
1896 if (status) return (status);
1899 status = id_to_name(id, "USER", &argv[i]);
1901 status = id_to_name(-id, "STRING", &argv[i]);
1902 if (status && status != MR_NO_MATCH)
1904 (*action)(q->vcnt, argv, actarg);
1905 for (j = 0; j < q->vcnt; j++)
1917 followup_gzcl(q, sq, v, action, actarg, cl)
1918 register struct query *q;
1919 register struct save_queue *sq;
1920 register struct validate *v;
1921 register int (*action)();
1928 while (sq_get_data(sq, &argv)) {
1929 mr_trim_args(q->vcnt, argv);
1931 id = atoi(argv[i = q->vcnt - 2]);
1933 status = id_to_name(id, "USER", &argv[i]);
1935 status = id_to_name(-id, "STRING", &argv[i]);
1936 if (status && status != MR_NO_MATCH)
1939 for (i = 1; i < 8; i+=2) {
1940 id = atoi(argv[i+1]);
1941 if (!strcmp(argv[i], "LIST")) {
1942 status = id_to_name(id, "LIST", &argv[i+1]);
1943 } else if (!strcmp(argv[i], "USER")) {
1944 status = id_to_name(id, "USER", &argv[i+1]);
1945 } else if (!strcmp(argv[i], "KERBEROS")) {
1946 status = id_to_name(id, "STRING", &argv[i+1]);
1947 } else if (!strcmp(argv[i], "NONE")) {
1950 argv[i+1] = strsave("NONE");
1954 argv[i+1] = strsave("???");
1956 if (status && status != MR_NO_MATCH)
1961 (*action)(q->vcnt, argv, actarg);
1963 /* free saved data */
1964 for (i = 0; i < q->vcnt; i++)
1976 followup_gsha(q, sq, v, action, actarg, cl)
1977 register struct query *q;
1978 register struct save_queue *sq;
1979 register struct validate *v;
1980 register int (*action)();
1987 while (sq_get_data(sq, &argv)) {
1988 mr_trim_args(q->vcnt, argv);
1992 status = id_to_name(id, "USER", &argv[4]);
1994 status = id_to_name(-id, "STRING", &argv[4]);
1995 if (status && status != MR_NO_MATCH)
1999 if (!strcmp(argv[1], "LIST")) {
2000 status = id_to_name(id, "LIST", &argv[2]);
2001 } else if (!strcmp(argv[1], "USER")) {
2002 status = id_to_name(id, "USER", &argv[2]);
2003 } else if (!strcmp(argv[1], "KERBEROS")) {
2004 status = id_to_name(id, "STRING", &argv[2]);
2005 } else if (!strcmp(argv[1], "NONE")) {
2008 argv[2] = strsave("NONE");
2012 argv[2] = strsave("???");
2014 if (status && status != MR_NO_MATCH)
2018 (*action)(q->vcnt, argv, actarg);
2020 /* free saved data */
2021 for (i = 0; i < q->vcnt; i++)
2031 /* Special query routines */
2033 /* set_pobox - this does all of the real work.
2034 * argv = user_id, type, box
2035 * if type is POP, then box should be a machine, and its ID should be put in
2036 * pop_id. If type is SMTP, then box should be a string and its ID should
2037 * be put in box_id. If type is NONE, then box doesn't matter.
2040 int set_pobox(q, argv, cl)
2045 EXEC SQL BEGIN DECLARE SECTION;
2047 char *box, potype[9];
2048 EXEC SQL END DECLARE SECTION;
2052 user = *(int *)argv[0];
2054 EXEC SQL REPEATED SELECT pop_id, potype INTO :id, :potype FROM users
2055 WHERE users_id = :user;
2056 if (ingres_errno) return(mr_errcode);
2057 if (!strcmp(strtrim(potype), "POP"))
2058 set_pop_usage(id, -1);
2060 if (!strcmp(argv[1], "POP")) {
2061 status = name_to_id(box, "MACHINE", &id);
2062 if (status == MR_NO_MATCH)
2066 EXEC SQL REPEATED UPDATE users SET potype = 'POP', pop_id = :id
2067 WHERE users_id = :user;
2068 set_pop_usage(id, 1);
2069 } else if (!strcmp(argv[1], "SMTP")) {
2070 if (index(box, '/') || index(box, '|'))
2071 return(MR_BAD_CHAR);
2072 status = name_to_id(box, "STRING", &id);
2073 if (status == MR_NO_MATCH) {
2074 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
2075 WHERE name='strings_id';
2077 EXEC SQL REPEATED UPDATE numvalues SET value = :id
2078 WHERE name='strings_id';
2079 EXEC SQL INSERT INTO strings (string_id, string)
2083 EXEC SQL REPEATED UPDATE users SET potype='SMTP', box_id = :id
2084 WHERE users_id = :user;
2085 } else /* argv[1] == "NONE" */ {
2086 EXEC SQL REPEATED UPDATE users SET potype='NONE'
2087 WHERE users_id = :user;
2090 set_pobox_modtime(q, argv, cl);
2091 EXEC SQL REPEATED UPDATE tblstats SET updates = updates+1, modtime='now'
2092 WHERE tblstats.table_name='users';
2093 if (ingres_errno) return(mr_errcode);
2098 /* get_list_info: passed a wildcard list name, returns lots of stuff about
2099 * each list. This is tricky: first build a queue of all requested
2100 * data. Rest of processing consists of fixing gid, ace_name, and modby.
2103 get_list_info(q, aargv, cl, action, actarg)
2104 register struct query *q;
2107 register int (*action)();
2110 char *argv[13], *malloc(), *realloc();
2111 EXEC SQL BEGIN DECLARE SECTION;
2112 char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
2113 char maillist[5], grouplist[5], gid_str[6], acl_name[256], desc[256];
2114 char modtime[27], modby[256], modwith[9];
2115 int id, rowcount, acl_id, hid, modby_id;
2116 EXEC SQL END DECLARE SECTION;
2117 int returned, status;
2118 struct save_queue *sq, *sq_create();
2120 returned = rowcount = 0;
2122 convert_wildcards(name);
2125 EXEC SQL DECLARE csr102 CURSOR FOR SELECT list_id FROM list
2126 WHERE name LIKE :name ESCAPE '*';
2127 EXEC SQL OPEN csr102;
2130 EXEC SQL FETCH csr102 INTO :id;
2131 if(sqlca.sqlcode!=0) break;
2132 sq_save_data(sq, id);
2135 EXEC SQL CLOSE csr102;
2137 if (ingres_errno) return(mr_errcode);
2139 return(MR_NO_MATCH);
2141 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
2142 argv[4] = maillist; argv[5] = grouplist; argv[6] = gid_str;
2143 argv[7] = acl_type; argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
2145 while (sq_get_data(sq, &id)) {
2149 EXEC SQL REPEATED SELECT name, CHAR(active), CHAR(publicflg),
2150 CHAR(hidden), hidden, CHAR(maillist), CHAR(grouplist), CHAR(gid),
2151 TRIM(acl_type), acl_id, description, CHAR(modtime), modby, modwith
2152 INTO :listname, :active, :public, :hidden, :hid, :maillist,
2153 :grouplist, :gid_str, :acl_type, :acl_id, :desc,
2154 :modtime, :modby_id, :modwith
2155 FROM list WHERE list_id = :id;
2157 if (ingres_errno) return(mr_errcode);
2159 if (atoi(gid_str) == -1)
2160 argv[6] = UNIQUE_GID;
2162 argv[8] = malloc(0);
2163 if (!strcmp(acl_type, "LIST")) {
2164 status = id_to_name(acl_id, "LIST", &argv[8]);
2165 } else if (!strcmp(acl_type, "USER")) {
2166 status = id_to_name(acl_id, "USER", &argv[8]);
2167 } else if (!strcmp(acl_type, "KERBEROS")) {
2168 status = id_to_name(acl_id, "STRING", &argv[8]);
2169 } else if (!strcmp(acl_type, "NONE")) {
2172 argv[8] = strsave("NONE");
2176 argv[8] = strsave("???");
2178 if (status && status != MR_NO_MATCH) return(status);
2180 argv[11] = malloc(0);
2182 status = id_to_name(modby_id, "USER", &argv[11]);
2184 status = id_to_name(-modby_id, "STRING", &argv[11]);
2185 if (status && status != MR_NO_MATCH) return(status);
2187 mr_trim_args(q->vcnt, argv);
2189 (*action)(q->vcnt, argv, actarg);
2195 if (ingres_errno) return(mr_errcode);
2196 return (MR_SUCCESS);
2200 /* Add_member_to_list: do list flattening as we go! MAXLISTDEPTH is
2201 * how many different ancestors a member is allowed to have.
2204 #define MAXLISTDEPTH 1024
2206 int add_member_to_list(q, argv, cl)
2211 EXEC SQL BEGIN DECLARE SECTION;
2212 int id, lid, mid, error, who, ref;
2213 char *mtype, dtype[9], *entity;
2214 EXEC SQL END DECLARE SECTION;
2215 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2216 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2218 char *dtypes[MAXLISTDEPTH];
2219 char *iargv[3], *buf;
2221 lid = *(int *)argv[0];
2223 mid = *(int *)argv[2];
2224 /* if the member is already a direct member of the list, punt */
2225 EXEC SQL REPEATED SELECT list_id INTO :idummy FROM imembers
2226 WHERE list_id = :lid AND member_id = :mid
2227 AND member_type = :mtype AND direct = 1;
2228 if (sqlca.sqlerrd[2] > 0)
2230 if (!strcasecmp(mtype, "STRING")) {
2232 status = id_to_name(mid, "STRING", &buf);
2233 if (status) return(status);
2234 if (index(buf, '/') || index(buf, '|')) {
2236 return(MR_BAD_CHAR);
2244 EXEC SQL DECLARE csr103 CURSOR FOR
2245 SELECT list_id, ref_count FROM imembers
2246 WHERE member_id = :lid AND member_type='LIST';
2247 EXEC SQL OPEN csr103;
2249 EXEC SQL FETCH csr103 INTO :id, :ref;
2250 if(sqlca.sqlcode != 0) break;
2252 ancestors[acount++] = id;
2253 if (acount >= MAXLISTDEPTH) break;
2255 EXEC SQL CLOSE csr103;
2256 if (ingres_errno) return(mr_errcode);
2257 if (acount >= MAXLISTDEPTH) {
2258 return(MR_INTERNAL);
2260 descendants[0] = mid;
2265 if (!strcmp(mtype, "LIST")) {
2266 EXEC SQL DECLARE csr104 CURSOR FOR
2267 SELECT member_id, member_type, ref_count
2269 WHERE list_id = :mid;
2270 EXEC SQL OPEN csr104;
2272 EXEC SQL FETCH csr104 INTO :id, :dtype, :ref;
2273 if(sqlca.sqlcode != 0) break;
2276 dtypes[dcount] = "LIST";
2279 dtypes[dcount] = "USER";
2282 dtypes[dcount] = "STRING";
2285 dtypes[dcount] = "KERBEROS";
2292 descendants[dcount++] = id;
2293 if (dcount >= MAXLISTDEPTH) {
2298 EXEC SQL CLOSE csr104;
2299 if (ingres_errno) return(mr_errcode);
2301 return(MR_INTERNAL);
2303 for (a = 0; a < acount; a++) {
2305 for (d = 0; d < dcount; d++) {
2306 mid = descendants[d];
2308 if (mid == lid && !strcmp(mtype, "LIST")) {
2309 return(MR_LISTLOOP);
2311 EXEC SQL REPEATED SELECT ref_count INTO :idummy FROM imembers
2312 WHERE list_id = :lid AND member_id = :mid
2313 AND member_type = :mtype;
2314 ref = aref[a] * dref[d];
2315 if (sqlca.sqlerrd[2] > 0) {
2316 if (a == 0 && d == 0) {
2317 EXEC SQL UPDATE imembers
2318 SET ref_count = ref_count+:ref, direct=1
2319 WHERE list_id = :lid AND member_id = :mid
2320 AND member_type = :mtype;
2322 EXEC SQL UPDATE imembers
2323 SET ref_count = ref_count+:ref
2324 WHERE list_id = :lid AND member_id = :mid
2325 AND member_type = :mtype;
2328 incremental_clear_before();
2329 if (a == 0 && d == 0) {
2330 EXEC SQL INSERT INTO imembers
2331 (list_id, member_id, direct, member_type, ref_count)
2332 VALUES (:lid, :mid, 1, :mtype, 1);
2334 EXEC SQL INSERT INTO imembers
2335 (list_id, member_id, member_type, ref_count)
2336 VALUES (:lid, :mid, :mtype, 1);
2338 iargv[0] = (char *)lid;
2340 iargv[2] = (char *)mid;
2341 incremental_after("members", 0, iargv);
2345 lid = *(int *)argv[0];
2346 entity = cl->entity;
2347 who = cl->client_id;
2348 EXEC SQL REPEATED UPDATE list
2349 SET modtime='now', modby = :who, modwith = :entity
2350 WHERE list_id = :lid;
2351 if (ingres_errno) return(mr_errcode);
2356 /* Delete_member_from_list: do list flattening as we go!
2359 int delete_member_from_list(q, argv, cl)
2364 EXEC SQL BEGIN DECLARE SECTION;
2365 int id, lid, mid, cnt, error, who, ref;
2366 char *mtype, dtype[9], *entity;
2367 EXEC SQL END DECLARE SECTION;
2368 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2369 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2370 char *dtypes[MAXLISTDEPTH];
2373 lid = *(int *)argv[0];
2375 mid = *(int *)argv[2];
2376 /* if the member is not a direct member of the list, punt */
2377 EXEC SQL REPEATED SELECT list_id INTO :idummy FROM imembers
2378 WHERE list_id = :lid AND member_id = :mid
2379 AND member_type = :mtype AND direct = 1;
2380 if (ingres_errno) return(mr_errcode);
2381 if (sqlca.sqlcode == 100)
2382 return(MR_NO_MATCH);
2386 EXEC SQL DECLARE csr105 CURSOR FOR
2387 SELECT list_id, ref_count FROM imembers
2388 WHERE member_id = :lid AND member_type = 'LIST';
2389 EXEC SQL OPEN csr105;
2391 EXEC SQL FETCH csr105 INTO :id, :ref;
2392 if(sqlca.sqlcode!=0) break;
2394 ancestors[acount++] = id;
2395 if (acount >= MAXLISTDEPTH) break;
2397 EXEC SQL CLOSE csr105;
2400 if (acount >= MAXLISTDEPTH)
2401 return(MR_INTERNAL);
2402 descendants[0] = mid;
2407 if (!strcmp(mtype, "LIST")) {
2408 EXEC SQL DECLARE csr106 CURSOR FOR
2409 SELECT member_id, member_type, ref_count FROM imembers
2410 WHERE list_id = :mid;
2411 EXEC SQL OPEN csr106;
2413 EXEC SQL FETCH csr106 INTO :id, :dtype, :ref;
2414 if(sqlca.sqlcode!=0) break;
2417 dtypes[dcount] = "LIST";
2420 dtypes[dcount] = "USER";
2423 dtypes[dcount] = "STRING";
2426 dtypes[dcount] = "KERBEROS";
2433 descendants[dcount++] = id;
2434 if (dcount >= MAXLISTDEPTH) break;
2436 EXEC SQL CLOSE csr106;
2440 return(MR_INTERNAL);
2442 for (a = 0; a < acount; a++) {
2444 for (d = 0; d < dcount; d++) {
2445 mid = descendants[d];
2447 if (mid == lid && !strcmp(mtype, "LIST")) {
2448 return(MR_LISTLOOP);
2450 EXEC SQL REPEATED SELECT ref_count INTO :cnt FROM imembers
2451 WHERE list_id = :lid AND member_id = :mid AND member_type = :mtype;
2452 ref = aref[a] * dref[d];
2454 iargv[0] = (char *)lid;
2456 iargv[2] = (char *)mid;
2457 incremental_before("members", 0, iargv);
2458 EXEC SQL DELETE FROM imembers
2459 WHERE list_id = :lid AND member_id = :mid
2460 AND member_type= :mtype;
2461 incremental_clear_after();
2462 } else if (a == 0 && d == 0) {
2463 EXEC SQL UPDATE imembers
2464 SET ref_count = ref_count - :ref, direct = 0
2465 WHERE list_id = :lid AND member_id = :mid
2466 AND member_type = :mtype;
2468 EXEC SQL UPDATE imembers
2469 SET ref_count = ref_count - :ref
2470 WHERE list_id = :lid AND member_id = :mid
2471 AND member_type = :mtype;
2475 lid = *(int *)argv[0];
2476 entity = cl->entity;
2477 who = cl->client_id;
2478 EXEC SQL UPDATE list SET modtime = 'now', modby = :who, modwith = :entity
2479 WHERE list_id = :lid;
2480 if (ingres_errno) return(mr_errcode);
2485 /* get_ace_use - given a type and a name, return a type and a name.
2486 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2487 * and argv[1] will contain the ID of the entity in question. The R*
2488 * types mean to recursively look at every containing list, not just
2489 * when the object in question is a direct member. On return, the
2490 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2493 int get_ace_use(q, argv, cl, action, actarg)
2501 EXEC SQL BEGIN DECLARE SECTION;
2503 int aid, listid, id;
2504 EXEC SQL END DECLARE SECTION;
2505 struct save_queue *sq, *sq_create();
2508 aid = *(int *)argv[1];
2509 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2510 !strcmp(atype, "KERBEROS")) {
2511 return(get_ace_internal(atype, aid, action, actarg));
2515 if (!strcmp(atype, "RLIST")) {
2516 sq_save_data(sq, aid);
2517 /* get all the list_id's of containing lists */
2518 EXEC SQL DECLARE csr107 CURSOR FOR
2519 SELECT list_id FROM imembers
2520 WHERE member_type='LIST' AND member_id = :aid;
2521 EXEC SQL OPEN csr107;
2523 EXEC SQL FETCH csr107 INTO :listid;
2524 if(sqlca.sqlcode != 0) break;
2525 sq_save_unique_data(sq, listid);
2527 EXEC SQL CLOSE csr107;
2528 /* now process each one */
2529 while (sq_get_data(sq, &id)) {
2530 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2535 if (!strcmp(atype, "RUSER")) {
2536 EXEC SQL DECLARE csr108 CURSOR FOR
2537 SELECT list_id FROM imembers
2538 WHERE member_type='USER' AND member_id = :aid;
2539 EXEC SQL OPEN csr108;
2541 EXEC SQL FETCH csr108 INTO :listid;
2542 if(sqlca.sqlcode != 0) break;
2543 sq_save_data(sq, listid);
2545 EXEC SQL CLOSE csr108;
2546 /* now process each one */
2547 while (sq_get_data(sq, &id)) {
2548 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2551 if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2555 if (!strcmp(atype, "RKERBERO")) {
2556 EXEC SQL DECLARE csr109 CURSOR FOR
2557 SELECT list_id FROM imembers
2558 WHERE member_type='KERBEROS' AND member_id = :aid;
2559 EXEC SQL OPEN csr109;
2561 EXEC SQL FETCH csr109 INTO :listid;
2562 if(sqlca.sqlcode != 0) break;
2563 sq_save_data(sq, listid);
2565 EXEC SQL CLOSE csr109;
2566 /* now process each one */
2567 while (sq_get_data(sq, &id)) {
2568 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2571 if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2576 if (ingres_errno) return(mr_errcode);
2577 if (!found) return(MR_NO_MATCH);
2582 /* This looks up a single list or user for ace use. atype must be "USER"
2583 * or "LIST", and aid is the ID of the corresponding object. This is used
2584 * by get_ace_use above.
2587 get_ace_internal(atype, aid, action, actarg)
2588 EXEC SQL BEGIN DECLARE SECTION;
2591 EXEC SQL END DECLARE SECTION;
2597 EXEC SQL BEGIN DECLARE SECTION;
2599 EXEC SQL END DECLARE SECTION;
2602 if (!strcmp(atype, "LIST")) {
2603 rargv[0] = "FILESYS";
2604 EXEC SQL DECLARE csr110 CURSOR FOR
2605 SELECT label FROM filesys
2606 WHERE owners = :aid;
2607 EXEC SQL OPEN csr110;
2609 EXEC SQL FETCH csr110 INTO :name;
2610 if(sqlca.sqlcode != 0) break;
2611 (*action)(2, rargv, actarg);
2614 EXEC SQL CLOSE csr110;
2617 EXEC SQL DECLARE csr111 CURSOR FOR
2618 SELECT capability FROM capacls
2619 WHERE list_id = :aid ;
2620 EXEC SQL OPEN csr111;
2622 EXEC SQL FETCH csr111 INTO :name ;
2623 if(sqlca.sqlcode != 0) break;
2624 (*action)(2, rargv, actarg);
2627 EXEC SQL CLOSE csr111;
2628 } else if (!strcmp(atype, "USER")) {
2629 rargv[0] = "FILESYS";
2630 EXEC SQL DECLARE csr112 CURSOR FOR
2631 SELECT label FROM filesys
2633 EXEC SQL OPEN csr112;
2635 EXEC SQL FETCH csr112 INTO :name ;
2636 if(sqlca.sqlcode != 0) break;
2637 (*action)(2, rargv, actarg);
2640 EXEC SQL CLOSE csr112;
2644 EXEC SQL DECLARE csr113 CURSOR FOR
2645 SELECT name FROM list
2646 WHERE acl_type = :atype AND acl_id = :aid;
2647 EXEC SQL OPEN csr113;
2649 EXEC SQL FETCH csr113 INTO :name;
2650 if(sqlca.sqlcode != 0) break;
2651 (*action)(2, rargv, actarg);
2654 EXEC SQL CLOSE csr113;
2656 rargv[0] = "SERVICE";
2657 EXEC SQL DECLARE csr114 CURSOR FOR
2658 SELECT name FROM servers
2659 WHERE acl_type = :atype AND acl_id = :aid;
2660 EXEC SQL OPEN csr114;
2662 EXEC SQL FETCH csr114 INTO :name;
2663 if(sqlca.sqlcode != 0) break;
2664 (*action)(2, rargv, actarg);
2667 EXEC SQL CLOSE csr114;
2669 rargv[0] = "HOSTACCESS";
2670 EXEC SQL DECLARE csr115 CURSOR FOR
2671 SELECT name FROM machine m, hostaccess ha
2672 WHERE m.mach_id = ha.mach_id AND ha.acl_type = :atype
2673 AND ha.acl_id = :aid;
2674 EXEC SQL OPEN csr115;
2676 EXEC SQL FETCH csr115 INTO :name;
2677 if(sqlca.sqlcode != 0) break;
2678 (*action)(2, rargv, actarg);
2681 EXEC SQL CLOSE csr115;
2683 rargv[0] = "ZEPHYR";
2684 EXEC SQL DECLARE csr116 CURSOR FOR
2685 SELECT class FROM zephyr z
2686 WHERE z.xmt_type = :atype AND z.xmt_id = :aid
2687 OR z.sub_type = :atype AND z.sub_id = :aid
2688 OR z.iws_type = :atype AND z.iws_id = :aid
2689 OR z.iui_type = :atype AND z.iui_id = :aid;
2690 EXEC SQL OPEN csr116;
2692 EXEC SQL FETCH csr116 INTO :name;
2693 if(sqlca.sqlcode != 0) break;
2694 (*action)(2, rargv, actarg);
2697 EXEC SQL CLOSE csr116;
2699 if (!found) return(MR_NO_MATCH);
2704 /* get_lists_of_member - given a type and a name, return the name and flags
2705 * of all of the lists of the given member. The member_type is one of
2706 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2707 * and argv[1] will contain the ID of the entity in question. The R*
2708 * types mean to recursively look at every containing list, not just
2709 * when the object in question is a direct member.
2712 int get_lists_of_member(q, argv, cl, action, actarg)
2719 int found = 0, direct = 1;
2721 EXEC SQL BEGIN DECLARE SECTION;
2723 int aid, listid, id;
2724 char name[33], active[5], public[5], hidden[5], maillist[5], grouplist[5];
2725 EXEC SQL END DECLARE SECTION;
2728 aid = *(int *)argv[1];
2729 if (!strcmp(atype, "RLIST")) {
2733 if (!strcmp(atype, "RUSER")) {
2737 if (!strcmp(atype, "RSTRING")) {
2741 if (!strcmp(atype, "RKERBEROS")) {
2750 rargv[4] = maillist;
2751 rargv[5] = grouplist;
2753 EXEC SQL DECLARE csr117a CURSOR FOR
2754 SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2755 CHAR(l.maillist), CHAR(l.grouplist)
2756 FROM list l, imembers im
2757 WHERE l.list_id = im.list_id AND im.direct = 1
2758 AND im.member_type = :atype AND im.member_id = :aid;
2759 EXEC SQL OPEN csr117a;
2761 EXEC SQL FETCH csr117a
2762 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2763 if(sqlca.sqlcode != 0) break;
2764 (*action)(6, rargv, actarg);
2767 EXEC SQL CLOSE csr117a;
2769 EXEC SQL DECLARE csr117b CURSOR FOR
2770 SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2771 CHAR(l.maillist), CHAR(l.grouplist)
2772 FROM list l, imembers im
2773 WHERE l.list_id = im.list_id
2774 AND im.member_type = :atype AND im.member_id = :aid;
2775 EXEC SQL OPEN csr117b;
2777 EXEC SQL FETCH csr117b
2778 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2779 if(sqlca.sqlcode != 0) break;
2780 (*action)(6, rargv, actarg);
2783 EXEC SQL CLOSE csr117b;
2786 if (ingres_errno) return(mr_errcode);
2787 if (!found) return(MR_NO_MATCH);
2792 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2793 * the five flags associated with each list. It will return the name of
2794 * each list that meets the quailifications. It does this by building a
2795 * where clause based on the arguments, then doing a retrieve.
2798 static char *lflags[5] = { "active", "publicflg", "hidden", "maillist", "grouplist" };
2800 int qualified_get_lists(q, argv, cl, action, actarg)
2807 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2808 "l", "name", lflags));
2812 /* get_members_of_list - this gets only direct members */
2814 get_members_of_list(q, argv, cl, action, actarg)
2821 return(gmol_internal(q, argv, cl, action, actarg, 1));
2824 /* get_end_members_of_list - this gets direct or indirect members */
2826 get_end_members_of_list(q, argv, cl, action, actarg)
2833 return(gmol_internal(q, argv, cl, action, actarg, 0));
2836 /** gmol_internal - optimized query for retrieval of list members
2837 ** used by both get_members_of_list and get_end_members_of_list
2840 ** argv[0] - list_id
2843 ** - retrieve USER members, then LIST members, then STRING members
2846 gmol_internal(q, argv, cl, action, actarg, flag)
2854 EXEC SQL BEGIN DECLARE SECTION;
2855 int list_id, member_id, direct;
2856 char member_name[129], member_type[9];
2857 EXEC SQL END DECLARE SECTION;
2860 struct save_queue *sq;
2862 /* true/false flag indicates whether to display only direct members. */
2868 list_id = *(int *)argv[0];
2872 EXEC SQL DECLARE csr118 CURSOR FOR
2873 SELECT member_type, member_id FROM imembers
2874 WHERE list_id = :list_id AND direct > :direct;
2875 EXEC SQL OPEN csr118;
2877 EXEC SQL FETCH csr118 INTO :member_type, :member_id;
2878 if (sqlca.sqlcode != 0) break;
2881 sq_save_data(sq, ((int)member_type[0] << 24) | (member_id & 0xffffff));
2883 EXEC SQL CLOSE csr118;
2885 if (members <= 49) {
2886 targv[1] = malloc(0);
2887 while (sq_remove_data(sq, &member_id)) {
2888 switch (member_id >> 24) {
2891 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
2892 (*action)(2, targv, actarg);
2896 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
2897 (*action)(2, targv, actarg);
2900 targv[0] = "STRING";
2901 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2902 (*action)(2, targv, actarg);
2905 targv[0] = "KERBEROS";
2906 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2907 (*action)(2, targv, actarg);
2911 return(MR_INTERNAL);
2920 targv[1] = member_name;
2922 EXEC SQL DECLARE csr119 CURSOR FOR
2923 SELECT u.login FROM users u, imembers im
2924 WHERE im.list_id = :list_id AND im.member_type = 'USER'
2925 AND im.member_id = u.users_id AND im.direct > :direct
2927 EXEC SQL OPEN csr119;
2929 EXEC SQL FETCH csr119 INTO :member_name;
2930 if(sqlca.sqlcode != 0) break;
2931 (*action)(2, targv, actarg);
2933 EXEC SQL CLOSE csr119;
2934 if (ingres_errno) return(mr_errcode);
2937 EXEC SQL DECLARE csr120 CURSOR FOR
2938 SELECT l.name FROM list l, imembers im
2939 WHERE im.list_id = :list_id AND im.member_type='LIST'
2940 AND im.member_id = l.list_id AND im.direct > :direct
2942 EXEC SQL OPEN csr120;
2944 EXEC SQL FETCH csr120 INTO :member_name;
2945 if(sqlca.sqlcode != 0) break;
2946 (*action)(2, targv, actarg);
2948 EXEC SQL CLOSE csr120;
2949 if (ingres_errno) return(mr_errcode);
2951 targv[0] = "STRING";
2952 EXEC SQL DECLARE csr121 CURSOR FOR
2953 SELECT str.string FROM strings str, imembers im
2954 WHERE im.list_id = :list_id AND im.member_type='STRING'
2955 AND im.member_id = str.string_id AND im.direct > :direct
2957 EXEC SQL OPEN csr121;
2959 EXEC SQL FETCH csr121 INTO :member_name;
2960 if(sqlca.sqlcode != 0) break;
2961 (*action)(2, targv, actarg);
2963 EXEC SQL CLOSE csr121;
2964 if (ingres_errno) return(mr_errcode);
2966 targv[0] = "KERBEROS";
2967 EXEC SQL DECLARE csr122 CURSOR FOR
2968 SELECT strings.string FROM strings, imembers
2969 WHERE imembers.list_id = :list_id AND imembers.member_type='KERBEROS'
2970 AND imembers.member_id = strings.string_id
2971 AND imembers.direct > :direct
2973 EXEC SQL OPEN csr122;
2975 EXEC SQL FETCH csr122 INTO :member_name;
2976 if(sqlca.sqlcode != 0) break;
2977 (*action)(2, targv, actarg);
2979 EXEC SQL CLOSE csr122;
2980 if (ingres_errno) return(mr_errcode);
2986 /* count_members_of_list: this is a simple query, but it cannot be done
2987 * through the dispatch table.
2990 int count_members_of_list(q, argv, cl, action, actarg)
2997 EXEC SQL BEGIN DECLARE SECTION;
2999 EXEC SQL END DECLARE SECTION;
3000 char *rargv[1], countbuf[5];
3002 list = *(int *)argv[0];
3003 rargv[0] = countbuf;
3004 EXEC SQL REPEATED SELECT count (*) INTO :ct FROM imembers
3005 WHERE list_id = :list AND direct=1;
3006 if (ingres_errno) return(mr_errcode);
3007 sprintf(countbuf, "%d", ct);
3008 (*action)(1, rargv, actarg);
3013 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
3014 * the three flags associated with each service. It will return the name of
3015 * each service that meets the quailifications. It does this by building a
3016 * where clause based on the arguments, then doing a retrieve.
3019 static char *sflags[3] = { "enable", "inprogress", "harderror" };
3021 int qualified_get_server(q, argv, cl, action, actarg)
3028 return(qualified_get(q, argv, action, actarg, "s.name != ''",
3029 "s", "name", sflags));
3033 /* generic qualified get routine, used by qualified_get_lists,
3034 * qualified_get_server, and qualified_get_serverhost.
3036 * start - a simple where clause, must not be empty
3037 * range - the name of the range variable
3038 * field - the field to return
3039 * flags - an array of strings, names of the flag variables
3042 int qualified_get(q, argv, action, actarg, start, range, field, flags)
3052 char name[33], qual[256];
3054 char *rargv[1], buf[32];
3056 strcpy(qual, start);
3057 for (i = 0; i < q->argc; i++) {
3058 if (!strcmp(argv[i], "TRUE")) {
3059 sprintf(buf, " AND %s.%s != 0", range, flags[i]);
3060 (void) strcat(qual, buf);
3061 } else if (!strcmp(argv[i], "FALSE")) {
3062 sprintf(buf, " AND %s.%s = 0", range, flags[i]);
3063 (void) strcat(qual, buf);
3067 rargv[0] = SQLDA->sqlvar[0].sqldata;
3068 sprintf(stmt_buf,"SELECT %s.%s FROM %s %s WHERE %s",q->rtable,field,q->rtable,q->rvar,qual); /** Should first rtabl be rvar ??? **/
3069 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3071 return(MR_INTERNAL);
3072 EXEC SQL DECLARE csr123 CURSOR FOR stmt;
3073 EXEC SQL OPEN csr123;
3075 EXEC SQL FETCH csr123 USING DESCRIPTOR :SQLDA;
3076 if(sqlca.sqlcode != 0) break;
3078 (*action)(1, rargv, actarg);
3080 EXEC SQL CLOSE csr123;
3081 if (ingres_errno) return(mr_errcode);
3083 return(MR_NO_MATCH);
3088 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
3089 * the five flags associated with each serverhost. It will return the name of
3090 * each service and host that meets the quailifications. It does this by
3091 * building a where clause based on the arguments, then doing a retrieve.
3094 static char *shflags[6] = { "service", "enable", "override", "success",
3095 "inprogress", "hosterror" };
3097 int qualified_get_serverhost(q, argv, cl, action, actarg)
3104 EXEC SQL BEGIN DECLARE SECTION;
3105 char sname[33], mname[33], qual[256];
3106 EXEC SQL END DECLARE SECTION;
3107 char *rargv[2], buf[32];
3110 /** the uppercase() function is INGRES-specific */
3111 sprintf(qual, "m.mach_id = sh.mach_id AND sh.service = uppercase('%s')",
3113 for (i = 1; i < q->argc; i++) {
3114 if (!strcmp(argv[i], "TRUE")) {
3115 sprintf(buf, " AND sh.%s != 0", shflags[i]);
3117 } else if (!strcmp(argv[i], "FALSE")) {
3118 sprintf(buf, " AND sh.%s = 0", shflags[i]);
3125 EXEC SQL DECLARE csr124 CURSOR FOR
3126 SELECT sh.service, m.name FROM serverhosts sh, machine m
3128 EXEC SQL OPEN csr124;
3130 EXEC SQL FETCH csr124 INTO :sname, :mname;
3131 if(sqlca.sqlcode != 0) break;
3133 (*action)(2, rargv, actarg);
3135 EXEC SQL CLOSE csr124;
3137 if (ingres_errno) return(mr_errcode);
3139 return(MR_NO_MATCH);
3144 /* register_user - change user's login name and allocate a pobox, group,
3145 * filesystem, and quota for them. The user's status must start out as 0,
3146 * and is left as 2. Arguments are: user's UID, new login name, and user's
3147 * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY,
3148 * MR_FS_STAFF, MR_FS_MISC).
3151 register_user(q, argv, cl)
3156 EXEC SQL BEGIN DECLARE SECTION;
3157 char *login, dir[65], *entity, directory[129], machname[33];
3158 int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
3159 int size, alloc, pid, ostatus, nstatus, gidval, fsidval, npidval;
3160 static int m_id = 0, def_quota = 0;
3161 EXEC SQL END DECLARE SECTION;
3162 char buffer[256], *aargv[3];
3164 entity = cl->entity;
3165 who = cl->client_id;
3167 uid = atoi(argv[0]);
3169 utype = atoi(argv[2]);
3172 EXEC SQL REPEATED SELECT users_id, status INTO :users_id, :ostatus
3174 WHERE uid = :uid AND (status=0 OR status=5 OR status=6);
3176 if (sqlca.sqlerrd[2] == 0)
3177 return(MR_NO_MATCH);
3178 if (sqlca.sqlerrd[2] > 1)
3179 return(MR_NOT_UNIQUE);
3181 /* check new login name */
3182 EXEC SQL REPEATED SELECT login INTO :cdummy FROM users
3183 WHERE login = LEFT(:login,SIZE(login)) AND users_id != :users_id;
3184 if (ingres_errno) return(mr_errcode);
3185 if (sqlca.sqlerrd[2] > 0) return(MR_IN_USE);
3186 EXEC SQL REPEATED SELECT name INTO :cdummy FROM list
3187 WHERE name = LEFT(:login,SIZE(name));
3188 if (ingres_errno) return(mr_errcode);
3189 if (sqlca.sqlerrd[2] > 0) return(MR_IN_USE);
3190 EXEC SQL REPEATED SELECT label INTO :cdummy FROM filesys
3191 WHERE label = LEFT(:login,SIZE(label));
3192 if (ingres_errno) return(mr_errcode);
3193 if (sqlca.sqlerrd[2] > 0) return(MR_IN_USE);
3194 com_err(whoami, 0, "login name OK");
3196 /* choose place for pobox, put in mid */
3197 EXEC SQL DECLARE csr130 CURSOR FOR
3198 SELECT sh.mach_id, m.name FROM serverhosts sh, machine m
3199 WHERE sh.service='POP' AND sh.mach_id=m.mach_id
3200 AND sh.value2 - sh.value1 =
3201 (SELECT MAX(value2 - value1) FROM serverhosts
3202 WHERE service = 'POP');
3203 EXEC SQL OPEN csr130;
3204 EXEC SQL FETCH csr130 INTO :mid, :machname;
3205 if (sqlca.sqlerrd[2] == 0) {
3206 EXEC SQL CLOSE csr130;
3207 if (ingres_errno) return(mr_errcode);
3208 return(MR_NO_POBOX);
3210 EXEC SQL CLOSE csr130;
3211 if (ingres_errno) return(mr_errcode);
3214 /* change login name, set pobox */
3215 sprintf(buffer, "u.users_id = %d", users_id);
3216 incremental_before("users", buffer, 0);
3218 if (ostatus == 5 || ostatus == 6)
3220 EXEC SQL REPEATED UPDATE users SET login = :login, status = :nstatus,
3221 modtime='now', modby = :who, modwith = :entity, potype='POP',
3222 pop_id = :mid, pmodtime='now', pmodby = :who, pmodwith = :entity
3223 WHERE users_id = :users_id;
3225 if (ingres_errno) return(mr_errcode);
3226 if (sqlca.sqlerrd[2] != 1)
3227 return(MR_INTERNAL);
3228 set_pop_usage(mid, 1);
3229 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
3231 incremental_after("users", buffer, 0);
3233 /* create group list */
3234 if (set_next_object_id("gid", "list", 1))
3236 if (set_next_object_id("list_id", "list", 0))
3238 EXEC SQL REPEATED SELECT value INTO :list_id FROM numvalues
3239 WHERE name='list_id';
3240 if (ingres_errno) return(mr_errcode);
3241 if (sqlca.sqlerrd[2] != 1)
3242 return(MR_INTERNAL);
3243 incremental_clear_before();
3244 EXEC SQL SELECT value INTO :gidval FROM numvalues WHERE name = 'gid';
3245 EXEC SQL REPEATED INSERT INTO list
3246 (name, list_id, active, publicflg, hidden, maillist, grouplist,
3247 gid, description, acl_type, acl_id,
3248 modtime, modby, modwith)
3249 VALUES (:login, :list_id, 1, 0, 0, 0, 1,
3250 :gidval, 'User Group', 'USER', :users_id,
3251 'now', :who, :entity);
3252 if (ingres_errno) return(mr_errcode);
3253 if (sqlca.sqlerrd[2] != 1)
3254 return(MR_INTERNAL);
3255 sprintf(buffer, "l.list_id = %d", list_id);
3256 incremental_after("list", buffer, 0);
3257 aargv[0] = (char *) list_id;
3259 aargv[2] = (char *) users_id;
3260 incremental_clear_before();
3261 EXEC SQL REPEATED INSERT INTO imembers
3262 (list_id, member_type, member_id, ref_count, direct)
3263 VALUES (:list_id, 'USER', :users_id, 1, 1);
3264 if (ingres_errno) return(mr_errcode);
3265 if (sqlca.sqlerrd[2] != 1)
3266 return(MR_INTERNAL);
3267 incremental_after("members", 0, aargv);
3270 /* Cell Name (I know, it shouldn't be hard coded...) */
3271 strcpy(machname, "ATHENA.MIT.EDU");
3272 EXEC SQL SELECT mach_id INTO :m_id FROM machine
3273 WHERE name = :machname;
3276 /* create filesystem */
3277 if (set_next_object_id("filsys_id", "filesys", 0))
3279 incremental_clear_before();
3280 if (islower(login[0]) && islower(login[1])) {
3281 sprintf(directory, "/afs/athena.mit.edu/user/%c/%c/%s",
3282 login[0], login[1], login);
3284 sprintf(directory, "/afs/athena.mit.edu/user/other/%s", login);
3287 EXEC SQL SELECT value INTO :fsidval FROM numvalues
3288 WHERE numvalues.name='filsys_id';
3289 EXEC SQL REPEATED INSERT INTO filesys
3290 (filsys_id, phys_id, label, type, mach_id, name,
3291 mount, access, comments, owner, owners, createflg,
3292 lockertype, modtime, modby, modwith)
3294 (:fsidval, 0, :login, 'AFS', :m_id, :directory,
3295 '/mit/'+:login, 'w', 'User Locker', :users_id, :list_id, 1,
3296 'HOMEDIR', 'now', :who, :entity);
3298 if (ingres_errno) return(mr_errcode);
3299 if (sqlca.sqlerrd[2] != 1)
3300 return(MR_INTERNAL);
3301 sprintf(buffer,"fs.filsys_id = %d",fsidval);
3302 incremental_after("filesys", buffer, 0);
3305 if (def_quota == 0) {
3306 EXEC SQL REPEATED SELECT value INTO :quota FROM numvalues
3307 WHERE name='def_quota';
3308 if (ingres_errno) return(mr_errcode);
3309 if (sqlca.sqlerrd[2] != 1)
3310 return(MR_NO_QUOTA);
3312 incremental_clear_before();
3313 EXEC SQL REPEATED INSERT INTO quota
3314 (entity_id, filsys_id, type, quota, phys_id, modtime, modby, modwith)
3316 (0, :fsidval, 'ANY', :def_quota, 0, 'now', :who, :entity);
3317 if (ingres_errno) return(mr_errcode);
3318 if (sqlca.sqlerrd[2] != 1)
3319 return(MR_INTERNAL);
3323 sprintf(buffer, "q.entity_id = 0 and q.filsys_id = %d and q.type = 'ANY'", fsidval);
3324 incremental_after("quota", buffer, aargv);
3325 com_err(whoami, 0, "quota of %d assigned", def_quota);
3326 if (ingres_errno) return(mr_errcode);
3328 cache_entry(login, "USER", users_id);
3330 EXEC SQL REPEATED UPDATE tblstats SET updates=updates+1, modtime='now'
3331 WHERE table_name='users';
3332 EXEC SQL REPEATED UPDATE tblstats SET appends=appends+1, modtime='now'
3333 WHERE table_name='list' OR table_name='filesys' OR table_name='quota';
3334 if (ingres_errno) return(mr_errcode);
3340 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
3344 ** delta (will be +/- 1)
3347 ** - incr/decr value field in serverhosts table for pop/mach_id
3351 static int set_pop_usage(id, cnt)
3352 EXEC SQL BEGIN DECLARE SECTION;
3355 EXEC SQL END DECLARE SECTION;
3357 EXEC SQL REPEATED UPDATE serverhosts SET value1 = value1 + :cnt
3358 WHERE serverhosts.service = 'POP' AND serverhosts.mach_id = :id;
3360 if (ingres_errno) return(mr_errcode);
3366 /* Validation Routines */
3368 validate_row(q, argv, v)
3369 register struct query *q;
3371 register struct validate *v;
3373 EXEC SQL BEGIN DECLARE SECTION;
3377 EXEC SQL END DECLARE SECTION;
3379 /* build where clause */
3380 build_qual(v->qual, v->argc, argv, qual);
3382 if (log_flags & LOG_VALID)
3383 /* tell the logfile what we're doing */
3384 com_err(whoami, 0, "validating row: %s", qual);
3386 /* look for the record */
3387 sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",q->rtable,qual);
3388 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3390 return(MR_INTERNAL);
3391 EXEC SQL DECLARE csr126 CURSOR FOR stmt;
3392 EXEC SQL OPEN csr126;
3393 EXEC SQL FETCH csr126 USING DESCRIPTOR :SQLDA;
3394 EXEC SQL CLOSE csr126;
3395 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3397 if (ingres_errno) return(mr_errcode);
3398 if (rowcount == 0) return(MR_NO_MATCH);
3399 if (rowcount > 1) return(MR_NOT_UNIQUE);
3403 validate_fields(q, argv, vo, n)
3405 register char *argv[];
3406 register struct valobj *vo;
3409 register int status;
3414 if (log_flags & LOG_VALID)
3415 com_err(whoami, 0, "validating %s in %s: %s",
3416 vo->namefield, vo->table, argv[vo->index]);
3417 status = validate_name(argv, vo);
3421 if (log_flags & LOG_VALID)
3422 com_err(whoami, 0, "validating %s in %s: %s",
3423 vo->idfield, vo->table, argv[vo->index]);
3424 status = validate_id(q, argv, vo);
3428 if (log_flags & LOG_VALID)
3429 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
3430 status = validate_date(argv, vo);
3434 if (log_flags & LOG_VALID)
3435 com_err(whoami, 0, "validating %s type: %s",
3436 vo->table, argv[vo->index]);
3437 status = validate_type(argv, vo);
3441 if (log_flags & LOG_VALID)
3442 com_err(whoami, 0, "validating typed data (%s): %s",
3443 argv[vo->index - 1], argv[vo->index]);
3444 status = validate_typedata(q, argv, vo);
3448 if (log_flags & LOG_VALID)
3449 com_err(whoami, 0, "validating rename %s in %s",
3450 argv[vo->index], vo->table);
3451 status = validate_rename(argv, vo);
3455 if (log_flags & LOG_VALID)
3456 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
3457 status = validate_chars(argv[vo->index]);
3465 status = lock_table(vo);
3469 status = convert_wildcards(argv[vo->index]);
3473 status = convert_wildcards_uppercase(argv[vo->index]);
3478 if (status != MR_EXISTS) return(status);
3482 if (ingres_errno) return(mr_errcode);
3487 /* validate_chars: verify that there are no illegal characters in
3488 * the string. Legal characters are printing chars other than
3489 * ", *, ?, \, [ and ].
3491 static int illegalchars[] = {
3492 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
3493 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
3494 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
3495 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
3496 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
3497 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
3498 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
3499 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
3500 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3501 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3502 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3503 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3504 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3505 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3506 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3507 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3514 if (illegalchars[*s++])
3515 return(MR_BAD_CHAR);
3520 validate_id(q, argv, vo)
3523 register struct valobj *vo;
3525 EXEC SQL BEGIN DECLARE SECTION;
3526 char *name, *tbl, *namefield, *idfield;
3528 EXEC SQL END DECLARE SECTION;
3532 name = argv[vo->index];
3534 namefield = vo->namefield;
3535 idfield = vo->idfield;
3537 if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
3538 !strcmp(tbl, "machine") ||
3539 !strcmp(tbl, "filesys") ||
3540 !strcmp(tbl, "list") ||
3541 !strcmp(tbl, "cluster") ||
3542 !strcmp(tbl, "strings")) {
3543 if (!strcmp(tbl, "machine"))
3544 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3545 status = name_to_id(name, tbl, &id);
3547 *(int *)argv[vo->index] = id;
3549 } else if (status == MR_NO_MATCH && !strcmp(tbl, "strings") &&
3550 (q->type == APPEND || q->type == UPDATE)) {
3551 EXEC SQL SELECT value INTO :id FROM numvalues
3552 WHERE name = 'strings_id';
3554 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'string_id';
3555 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3556 cache_entry(name, "STRING", id);
3557 *(int *)argv[vo->index] = id;
3559 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
3565 if (!strcmp(namefield, "uid")) {
3566 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = %s",idfield,tbl,namefield,name);
3568 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",idfield,tbl,namefield,name);
3570 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3572 return(MR_INTERNAL);
3573 EXEC SQL DECLARE csr127 CURSOR FOR stmt;
3574 EXEC SQL OPEN csr127;
3576 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3577 if(sqlca.sqlcode == 0) {
3579 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3580 if(sqlca.sqlcode == 0) rowcount++;
3582 EXEC SQL CLOSE csr127;
3586 if (rowcount != 1) return(vo->error);
3587 bcopy(SQLDA->sqlvar[0].sqldata,argv[vo->index],sizeof(int));
3591 validate_name(argv, vo)
3593 register struct valobj *vo;
3595 EXEC SQL BEGIN DECLARE SECTION;
3596 char *name, *tbl, *namefield;
3598 EXEC SQL END DECLARE SECTION;
3601 name = argv[vo->index];
3603 namefield = vo->namefield;
3604 if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
3605 for (c = name; *c; c++)
3609 sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
3610 tbl,tbl,namefield,name);
3611 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3613 return(MR_INTERNAL);
3614 EXEC SQL DECLARE csr128 CURSOR FOR stmt;
3615 EXEC SQL OPEN csr128;
3616 EXEC SQL FETCH csr128 USING DESCRIPTOR :SQLDA;
3617 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3618 EXEC SQL CLOSE csr128;
3620 if (ingres_errno) return(mr_errcode);
3621 return ((rowcount == 1) ? MR_EXISTS : vo->error);
3624 validate_date(argv, vo)
3628 EXEC SQL BEGIN DECLARE SECTION;
3632 EXEC SQL END DECLARE SECTION;
3634 idate = argv[vo->index];
3635 EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
3637 if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
3642 validate_rename(argv, vo)
3646 EXEC SQL BEGIN DECLARE SECTION;
3647 char *name, *tbl, *namefield, *idfield;
3649 EXEC SQL END DECLARE SECTION;
3653 c = name = argv[vo->index];
3655 if (illegalchars[*c++])
3656 return(MR_BAD_CHAR);
3658 /* minor kludge to upcasify machine names */
3659 if (!strcmp(tbl, "machine"))
3660 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3661 namefield = vo->namefield;
3662 idfield = vo->idfield;
3665 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3667 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = LEFT('%s',SIZE(%s))",
3668 namefield,tbl,namefield,name,namefield);
3669 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3671 return(MR_INTERNAL);
3672 EXEC SQL DECLARE csr129 CURSOR FOR stmt;
3673 EXEC SQL OPEN csr129;
3674 EXEC SQL FETCH csr129 USING DESCRIPTOR :SQLDA;
3675 if(sqlca.sqlcode == 0) id=1; else id=0;
3676 EXEC SQL CLOSE csr129;
3678 if (ingres_errno) return(mr_errcode);
3684 status = name_to_id(name, tbl, &id);
3685 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3692 validate_type(argv, vo)
3694 register struct valobj *vo;
3696 EXEC SQL BEGIN DECLARE SECTION;
3699 EXEC SQL END DECLARE SECTION;
3702 typename = vo->table;
3703 c = val = argv[vo->index];
3705 if (illegalchars[*c++])
3706 return(MR_BAD_CHAR);
3709 /* uppercase type fields */
3710 for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
3712 EXEC SQL SELECT trans INTO :cdummy FROM alias
3713 WHERE name = :typename AND type='TYPE' AND trans = :val;
3714 if (ingres_errno) return(mr_errcode);
3715 return (sqlca.sqlerrd[2] ? MR_EXISTS : vo->error);
3718 /* validate member or type-specific data field */
3720 validate_typedata(q, argv, vo)
3721 register struct query *q;
3722 register char *argv[];
3723 register struct valobj *vo;
3725 EXEC SQL BEGIN DECLARE SECTION;
3728 char data_type[129];
3730 EXEC SQL END DECLARE SECTION;
3735 /* get named object */
3736 name = argv[vo->index];
3738 /* get field type string (known to be at index-1) */
3739 field_type = argv[vo->index-1];
3741 /* get corresponding data type associated with field type name */
3742 EXEC SQL SELECT trans INTO :data_type FROM alias
3743 WHERE name = :field_type AND type='TYPEDATA';
3744 if (ingres_errno) return(mr_errcode);
3745 if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
3747 /* now retrieve the record id corresponding to the named object */
3748 if (index(data_type, ' '))
3749 *index(data_type, ' ') = 0;
3750 if (!strcmp(data_type, "user")) {
3752 status = name_to_id(name, data_type, &id);
3753 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3755 if (status) return(status);
3756 } else if (!strcmp(data_type, "list")) {
3758 status = name_to_id(name, data_type, &id);
3759 if (status && status == MR_NOT_UNIQUE)
3761 if (status == MR_NO_MATCH) {
3762 /* if idfield is non-zero, then if argv[0] matches the string
3763 * that we're trying to resolve, we should get the value of
3764 * numvalues.[idfield] for the id.
3766 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3767 set_next_object_id(q->validate->object_id, q->rtable, 0);
3769 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
3771 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
3774 } else if (status) return(status);
3775 } else if (!strcmp(data_type, "machine")) {
3777 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3778 status = name_to_id(name, data_type, &id);
3779 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3781 if (status) return(status);
3782 } else if (!strcmp(data_type, "string")) {
3784 status = name_to_id(name, data_type, &id);
3785 if (status && status == MR_NOT_UNIQUE)
3787 if (status == MR_NO_MATCH) {
3788 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3789 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
3791 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3792 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3793 cache_entry(name, "STRING", id);
3794 } else if (status) return(status);
3795 } else if (!strcmp(data_type, "none")) {
3801 /* now set value in argv */
3802 *(int *)argv[vo->index] = id;
3808 /* Lock the table named by the validation object */
3813 sprintf(stmt_buf,"UPDATE %s SET modtime='now' WHERE %s.%s = 0",
3814 vo->table,vo->table,vo->idfield);
3815 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
3816 if (ingres_errno) return(mr_errcode);
3817 if (sqlca.sqlerrd[2] != 1)
3824 /* Check the database at startup time. For now this just resets the
3825 * inprogress flags that the DCM uses.
3828 sanity_check_database()
3833 /* Dynamic SQL support routines */
3834 MR_SQLDA_T *mr_alloc_SQLDA()
3837 short *null_indicators;
3840 if((it=(MR_SQLDA_T *)malloc(sizeof(MR_SQLDA_T)))==NULL) {
3841 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
3845 if((null_indicators=(short *)calloc(QMAXARGS,sizeof(short)))==NULL) {
3846 com_err(whoami, MR_NO_MEM, "setting up SQLDA null indicators");
3850 for(j=0; j<QMAXARGS; j++) {
3851 if((it->sqlvar[j].sqldata=malloc(sizeof(short)+QMAXARGSIZE))==NULL) {
3852 com_err(whoami, MR_NO_MEM, "setting up SQLDA variables");
3855 it->sqlvar[j].sqllen=QMAXARGSIZE;
3856 it->sqlvar[j].sqlind=null_indicators+j;
3857 null_indicators[j]=0;
3864 /* Use this after FETCH USING DESCRIPTOR one or more
3865 * result columns may contain NULLs. This routine is
3866 * not currently needed, since db/schema creates all
3867 * columns with a NOT NULL WITH DEFAULT clause.
3869 * This is currently dead flesh, since no Moira columns
3870 * allow null values; all use default values.
3872 mr_fix_nulls_in_SQLDA(da)
3875 register IISQLVAR *var;
3879 for(j=0, var=da->sqlvar; j<da->sqld; j++, var++) {
3880 switch(var->sqltype) {
3881 case -IISQ_CHA_TYPE:
3885 case -IISQ_INT_TYPE:
3887 intp=(int *)var->sqldata;
3895 /* prefetch_value():
3896 * This routine fetches an appropriate value from the numvalues table.
3897 * It is a little hack to get around the fact that SQL doesn't let you
3898 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
3900 * It is called from the query table as (*v->pre_rtn)(q,Argv,cl) or
3901 * from within a setup_...() routine with the appropriate arguments.
3903 * Correct functioning of this routine may depend on the assumption
3904 * that this query is an APPEND.
3907 prefetch_value(q,argv,cl)
3912 EXEC SQL BEGIN DECLARE SECTION;
3913 char *name = q->validate->object_id;
3915 EXEC SQL END DECLARE SECTION;
3916 int status, limit, argc;
3918 /* set next object id, limiting it if necessary */
3919 if(!strcmp(name, "uid") || !strcmp(name, "gid"))
3920 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
3923 if((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
3926 /* fetch object id */
3927 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name=:name;
3928 if(ingres_errno) return(mr_errcode);
3929 if(sqlca.sqlerrd[2] != 1) return(MR_INTERNAL);
3931 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
3932 sprintf(argv[argc],"%d",value); /** Could save this step by changing tlist from %s to %d **/
3937 /* prefetch_filesys():
3938 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
3939 * Appends the filsys_id and the phys_id to the argv so they can be
3940 * referenced in an INSERT into a table other than filesys. Also
3941 * see comments at prefetch_value().
3943 * Assumes the existence of a row where filsys_id = argv[0], since a
3944 * filesys label has already been resolved to a filsys_id.
3946 prefetch_filesys(q,argv,cl)
3951 EXEC SQL BEGIN DECLARE SECTION;
3953 EXEC SQL END DECLARE SECTION;
3956 fid = *(int *)argv[0];
3957 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
3958 if(ingres_errno) return(mr_errcode);
3960 argc=q->argc+q->vcnt;
3961 sprintf(argv[argc++],"%d",fid);
3962 sprintf(argv[argc],"%d",phid);
3967 /* Convert normal Unix-style wildcards to SQL voodoo */
3968 convert_wildcards(arg)
3971 static char buffer[QMAXARGSIZE];
3972 register char *s, *d;
3974 for(d=buffer,s=arg;*s;s++) {
3976 case '*': *d++='%'; *d++='%'; break;
3977 case '?': *d++='_'; break;
3980 case ']': *d++='*'; *d++ = *s; break;
3981 case '%': *d++='*'; *d++='%'; *d++='%'; break;
3982 default: *d++ = *s; break;
3987 /* Copy back into argv */
3993 /* This version includes uppercase conversion, for things like gmac.
3994 * This is necessary because "LIKE" doesn't work with "uppercase()".
3995 * Including it in a wildcard routine saves making two passes over
3996 * the argument string.
3998 convert_wildcards_uppercase(arg)
4001 static char buffer[QMAXARGSIZE];
4002 register char *s, *d;
4004 for(d=buffer,s=arg;*s;s++) {
4006 case '*': *d++='%'; *d++='%'; break;
4007 case '?': *d++='_'; break;
4010 case ']': *d++='*'; *d++ = *s; break;
4011 case '%': *d++='*'; *d++='%'; *d++='%'; break;
4012 default: *d++=toupper(*s); break; /* This is the only diff. */
4017 /* Copy back into argv */
4024 /* Looks like it's time to build an abstraction barrier, Yogi */
4026 EXEC SQL BEGIN DECLARE SECTION;
4028 EXEC SQL END DECLARE SECTION;
4032 EXEC SQL PREPARE stmt FROM :stmt;
4033 EXEC SQL DESCRIBE stmt INTO :SQLDA;
4034 if(SQLDA->sqld==0) /* Not a SELECT */
4035 return(MR_INTERNAL);
4036 EXEC SQL DECLARE csr CURSOR FOR stmt;
4038 EXEC SQL FETCH csr USING DESCRIPTOR :SQLDA;
4039 if(sqlca.sqlcode==0)
4041 else if((sqlca.sqlcode<0) && mr_errcode)
4050 /* eof:qsupport.dc */