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[];
32 EXEC SQL END DECLARE SECTION;
34 /* Specialized Access Routines */
36 /* access_user - verify that client name equals specified login name
38 * - since field validation routines are called first, a users_id is
39 * now in argv[0] instead of the login name.
42 EXEC SQL WHENEVER SQLERROR CALL ingerr;
44 access_user(q, argv, cl)
49 if (cl->users_id != *(int *)argv[0])
57 /* access_login - verify that client name equals specified login name
59 * argv[0...n] contain search info. q->
62 access_login(q, argv, cl)
67 EXEC SQL BEGIN DECLARE SECTION;
70 EXEC SQL END DECLARE SECTION;
72 build_qual(q->qual, q->argc, argv, qual);
73 if (!strncmp(q->name,"get_user_account",strlen("get_user_account"))) {
74 EXEC SQL SELECT users_id INTO :id FROM users u, strings str WHERE :qual;
76 EXEC SQL SELECT users_id INTO :id FROM users u WHERE :qual;
79 if (sqlca.sqlerrd[2] != 1 || id != cl->users_id)
87 /* access_list - check access for most list operations
89 * Inputs: argv[0] - list_id
91 * argv[2] - member ID (only for queries "amtl" and "dmfl")
92 * argv[7] - group IID (only for query "ulis")
95 * - check that client is a member of the access control list
96 * - OR, if the query is add_member_to_list or delete_member_from_list
97 * and the list is public, allow access if client = member
100 access_list(q, argv, cl)
105 EXEC SQL BEGIN DECLARE SECTION;
106 int list_id, acl_id, flags, gid;
108 EXEC SQL END DECLARE SECTION;
110 int client_id, status;
112 list_id = *(int *)argv[0];
113 EXEC SQL SELECT acl_id, acl_type, gid, publicflg
114 INTO :acl_id, :acl_type, :gid, :flags
116 WHERE list_id = :list_id;
118 if (sqlca.sqlerrd[2] != 1)
121 /* parse client structure */
122 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
125 /* if amtl or dmfl and list is public allow client to add or delete self */
126 if (((!strcmp("amtl", q->shortname) && flags) ||
127 (!strcmp("dmfl", q->shortname))) &&
128 (!strcmp("USER", argv[1]))) {
129 if (*(int *)argv[2] == client_id) return(MR_SUCCESS);
130 /* if update_list, don't allow them to change the GID */
131 } else if (!strcmp("ulis", q->shortname)) {
132 if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
133 (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
137 /* check for client in access control list */
138 status = find_member(acl_type, acl_id, client_type, client_id, 0);
139 if (!status) return(MR_PERM);
145 /* access_visible_list - allow access to list only if it is not hidden,
146 * or if the client is on the ACL
148 * Inputs: argv[0] - list_id
149 * cl - client identifier
152 access_visible_list(q, argv, cl)
157 EXEC SQL BEGIN DECLARE SECTION;
158 int list_id, acl_id, flags ;
160 EXEC SQL END DECLARE SECTION;
162 int client_id, status;
164 list_id = *(int *)argv[0];
165 EXEC SQL SELECT hidden, acl_id, acl_type
166 INTO :flags, :acl_id, :acl_type
168 WHERE list_id = :list_id;
169 if (sqlca.sqlerrd[2] != 1)
174 /* parse client structure */
175 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
178 /* check for client in access control list */
179 status = find_member(acl_type, acl_id, client_type, client_id, 0);
187 /* access_vis_list_by_name - allow access to list only if it is not hidden,
188 * or if the client is on the ACL
190 * Inputs: argv[0] - list name
191 * cl - client identifier
194 access_vis_list_by_name(q, argv, cl)
199 EXEC SQL BEGIN DECLARE SECTION;
200 int acl_id, flags, rowcount;
201 char acl_type[9], *listname;
202 EXEC SQL END DECLARE SECTION;
204 int client_id, status;
207 EXEC SQL SELECT hidden, acl_id, acl_type INTO :flags, :acl_id, :acl_type
208 FROM list WHERE name = :listname;
210 rowcount=sqlca.sqlerrd[2];
218 /* parse client structure */
219 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
222 /* check for client in access control list */
223 status = find_member(acl_type, acl_id, client_type, client_id, 0);
231 /* access_member - allow user to access member of type "USER" and name matches
232 * username, or to access member of type "LIST" and list is one that user is
233 * on the acl of, or the list is visible.
236 access_member(q, argv, cl)
241 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
242 return(access_visible_list(q, &argv[1], cl));
244 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
245 if (cl->users_id == *(int *)argv[1])
249 if (!strcmp(argv[0], "KERBEROS") || !strcmp(argv[0], "RKERBERO")) {
250 if (cl->client_id == *(int *)argv[1])
258 /* access_qgli - special access routine for Qualified_get_lists. Allows
259 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
262 access_qgli(q, argv, cl)
267 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
273 /* access_service - allow access if user is on ACL of service. Don't
274 * allow access if a wildcard is used.
277 access_service(q, argv, cl)
282 EXEC SQL BEGIN DECLARE SECTION;
284 char *name, acl_type[9];
285 EXEC SQL END DECLARE SECTION;
286 int client_id, status;
287 char *client_type, *c;
290 for(c=name;*c;c++) if(islower(*c)) *c = toupper(*c); /* uppercasify */
291 EXEC SQL SELECT acl_id, acl_type INTO :acl_id, :acl_type FROM servers
293 if (sqlca.sqlerrd[2] > 1)
296 /* parse client structure */
297 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
300 /* check for client in access control list */
301 status = find_member(acl_type, acl_id, client_type, client_id, 0);
302 if (!status) return(MR_PERM);
308 /* access_filesys - verify that client is owner or on owners list of filesystem
312 access_filesys(q, argv, cl)
317 EXEC SQL BEGIN DECLARE SECTION;
318 int users_id, list_id;
320 EXEC SQL END DECLARE SECTION;
321 int status, client_id;
325 EXEC SQL SELECT owner, owners INTO :users_id, :list_id FROM filesys
328 if (sqlca.sqlerrd[2] != 1)
330 if (users_id == cl->users_id)
332 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
334 status = find_member("LIST", list_id, client_type, client_id, 0);
345 /* Setup routine for add_user
347 * Inputs: argv[0] - login
352 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
353 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
356 setup_ausr(q, argv, cl)
358 register char *argv[];
362 EXEC SQL BEGIN DECLARE SECTION;
364 EXEC SQL END DECLARE SECTION;
366 if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
370 if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1) {
371 if (set_next_object_id("uid", "users", 1))
372 return(MR_INGRES_ERR);
373 EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'uid';
374 if (sqlca.sqlerrd[2] != 1)
376 sprintf(argv[row], "%d", nuid);
379 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1) {
380 sprintf(argv[0], "#%s", argv[row]);
383 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
390 /* setup_dusr - verify that the user is no longer being referenced
391 * and may safely be deleted.
394 int setup_dusr(q, argv)
398 EXEC SQL BEGIN DECLARE SECTION;
400 EXEC SQL END DECLARE SECTION;
402 id = *(int *)argv[0];
404 /* For now, only allow users to be deleted if their status is 0 */
405 EXEC SQL REPEATED SELECT status INTO :flag FROM users
406 WHERE users_id = :id;
407 if (flag != 0 && flag != 4)
410 EXEC SQL REPEATED DELETE FROM quota WHERE entity_id = :id AND type='USER';
411 EXEC SQL REPEATED DELETE FROM krbmap WHERE users_id = :id;
412 EXEC SQL REPEATED SELECT COUNT(member_id) INTO :cnt FROM imembers
413 WHERE member_id = :id AND member_type = 'USER';
416 EXEC SQL REPEATED SELECT COUNT(label) INTO :cnt FROM filesys
420 EXEC SQL REPEATED SELECT COUNT(name) INTO :cnt FROM list
421 WHERE acl_id = :id AND acl_type = 'USER';
424 EXEC SQL REPEATED SELECT COUNT(name) INTO :cnt FROM servers
425 WHERE acl_id = :id AND acl_type = 'USER';
428 EXEC SQL REPEATED SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
429 WHERE acl_id = :id AND acl_type = 'USER';
438 /* setup_spop: verify that there is already a valid POP machine_id in the
439 * pop_id field. Also take care of keeping track of the post office usage.
441 int setup_spop(q, argv)
445 EXEC SQL BEGIN DECLARE SECTION;
448 EXEC SQL END DECLARE SECTION;
450 id = *(int *)argv[0];
451 EXEC SQL REPEATED SELECT potype, pop_id INTO :type, :mid FROM users
452 WHERE users_id = :id;
453 if(sqlca.sqlerrd[2] = 0)
455 EXEC SQL REPEATED SELECT mach_id INTO :mid FROM machine
456 WHERE mach_id = :mid;
457 if (sqlca.sqlerrd[2] = 0)
459 if (strcmp(strtrim(type), "POP"))
460 set_pop_usage(mid, 1);
465 /* setup_dpob: Take care of keeping track of the post office usage.
467 int setup_dpob(q, argv)
471 EXEC SQL BEGIN DECLARE SECTION;
474 EXEC SQL END DECLARE SECTION;
476 user = *(int *)argv[0];
477 EXEC SQL REPEATED SELECT potype, pop_id INTO :type, :id FROM users
478 WHERE users_id = :user;
479 if (ingres_errno) return(mr_errcode);
481 if (!strcmp(strtrim(type), "POP"))
482 set_pop_usage(id, -1);
487 /* setup_dmac - verify that the machine is no longer being referenced
488 * and may safely be deleted.
491 int setup_dmac(q, argv)
495 EXEC SQL BEGIN DECLARE SECTION;
497 EXEC SQL END DECLARE SECTION;
499 id = *(int *)argv[0];
500 EXEC SQL REPEATED SELECT COUNT(login) INTO :cnt FROM users
501 WHERE potype='POP' AND pop_id = :id;
504 EXEC SQL REPEATED SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
508 EXEC SQL REPEATED SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
512 EXEC SQL REPEATED SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
516 EXEC SQL REPEATED SELECT COUNT(mach_id) INTO :cnt FROM printcap
520 EXEC SQL REPEATED SELECT COUNT(quotaserver) INTO :cnt FROM printcap
521 WHERE quotaserver = :id;
524 EXEC SQL REPEATED SELECT COUNT(mach_id) INTO :cnt FROM palladium
529 EXEC SQL REPEATED DELETE FROM mcmap WHERE mach_id = :id;
530 if (ingres_errno) return(mr_errcode);
535 /* setup_dclu - verify that the cluster is no longer being referenced
536 * and may safely be deleted.
539 int setup_dclu(q, argv)
543 EXEC SQL BEGIN DECLARE SECTION;
545 EXEC SQL END DECLARE SECTION;
547 id = *(int *)argv[0];
548 EXEC SQL REPEATED SELECT COUNT(mach_id) INTO :cnt FROM mcmap
552 EXEC SQL REPEATED SELECT COUNT(clu_id) INTO :cnt FROM svc
562 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
563 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
564 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
565 * a -1 there. Remember that this is also used for ulis, with the indexes
566 * at 6 & 7. Also check that the list name does not contain uppercase
567 * characters, control characters, @, or :.
570 static int badlistchars[] = {
571 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
572 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
573 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
574 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
575 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
576 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, /* P - _ */
577 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
578 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
579 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
580 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
581 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
582 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
583 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
584 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
585 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
586 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
589 int setup_alis(q, argv, cl)
594 EXEC SQL BEGIN DECLARE SECTION;
596 EXEC SQL END DECLARE SECTION;
601 if (!strcmp(q->shortname, "alis"))
603 else if (!strcmp(q->shortname, "ulis"))
606 for (p = (unsigned char *) argv[idx]; *p; p++)
607 if (badlistchars[*p])
610 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1) {
611 if (atoi(argv[5 + idx])) {
612 if (set_next_object_id("gid", "list", 1))
613 return(MR_INGRES_ERR);
614 EXEC SQL REPEATED SELECT value INTO :ngid FROM numvalues
616 if (ingres_errno) return(mr_errcode);
617 sprintf(argv[6 + idx], "%d", ngid);
619 strcpy(argv[6 + idx], "-1");
623 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
630 /* setup_dlis - verify that the list is no longer being referenced
631 * and may safely be deleted.
634 int setup_dlis(q, argv)
640 id = *(int *)argv[0];
641 sprintf(stmt_buf,"SELECT member_id FROM imembers WHERE member_id = %d AND member_type='LIST'",id);
642 if(ec=mr_select_any(stmt_buf)) {
643 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
646 sprintf(stmt_buf,"SELECT member_id FROM imembers WHERE list_id = %d",id);
647 if(ec=mr_select_any(stmt_buf)) {
648 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
651 sprintf(stmt_buf,"SELECT label FROM filesys WHERE owners = %d",id);
652 if(ec=mr_select_any(stmt_buf)) {
653 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
656 sprintf(stmt_buf,"SELECT tag FROM capacls WHERE list_id = %d",id);
657 if(ec=mr_select_any(stmt_buf)) {
658 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
661 sprintf(stmt_buf,"SELECT name FROM list WHERE acl_id = %d AND acl_type='LIST' AND list_id != %d",id,id);
662 if(ec=mr_select_any(stmt_buf)) {
663 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
666 sprintf(stmt_buf,"SELECT name FROM servers WHERE acl_id = %d AND acl_type='LIST'",id);
667 if(ec=mr_select_any(stmt_buf)) {
668 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
671 sprintf(stmt_buf,"SELECT entity_id FROM quota WHERE entity_id = %d AND type='GROUP'",id);
672 if(ec=mr_select_any(stmt_buf)) {
673 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
676 sprintf(stmt_buf,"SELECT acl_id FROM hostaccess WHERE acl_id = %d AND acl_type='LIST'",id);
677 if(ec=mr_select_any(stmt_buf)) {
678 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
681 sprintf(stmt_buf,"SELECT class FROM zephyr z \
682 WHERE z.xmt_type = 'LIST' AND z.xmt_id = %d \
683 OR z.sub_type = 'LIST' AND z.sub_id = %d \
684 OR z.iws_type = 'LIST' AND z.iws_id = %d \
685 OR z.iui_type = 'LIST' AND z.iui_id = %d",id,id,id,id);
686 if(ec=mr_select_any(stmt_buf)) {
687 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
694 /* setup_dsin - verify that the service is no longer being referenced
695 * and may safely be deleted.
698 int setup_dsin(q, argv)
702 EXEC SQL BEGIN DECLARE SECTION;
705 EXEC SQL END DECLARE SECTION;
707 sprintf(stmt_buf,"SELECT service FROM serverhosts WHERE service = UPPERCASE('%s')",argv[0]);
708 if(ec=mr_select_any(stmt_buf)) {
716 EXEC SQL SELECT inprogress INTO :ec FROM servers
717 WHERE name=UPPERCASE(:svrname);
727 /* setup_dshi - verify that the service-host is no longer being referenced
728 * and may safely be deleted.
731 int setup_dshi(q, argv)
735 EXEC SQL BEGIN DECLARE SECTION;
738 EXEC SQL END DECLARE SECTION;
741 id = *(int *)argv[1];
743 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
744 WHERE service=UPPERCASE(:svrname) AND mach_id = :id;
756 ** setup_add_filesys - verify existance of referenced file systems
768 ** * extract directory prefix from name
769 ** * verify mach_id/dir in nfsphys
770 ** * verify access in {r, w, R, W}
772 ** Side effect: sets variable var_phys_id to the ID of the physical
773 ** filesystem (nfsphys_id for NFS, 0 for RVD)
776 ** MR_NFS - specified directory not exported
777 ** MR_FILESYS_ACCESS - invalid filesys access
781 EXEC SQL BEGIN DECLARE SECTION;
782 static int var_phys_id;
783 EXEC SQL END DECLARE SECTION;
785 setup_afil(q, argv, cl)
792 EXEC SQL BEGIN DECLARE SECTION;
794 char ftype[32], *access;
795 EXEC SQL END DECLARE SECTION;
798 mach_id = *(int *)argv[2];
803 sprintf(ftype, "fs_access_%s", type);
804 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
805 WHERE name = :ftype AND type = 'TYPE' and trans = :access;
806 if (ingres_errno) return(mr_errcode);
807 if (ok == 0) return(MR_FILESYS_ACCESS);
809 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
812 if (!strcmp(type, "NFS"))
813 return (check_nfs(mach_id, name, access));
819 /* Verify the arguments, depending on the FStype. Also, if this is an
820 * NFS filesystem, then update any quotas for that filesystem to reflect
824 setup_ufil(q, argv, cl)
831 EXEC SQL BEGIN DECLARE SECTION;
832 int fid, total, who, ok;
833 char *entity, ftype[32], *access;
835 short int total_null;
836 EXEC SQL END DECLARE SECTION;
839 mach_id = *(int *)argv[3];
842 fid = *(int *)argv[0];
846 sprintf(ftype, "fs_access_%s", type);
847 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
848 WHERE name = :ftype AND type='TYPE' AND trans = :access;
849 if (ingres_errno) return(mr_errcode);
850 if (ok == 0) return(MR_FILESYS_ACCESS);
852 EXEC SQL SELECT type INTO :ftype FROM filesys
853 WHERE filsys_id = :fid;
855 if (ingres_errno) return(mr_errcode);
857 if (!strcmp(type, "NFS")) {
858 status = check_nfs(mach_id, name, access);
859 EXEC SQL UPDATE quota SET phys_id = :var_phys_id
860 WHERE filsys_id = :fid;
861 if (ingres_errno) return(mr_errcode);
863 } else if (!strcmp(type, "AFS") && strcmp(ftype, "AFS")) {
865 EXEC SQL REPEATED DELETE FROM quota
866 WHERE type = 'ANY' AND filsys_id = :fid;
867 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
868 WHERE filsys_id = :fid AND phys_id != 0;
869 if (ingres_errno) return(mr_errcode);
870 if (!total_null && (total != 0)) {
872 * append quota (quota = total, filsys_id = fid,
873 * phys_id = 0, entity_id = 0, type = "ANY",
874 * modtime = "now", modby = who, modwith = entity)
876 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
877 type, modtime, modby, modwith)
878 VALUES (:total, :fid, 0, 0,
879 'ANY', 'now', :who, :entity) ;
880 if (ingres_errno) return(mr_errcode);
883 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
884 if (ingres_errno) return(mr_errcode);
890 /* Find the NFS physical partition that the named directory is on.
891 * This is done by comparing the dir against the mount point of the
892 * partition. To make sure we get the correct match when there is
893 * more than one, we sort the query in reverse order by dir name.
896 check_nfs(mach_id, name, access)
897 EXEC SQL BEGIN DECLARE SECTION;
899 EXEC SQL END DECLARE SECTION;
903 EXEC SQL BEGIN DECLARE SECTION;
905 EXEC SQL END DECLARE SECTION;
912 EXEC SQL DECLARE csr101 CURSOR FOR
913 SELECT nfsphys_id, TRIM (dir) FROM nfsphys
914 WHERE mach_id = :mach_id
916 EXEC SQL OPEN csr101;
918 EXEC SQL FETCH csr101 INTO :var_phys_id, :dir;
919 if(sqlca.sqlcode != 0) break;
923 if (*cp1++ != *cp2) break;
931 EXEC SQL CLOSE csr101;
938 /* setup_dfil: free any quota records and fsgroup info associated with
939 * a filesystem when it is deleted. Also adjust the allocation numbers.
942 setup_dfil(q, argv, cl)
947 EXEC SQL BEGIN DECLARE SECTION;
948 int id, total, phys_id;
950 EXEC SQL END DECLARE SECTION;
952 id = *(int *)argv[0];
953 EXEC SQL REPEATED SELECT SUM (quota) INTO :total:none FROM quota
954 WHERE filsys_id = :id;
958 /** What if there are multiple phys_id's per f/s? (bad data) **/
959 EXEC SQL REPEATED SELECT phys_id INTO :phys_id FROM filesys
960 WHERE filsys_id = :id;
961 EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated - :total
962 WHERE nfsphys_id = :phys_id;
965 EXEC SQL REPEATED DELETE FROM quota WHERE filsys_id = :id;
967 EXEC SQL REPEATED DELETE FROM fsgroup WHERE filsys_id = :id;
968 EXEC SQL REPEATED DELETE FROM fsgroup WHERE group_id = :id;
969 if (ingres_errno) return(mr_errcode);
974 /* setup_dnfp: check to see that the nfs physical partition does not have
975 * any filesystems assigned to it before allowing it to be deleted.
978 setup_dnfp(q, argv, cl)
983 EXEC SQL BEGIN DECLARE SECTION;
986 EXEC SQL END DECLARE SECTION;
988 id = *(int *)argv[0];
990 EXEC SQL REPEATED SELECT label INTO :cnt FROM filesys fs, nfsphys np
991 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
992 AND np.mach_id = :id AND np.dir = :dir;
1001 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
1002 * argv[0] = filsys_id
1003 * argv[1] = type if "update_quota" or "delete_quota"
1004 * argv[2 or 1] = users_id or list_id
1007 setup_dqot(q, argv, cl)
1012 EXEC SQL BEGIN DECLARE SECTION;
1013 int quota, fs, id, physid;
1015 EXEC SQL END DECLARE SECTION;
1017 fs = *(int *)argv[0];
1018 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
1020 id = *(int *)argv[2];
1023 id = *(int *)argv[1];
1026 EXEC SQL REPEATED SELECT quota INTO :quota FROM quota
1027 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
1028 EXEC SQL REPEATED SELECT phys_id INTO :physid FROM filesys
1029 WHERE filsys_id = :fs;
1030 EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated - :quota
1031 WHERE nfsphys_id = :physid;
1033 if (ingres_errno) return(mr_errcode);
1038 /* setup_sshi: don't exclusive lock the machine table during
1039 * set_server_host_internal.
1041 /** Not allowed under (INGRES) SQL **/
1042 setup_sshi(q, argv, cl)
1049 EXEC SQL set lockmode session where readlock = system;
1056 /* setup add_kerberos_user_mapping: add the string to the string
1057 * table if necessary.
1060 setup_akum(q, argv, cl)
1065 EXEC SQL BEGIN DECLARE SECTION;
1068 EXEC SQL END DECLARE SECTION;
1071 if (name_to_id(name, "STRING", &id) != MR_SUCCESS) {
1072 if (q->type != APPEND) return(MR_STRING);
1073 EXEC SQL SELECT value INTO :id FROM numvalues
1074 WHERE name = 'strings_id';
1076 EXEC SQL UPDATE numvalues SET value = :id
1077 WHERE name = 'strings_id';
1078 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
1079 cache_entry(name, "STRING", id);
1081 if (ingres_errno) return(mr_errcode);
1082 *(int *)argv[1] = id;
1088 /* FOLLOWUP ROUTINES */
1090 /* generic set_modtime routine. This takes the table name from the query,
1091 * and will update the modtime, modby, and modwho fields in the entry in
1092 * the table whose name field matches argv[0].
1095 set_modtime(q, argv, cl)
1100 char *name, *entity, *table;
1103 entity = cl->entity;
1104 who = cl->client_id;
1108 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, modwith = '%s' WHERE %s.name = LEFT('%s',SIZE(%s.name))",table,who,entity,table,name,table);
1109 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1114 /* generic set_modtime_by_id routine. This takes the table name from
1115 * the query, and the id name from the validate record,
1116 * and will update the modtime, modby, and modwho fields in the entry in
1117 * the table whose id matches argv[0].
1120 set_modtime_by_id(q, argv, cl)
1125 char *entity, *table, *id_name;
1128 entity = cl->entity;
1129 who = cl->client_id;
1131 id_name = q->validate->object_id;
1133 id = *(int *)argv[0];
1134 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, \
1135 modwith = '%s' WHERE %s.%s = %d",table,who,entity,table,id_name,id);
1136 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1141 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
1144 set_finger_modtime(q, argv, cl)
1149 EXEC SQL BEGIN DECLARE SECTION;
1152 EXEC SQL END DECLARE SECTION;
1154 entity = cl->entity;
1155 who = cl->client_id;
1156 users_id = *(int *)argv[0];
1158 EXEC SQL UPDATE users SET fmodtime='now', fmodby = :who, fmodwith = :entity
1159 WHERE users.users_id = :users_id;
1165 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
1168 set_pobox_modtime(q, argv, cl)
1173 EXEC SQL BEGIN DECLARE SECTION;
1176 EXEC SQL END DECLARE SECTION;
1178 entity = cl->entity;
1179 who = cl->client_id;
1180 users_id = *(int *)argv[0];
1182 EXEC SQL UPDATE users SET pmodtime='now', pmodby = :who, pmodwith = :entity
1183 WHERE users.users_id = :users_id;
1189 /* Like set_modtime, but uppercases the name first.
1192 set_uppercase_modtime(q, argv, cl)
1197 char *name, *entity, *table;
1200 entity = cl->entity;
1201 who = cl->client_id;
1205 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, modwith = '%s' WHERE %s.name = UPPERCASE(LEFT('%s',SIZE(%s.name)))",table,who,entity,table,name,table);
1206 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1212 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
1213 * is necessary for add_machine_to_cluster becuase the table that query
1214 * operates on is "mcm", not "machine".
1217 set_mach_modtime_by_id(q, argv, cl)
1222 EXEC SQL BEGIN DECLARE SECTION;
1225 EXEC SQL END DECLARE SECTION;
1227 entity = cl->entity;
1228 who = cl->client_id;
1229 id = *(int *)argv[0];
1230 EXEC SQL UPDATE machine SET modtime='now', modby = :who, modwith = :entity
1231 WHERE machine.mach_id = :id;
1237 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
1238 * is necessary for add_cluster_data and delete_cluster_data becuase the
1239 * table that query operates on is "svc", not "cluster".
1242 set_cluster_modtime_by_id(q, argv, cl)
1247 EXEC SQL BEGIN DECLARE SECTION;
1250 EXEC SQL END DECLARE SECTION;
1252 entity = cl->entity;
1253 who = cl->client_id;
1255 id = *(int *)argv[0];
1256 EXEC SQL UPDATE cluster SET modtime='now', modby = :who, modwith = :entity
1257 WHERE cluster.clu_id = :id;
1262 /* sets the modtime on the serverhost where the service name is in argv[0]
1263 * and the mach_id is in argv[1].
1266 set_serverhost_modtime(q, argv, cl)
1271 EXEC SQL BEGIN DECLARE SECTION;
1272 char *entity, *serv;
1274 EXEC SQL END DECLARE SECTION;
1276 entity = cl->entity;
1277 who = cl->client_id;
1280 id = *(int *)argv[1];
1281 EXEC SQL UPDATE serverhosts
1282 SET modtime = 'now', modby = :who, modwith = :entity
1283 WHERE service = :serv AND mach_id = :id;
1288 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1289 * directory name is in argv[1].
1292 set_nfsphys_modtime(q, argv, cl)
1297 EXEC SQL BEGIN DECLARE SECTION;
1300 EXEC SQL END DECLARE SECTION;
1302 entity = cl->entity;
1303 who = cl->client_id;
1305 id = *(int *)argv[0];
1307 EXEC SQL UPDATE nfsphys SET modtime = 'now', modby = :who, modwith = :entity
1308 WHERE dir = :dir AND mach_id = :id;
1313 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1317 set_filesys_modtime(q, argv, cl)
1322 EXEC SQL BEGIN DECLARE SECTION;
1323 char *label, *entity;
1325 EXEC SQL END DECLARE SECTION;
1327 entity = cl->entity;
1328 who = cl->client_id;
1331 if (!strcmp(q->shortname, "ufil"))
1334 EXEC SQL UPDATE filesys SET modtime = 'now', modby = :who,
1335 modwith = :entity, phys_id = :var_phys_id
1336 WHERE label = LEFT(:label,SIZE(label));
1341 /* sets the modtime on a zephyr class, where argv[0] contains the class
1345 set_zephyr_modtime(q, argv, cl)
1350 EXEC SQL BEGIN DECLARE SECTION;
1351 char *class, *entity;
1353 EXEC SQL END DECLARE SECTION;
1355 entity = cl->entity;
1356 who = cl->client_id;
1360 EXEC SQL UPDATE zephyr SET modtime = 'now', modby = :who, modwith = :entity
1361 WHERE class = LEFT(:class,SIZE(class));
1367 /* fixes the modby field. This will be the second to last thing in the
1368 * argv, the argv length is determined from the query structure. It is
1369 * passed as a pointer to an integer. This will either turn it into a
1370 * username, or # + the users_id.
1372 followup_fix_modby(q, sq, v, action, actarg, cl)
1374 register struct save_queue *sq;
1376 register int (*action)();
1377 register int actarg;
1381 char **argv, *malloc();
1385 while (sq_get_data(sq, &argv)) {
1388 status = id_to_name(id, "USER", &argv[i]);
1390 status = id_to_name(-id, "STRING", &argv[i]);
1391 if (status && status != MR_NO_MATCH)
1393 (*action)(q->vcnt, argv, actarg);
1394 for (j = 0; j < q->vcnt; j++)
1403 /* After retrieving a user account, fix the modby field and signature.
1404 * The modby field is the second to last thing in the
1405 * argv, the argv length is determined from the query structure. It is
1406 * passed as a pointer to an integer. This will either turn it into a
1407 * username, or # + the users_id. Only "gua*" queries have a signature,
1408 * these are ones with U_END return values. "gub*" queries also use this
1409 * routine but don't have a signature.
1411 followup_guax(q, sq, v, action, actarg, cl)
1413 register struct save_queue *sq;
1415 register int (*action)();
1416 register int actarg;
1420 char **argv, *malloc();
1422 unsigned char sigbuf[256];
1425 EXEC SQL BEGIN DECLARE SECTION;
1428 varchar struct { short data_size; char data_buf[257];} rsig;
1429 EXEC SQL END DECLARE SECTION;
1434 while (sq_get_data(sq, &argv)) {
1436 com_err(whoami, 0, "argv[SIGNATURE] = \"%s\"", argv[U_SIGNATURE]);
1440 status = id_to_name(id, "USER", &argv[i]);
1442 status = id_to_name(-id, "STRING", &argv[i]);
1443 if (status && status != MR_NO_MATCH)
1446 if (q->vcnt == U_END && strlen(argv[U_SIGNATURE])) {
1447 login = argv[U_NAME];
1448 EXEC SQL REPEATED SELECT signature, sigdate, sigwho
1449 INTO :rsig, :timestamp, :who FROM users
1450 WHERE login = :login;
1451 /** What about (INGRES) error handling? **/
1453 status = id_to_name(who, "STRING", &kname);
1454 si.timestamp = timestamp;
1455 si.SigInfoVersion = 0; /* XXXXX this isn't used */
1456 kname_parse(si.pname, si.pinst, si.prealm, kname);
1458 rsig.data_buf[rsig.data_size] = 0;
1459 si.rawsig = (unsigned char *)strsave(rsig.data_buf);
1460 if (log_flags & LOG_GDSS)
1461 com_err(whoami, 0, "rawsig length = %d, sig=\"%s\"", strlen(si.rawsig), si.rawsig);
1462 GDSS_Recompose(&si, sigbuf);
1464 free(argv[U_SIGNATURE]);
1465 argv[U_SIGNATURE] = strsave(sigbuf);
1466 if (log_flags & LOG_GDSS)
1467 com_err(whoami, 0, "generated signature length %d", strlen(sigbuf));
1470 (*action)(q->vcnt, argv, actarg);
1471 for (j = 0; j < q->vcnt; j++)
1481 ** followup_ausr - add finger and pobox entries, set_user_modtime
1484 ** argv[0] - login (add_user)
1485 ** argv[3] - last name
1486 ** argv[4] - first name
1487 ** argv[5] - middle name
1491 followup_ausr(q, argv, cl)
1496 EXEC SQL BEGIN DECLARE SECTION;
1497 int who, status, id;
1498 char *login, *entity, *src, *dst, *name;
1500 EXEC SQL END DECLARE SECTION;
1502 char databuf[32], *kname_unparse();
1503 EXEC SQL BEGIN DECLARE SECTION;
1505 int sigwho, timestamp;
1506 EXEC SQL END DECLARE SECTION;
1510 /* build fullname */
1511 if (strlen(argv[4]) && strlen(argv[5]))
1512 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1513 else if (strlen(argv[4]))
1514 sprintf(fullname, "%s %s", argv[4], argv[3]);
1516 sprintf(fullname, "%s", argv[3]);
1519 if (q->vcnt == U_END && *argv[U_SIGNATURE]) {
1520 sprintf(databuf, "%s:%s", argv[U_NAME], argv[U_MITID]);
1521 /* skip bytes for timestamp & kname */
1522 si.rawsig = (unsigned char *) rawsig;
1523 status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE], &si);
1524 if (strlen(rawsig) > mr_sig_length) {
1525 com_err(whoami, 0, "GDSS signature would be truncated."); /** untested **/
1526 return(MR_INTERNAL);
1529 name = kname_unparse(si.pname, si.pinst, si.prealm);
1530 status = name_to_id(name, "STRING", &sigwho);
1531 if (status == MR_NO_MATCH) {
1532 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1533 WHERE name='strings_id';
1535 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1536 WHERE name='strings_id';
1537 EXEC SQL INSERT INTO strings (string_id, string)
1538 VALUES (:sigwho, :name);
1541 timestamp = si.timestamp;
1543 if (log_flags & LOG_GDSS)
1544 hex_dump(argv[U_SIGNATURE]);
1545 return(gdss2et(status));
1555 who = cl->client_id;
1556 entity = cl->entity;
1558 /* create finger entry, pobox & set modtime on user */
1560 EXEC SQL REPEATED UPDATE users
1561 SET modtime='now', modby=:who, modwith = :entity,
1562 fullname = :fullname, affiliation = type,
1563 signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho,
1564 fmodtime='now', fmodby = :who, fmodwith = :entity,
1565 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1566 WHERE login = :login;
1568 EXEC SQL REPEATED UPDATE users
1569 SET modtime='now', modby=:who, modwith = :entity,
1570 fullname = :fullname, affiliation = type,
1571 fmodtime='now', fmodby = :who, fmodwith = :entity,
1572 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1573 WHERE login = :login;
1581 ** followup_uusr - do signature, set_user_modtime
1584 ** argv[0] - login (add_user)
1585 ** argv[U_SIGNATURE] - sig
1589 followup_uuac(q, argv, cl)
1594 EXEC SQL BEGIN DECLARE SECTION;
1595 int who, status, id;
1596 char *entity, *name;
1597 EXEC SQL END DECLARE SECTION;
1599 char databuf[32], *kname_unparse();
1600 EXEC SQL BEGIN DECLARE SECTION;
1603 int sigwho, timestamp;
1604 EXEC SQL END DECLARE SECTION;
1608 id = *(int *)argv[0];
1609 who = cl->client_id;
1610 entity = cl->entity;
1613 if (q->vcnt == U_MODTIME && *argv[U_SIGNATURE + 1]) {
1615 status = id_to_name(id, "USER", &login);
1616 sprintf(databuf, "%s:%s", login, argv[U_MITID+1]);
1618 /* skip bytes for timestamp & kname */
1619 si.rawsig = (unsigned char *) rawsig;
1621 com_err(whoami, 0, "verifying sig");
1623 status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE+1], &si);
1625 com_err(whoami, 0, "verified");
1627 if (strlen(rawsig) > mr_sig_length) {
1628 com_err(whoami, 0, "GDSS signature would be truncated."); /** untested **/
1629 return(MR_INTERNAL);
1632 name = kname_unparse(si.pname, si.pinst, si.prealm);
1633 status = name_to_id(name, "STRING", &sigwho);
1634 if (status == MR_NO_MATCH) {
1635 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1636 WHERE name='strings_id';
1638 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1639 WHERE name='strings_id';
1640 EXEC SQL INSERT INTO strings (string_id, string)
1641 VALUES (:sigwho, :name);
1644 timestamp = si.timestamp;
1646 if (log_flags & LOG_GDSS)
1647 hex_dump(argv[U_SIGNATURE+1]);
1648 return(gdss2et(status));
1657 /* create finger entry, pobox & set modtime on user */
1660 EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity,
1661 signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho
1662 WHERE users_id = :id;
1664 EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity
1665 WHERE users_id = :id;
1671 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1672 * type in argv[1]. Then completes the upcall to the user.
1674 * argv[2] is of the form "123:234" where the first integer is the machine
1675 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1676 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1680 followup_gpob(q, sq, v, action, actarg, cl)
1681 register struct query *q;
1682 register struct save_queue *sq;
1683 register struct validate *v;
1684 register int (*action)();
1688 char **argv, *index();
1690 int mid, sid, status, i;
1693 while (sq_get_data(sq, &argv)) {
1694 mr_trim_args(2, argv);
1696 p = index(argv[2], ':');
1698 mid = atoi(argv[2]);
1701 if (!strcmp(ptype, "POP")) {
1702 status = id_to_name(mid, "MACHINE", &argv[2]);
1703 if (status == MR_NO_MATCH)
1705 } else if (!strcmp(ptype, "SMTP")) {
1706 status = id_to_name(sid, "STRING", &argv[2]);
1707 if (status == MR_NO_MATCH)
1709 } else /* ptype == "NONE" */ {
1712 if (status) return(status);
1714 if (!strcmp(q->shortname, "gpob")) {
1715 sid = atoi(argv[4]);
1717 status = id_to_name(sid, "USER", &argv[4]);
1719 status = id_to_name(-sid, "STRING", &argv[4]);
1721 if (status && status != MR_NO_MATCH) return(status);
1723 (*action)(q->vcnt, argv, actarg);
1725 /* free saved data */
1726 for (i = 0; i < q->vcnt; i++)
1732 return (MR_SUCCESS);
1736 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1737 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1738 * proper name based on the type, and repace that string in the argv.
1739 * Also fixes the modby field by called followup_fix_modby.
1742 followup_glin(q, sq, v, action, actarg, cl)
1743 register struct query *q;
1744 register struct save_queue *sq;
1745 register struct validate *v;
1746 register int (*action)();
1750 char **argv, *malloc(), *realloc(), *type;
1751 int id, i, idx, status;
1754 if (!strcmp(q->shortname, "gsin"))
1757 while (sq_get_data(sq, &argv)) {
1758 mr_trim_args(q->vcnt, argv);
1760 id = atoi(argv[i = q->vcnt - 2]);
1762 status = id_to_name(id, "USER", &argv[i]);
1764 status = id_to_name(-id, "STRING", &argv[i]);
1765 if (status && status != MR_NO_MATCH)
1768 id = atoi(argv[idx]);
1769 type = argv[idx - 1];
1771 if (!strcmp(type, "LIST")) {
1772 status = id_to_name(id, "LIST", &argv[idx]);
1773 } else if (!strcmp(type, "USER")) {
1774 status = id_to_name(id, "USER", &argv[idx]);
1775 } else if (!strcmp(type, "KERBEROS")) {
1776 status = id_to_name(id, "STRING", &argv[idx]);
1777 } else if (!strcmp(type, "NONE")) {
1780 argv[idx] = strsave("NONE");
1784 argv[idx] = strsave("???");
1786 if (status && status != MR_NO_MATCH)
1789 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1790 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1791 strcpy(argv[6], UNIQUE_GID);
1795 (*action)(q->vcnt, argv, actarg);
1797 /* free saved data */
1798 for (i = 0; i < q->vcnt; i++)
1804 return (MR_SUCCESS);
1808 /* followup_gqot: Fix the entity name, directory name & modby fields
1809 * argv[0] = filsys_id
1811 * argv[2] = entity_id
1812 * argv[3] = ascii(quota)
1815 followup_gqot(q, sq, v, action, actarg, cl)
1817 register struct save_queue *sq;
1819 register int (*action)();
1820 register int actarg;
1824 char **argv, *malloc();
1825 EXEC SQL BEGIN DECLARE SECTION;
1828 EXEC SQL END DECLARE SECTION;
1831 if (!strcmp(q->name, "get_quota") ||
1832 !strcmp(q->name, "get_quota_by_filesys"))
1836 while (sq_get_data(sq, &argv)) {
1838 switch (argv[1][0]) {
1840 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1844 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1848 argv[2] = strsave("system:anyuser");
1852 argv[2] = malloc(8);
1853 sprintf(argv[2], "%d", id);
1856 id = atoi(argv[idx]);
1858 argv[idx] = malloc(256);
1862 EXEC SQL REPEATED SELECT name INTO :name FROM filesys
1863 WHERE label = :label;
1865 EXEC SQL REPEATED SELECT dir INTO :name FROM nfsphys
1866 WHERE nfsphys_id = :id;
1868 if (sqlca.sqlerrd[2] != 1) {
1869 sprintf(argv[idx], "#%d", id);
1872 id = atoi(argv[idx+3]);
1874 status = id_to_name(id, "USER", &argv[idx+3]);
1876 status = id_to_name(-id, "STRING", &argv[idx+3]);
1877 if (status && status != MR_NO_MATCH)
1879 (*action)(q->vcnt, argv, actarg);
1880 for (j = 0; j < q->vcnt; j++)
1889 /* followup_aqot: Add allocation to nfsphys after creating quota.
1890 * argv[0] = filsys_id
1891 * argv[1] = type if "add_quota" or "update_quota"
1893 * argv[3 or 2] = ascii(quota)
1896 followup_aqot(q, argv, cl)
1901 EXEC SQL BEGIN DECLARE SECTION;
1902 int quota, id, fs, who, physid;
1903 char *entity, *qtype, *table_name;
1904 EXEC SQL END DECLARE SECTION;
1909 table_name=q->rtable;
1910 fs = *(int *)argv[0];
1911 EXEC SQL REPEATED SELECT phys_id INTO :physid FROM filesys
1912 WHERE filsys_id = :fs;
1916 if (!strcmp(q->shortname, "aqot") || !strcmp(q->shortname, "uqot")) {
1918 id = *(int *)argv[2];
1919 quota = atoi(argv[3]);
1920 sprintf(incr_qual,"q.filsys_id = %d",fs);
1923 id = *(int *)argv[1];
1924 quota = atoi(argv[2]);
1925 sprintf(incr_qual,"q.filsys_id=%d AND q.type='%s' AND q.entity_id=%d",
1929 /* quota case of incremental_{before|after} only looks at slot 1 */
1932 /* Follows one of many possible gross hacks to fix these particular
1933 * conflicts between what is possible in the query table and what
1934 * is possible in SQL.
1936 if(q->type==APPEND) {
1937 incremental_clear_before();
1938 EXEC SQL INSERT INTO quota
1939 (filsys_id, type, entity_id, quota, phys_id)
1940 VALUES (:fs, :qtype, :id, :quota, :physid);
1941 incremental_after(table_name, incr_qual, incr_argv);
1943 incremental_before(table_name, incr_qual, incr_argv);
1944 EXEC SQL UPDATE quota SET quota = :quota
1945 WHERE filsys_id = :fs AND type = :qtype AND entity_id = :id;
1946 status = mr_errcode;
1947 incremental_after(table_name, incr_qual, incr_argv);
1952 flush_name(argv[0], q->rtable);
1953 if(q->type==APPEND) {
1954 EXEC SQL UPDATE tblstats SET appends = appends + 1, modtime = 'now'
1955 WHERE table_name = :table_name;
1957 EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = 'now'
1958 WHERE table_name = :table_name;
1961 /* Proceed with original followup */
1962 who = cl->client_id;
1963 entity = cl->entity;
1965 EXEC SQL REPEATED UPDATE quota
1966 SET modtime = 'now', modby = :who, modwith = :entity
1967 WHERE filsys_id = :fs and type = :qtype and entity_id = :id;
1968 EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated + :quota
1969 WHERE nfsphys_id = :physid;
1970 if (ingres_errno) return(mr_errcode);
1975 /* Necessitated by the requirement of a correlation name by the incremental
1976 * routines, since query table deletes don't provide one.
1978 followup_dqot(q,argv,cl)
1986 EXEC SQL BEGIN DECLARE SECTION;
1989 EXEC SQL END DECLARE SECTION;
1991 fs = *(int *)argv[0];
1992 if (!strcmp(q->shortname, "dqot")) {
1994 id = *(int *)argv[2];
1997 id = *(int *)argv[1];
1999 sprintf(incr_qual,"q.filsys_id=%d AND q.type='%s' AND q.entity_id=%d",
2002 /* quota case of incremental_{before|after} only looks at slot 1 */
2005 incremental_before(q->rtable, incr_qual, incr_argv);
2006 EXEC SQL DELETE FROM quota q WHERE :incr_qual;
2007 incremental_clear_after();
2011 flush_name(argv[0], q->rtable);
2013 tblname = q->rtable;
2014 EXEC SQL UPDATE tblstats SET deletes = deletes + 1, modtime = 'now'
2015 WHERE table_name = :tblname;
2020 followup_gpce(q, sq, v, action, actarg, cl)
2022 register struct save_queue *sq;
2024 register int (*action)();
2025 register int actarg;
2029 char **argv, *malloc();
2033 while (sq_get_data(sq, &argv)) {
2034 id = atoi(argv[PCAP_QSERVER]);
2035 status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
2036 if (status) return (status);
2039 status = id_to_name(id, "USER", &argv[i]);
2041 status = id_to_name(-id, "STRING", &argv[i]);
2042 if (status && status != MR_NO_MATCH)
2044 (*action)(q->vcnt, argv, actarg);
2045 for (j = 0; j < q->vcnt; j++)
2057 followup_gzcl(q, sq, v, action, actarg, cl)
2058 register struct query *q;
2059 register struct save_queue *sq;
2060 register struct validate *v;
2061 register int (*action)();
2068 while (sq_get_data(sq, &argv)) {
2069 mr_trim_args(q->vcnt, argv);
2071 id = atoi(argv[i = q->vcnt - 2]);
2073 status = id_to_name(id, "USER", &argv[i]);
2075 status = id_to_name(-id, "STRING", &argv[i]);
2076 if (status && status != MR_NO_MATCH)
2079 for (i = 1; i < 8; i+=2) {
2080 id = atoi(argv[i+1]);
2081 if (!strcmp(argv[i], "LIST")) {
2082 status = id_to_name(id, "LIST", &argv[i+1]);
2083 } else if (!strcmp(argv[i], "USER")) {
2084 status = id_to_name(id, "USER", &argv[i+1]);
2085 } else if (!strcmp(argv[i], "KERBEROS")) {
2086 status = id_to_name(id, "STRING", &argv[i+1]);
2087 } else if (!strcmp(argv[i], "NONE")) {
2090 argv[i+1] = strsave("NONE");
2094 argv[i+1] = strsave("???");
2096 if (status && status != MR_NO_MATCH)
2101 (*action)(q->vcnt, argv, actarg);
2103 /* free saved data */
2104 for (i = 0; i < q->vcnt; i++)
2116 followup_gsha(q, sq, v, action, actarg, cl)
2117 register struct query *q;
2118 register struct save_queue *sq;
2119 register struct validate *v;
2120 register int (*action)();
2127 while (sq_get_data(sq, &argv)) {
2128 mr_trim_args(q->vcnt, argv);
2132 status = id_to_name(id, "USER", &argv[4]);
2134 status = id_to_name(-id, "STRING", &argv[4]);
2135 if (status && status != MR_NO_MATCH)
2139 if (!strcmp(argv[1], "LIST")) {
2140 status = id_to_name(id, "LIST", &argv[2]);
2141 } else if (!strcmp(argv[1], "USER")) {
2142 status = id_to_name(id, "USER", &argv[2]);
2143 } else if (!strcmp(argv[1], "KERBEROS")) {
2144 status = id_to_name(id, "STRING", &argv[2]);
2145 } else if (!strcmp(argv[1], "NONE")) {
2148 argv[2] = strsave("NONE");
2152 argv[2] = strsave("???");
2154 if (status && status != MR_NO_MATCH)
2158 (*action)(q->vcnt, argv, actarg);
2160 /* free saved data */
2161 for (i = 0; i < q->vcnt; i++)
2171 /* Special query routines */
2173 /* set_pobox - this does all of the real work.
2174 * argv = user_id, type, box
2175 * if type is POP, then box should be a machine, and its ID should be put in
2176 * pop_id. If type is SMTP, then box should be a string and its ID should
2177 * be put in box_id. If type is NONE, then box doesn't matter.
2180 int set_pobox(q, argv, cl)
2185 EXEC SQL BEGIN DECLARE SECTION;
2187 char *box, potype[9];
2188 EXEC SQL END DECLARE SECTION;
2192 user = *(int *)argv[0];
2194 EXEC SQL REPEATED SELECT pop_id, potype INTO :id, :potype FROM users
2195 WHERE users_id = :user;
2196 if (ingres_errno) return(mr_errcode);
2197 if (!strcmp(strtrim(potype), "POP"))
2198 set_pop_usage(id, -1);
2200 if (!strcmp(argv[1], "POP")) {
2201 status = name_to_id(box, "MACHINE", &id);
2202 if (status == MR_NO_MATCH)
2206 EXEC SQL REPEATED UPDATE users SET potype = 'POP', pop_id = :id
2207 WHERE users_id = :user;
2208 set_pop_usage(id, 1);
2209 } else if (!strcmp(argv[1], "SMTP")) {
2210 if (index(box, '/') || index(box, '|'))
2211 return(MR_BAD_CHAR);
2212 status = name_to_id(box, "STRING", &id);
2213 if (status == MR_NO_MATCH) {
2214 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
2215 WHERE name='strings_id';
2217 EXEC SQL REPEATED UPDATE numvalues SET value = :id
2218 WHERE name='strings_id';
2219 EXEC SQL INSERT INTO strings (string_id, string)
2223 EXEC SQL REPEATED UPDATE users SET potype='SMTP', box_id = :id
2224 WHERE users_id = :user;
2225 } else /* argv[1] == "NONE" */ {
2226 EXEC SQL REPEATED UPDATE users SET potype='NONE'
2227 WHERE users_id = :user;
2230 set_pobox_modtime(q, argv, cl);
2231 EXEC SQL REPEATED UPDATE tblstats SET updates = updates+1, modtime='now'
2232 WHERE table_name='users';
2233 if (ingres_errno) return(mr_errcode);
2238 /* get_list_info: passed a wildcard list name, returns lots of stuff about
2239 * each list. This is tricky: first build a queue of all requested
2240 * data. Rest of processing consists of fixing gid, ace_name, and modby.
2243 get_list_info(q, aargv, cl, action, actarg)
2244 register struct query *q;
2247 register int (*action)();
2250 char *argv[13], *malloc(), *realloc();
2251 EXEC SQL BEGIN DECLARE SECTION;
2252 char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
2253 char maillist[5], grouplist[5], gid_str[6], acl_name[256], desc[256];
2254 char modtime[27], modby[256], modwith[9];
2255 int id, rowcount, acl_id, hid, modby_id;
2257 EXEC SQL END DECLARE SECTION;
2258 int returned, status;
2259 struct save_queue *sq, *sq_create();
2261 returned = rowcount = 0;
2263 convert_wildcards(name);
2266 sprintf(qual,"name LIKE '%s' ESCAPE '*'",name);
2267 optimize_sql_stmt(qual);
2268 EXEC SQL DECLARE csr102 CURSOR FOR SELECT list_id FROM list
2270 EXEC SQL OPEN csr102;
2273 EXEC SQL FETCH csr102 INTO :id;
2274 if(sqlca.sqlcode!=0) break;
2275 sq_save_data(sq, id);
2278 EXEC SQL CLOSE csr102;
2280 if (ingres_errno) return(mr_errcode);
2282 return(MR_NO_MATCH);
2284 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
2285 argv[4] = maillist; argv[5] = grouplist; argv[6] = gid_str;
2286 argv[7] = acl_type; argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
2288 while (sq_get_data(sq, &id)) {
2292 EXEC SQL REPEATED SELECT name, CHAR(active), CHAR(publicflg),
2293 CHAR(hidden), hidden, CHAR(maillist), CHAR(grouplist), CHAR(gid),
2294 TRIM(acl_type), acl_id, description, CHAR(modtime), modby, modwith
2295 INTO :listname, :active, :public, :hidden, :hid, :maillist,
2296 :grouplist, :gid_str, :acl_type, :acl_id, :desc,
2297 :modtime, :modby_id, :modwith
2298 FROM list WHERE list_id = :id;
2300 if (ingres_errno) return(mr_errcode);
2302 if (atoi(gid_str) == -1)
2303 argv[6] = UNIQUE_GID;
2305 argv[8] = malloc(0);
2306 if (!strcmp(acl_type, "LIST")) {
2307 status = id_to_name(acl_id, "LIST", &argv[8]);
2308 } else if (!strcmp(acl_type, "USER")) {
2309 status = id_to_name(acl_id, "USER", &argv[8]);
2310 } else if (!strcmp(acl_type, "KERBEROS")) {
2311 status = id_to_name(acl_id, "STRING", &argv[8]);
2312 } else if (!strcmp(acl_type, "NONE")) {
2315 argv[8] = strsave("NONE");
2319 argv[8] = strsave("???");
2321 if (status && status != MR_NO_MATCH) return(status);
2323 argv[11] = malloc(0);
2325 status = id_to_name(modby_id, "USER", &argv[11]);
2327 status = id_to_name(-modby_id, "STRING", &argv[11]);
2328 if (status && status != MR_NO_MATCH) return(status);
2330 mr_trim_args(q->vcnt, argv);
2332 (*action)(q->vcnt, argv, actarg);
2338 if (ingres_errno) return(mr_errcode);
2339 return (MR_SUCCESS);
2343 /* Add_member_to_list: do list flattening as we go! MAXLISTDEPTH is
2344 * how many different ancestors a member is allowed to have.
2347 #define MAXLISTDEPTH 1024
2349 int add_member_to_list(q, argv, cl)
2354 EXEC SQL BEGIN DECLARE SECTION;
2355 int id, lid, mid, error, who, ref, rowcnt;
2356 char *mtype, dtype[9], *entity;
2357 EXEC SQL END DECLARE SECTION;
2358 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2359 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2361 char *dtypes[MAXLISTDEPTH];
2362 char *iargv[3], *buf;
2364 lid = *(int *)argv[0];
2366 mid = *(int *)argv[2];
2367 /* if the member is already a direct member of the list, punt */
2368 EXEC SQL REPEATED SELECT COUNT(list_id) INTO :rowcnt FROM imembers
2369 WHERE list_id = :lid AND member_id = :mid
2370 AND member_type = :mtype AND direct = 1;
2373 if (!strcasecmp(mtype, "STRING")) {
2375 status = id_to_name(mid, "STRING", &buf);
2376 if (status) return(status);
2377 if (index(buf, '/') || index(buf, '|')) {
2379 return(MR_BAD_CHAR);
2387 EXEC SQL DECLARE csr103 CURSOR FOR
2388 SELECT list_id, ref_count FROM imembers
2389 WHERE member_id = :lid AND member_type='LIST';
2390 EXEC SQL OPEN csr103;
2392 EXEC SQL FETCH csr103 INTO :id, :ref;
2393 if(sqlca.sqlcode != 0) break;
2395 ancestors[acount++] = id;
2396 if (acount >= MAXLISTDEPTH) break;
2398 EXEC SQL CLOSE csr103;
2399 if (ingres_errno) return(mr_errcode);
2400 if (acount >= MAXLISTDEPTH) {
2401 return(MR_INTERNAL);
2403 descendants[0] = mid;
2408 if (!strcmp(mtype, "LIST")) {
2409 EXEC SQL DECLARE csr104 CURSOR FOR
2410 SELECT member_id, member_type, ref_count
2412 WHERE list_id = :mid;
2413 EXEC SQL OPEN csr104;
2415 EXEC SQL FETCH csr104 INTO :id, :dtype, :ref;
2416 if(sqlca.sqlcode != 0) break;
2419 dtypes[dcount] = "LIST";
2422 dtypes[dcount] = "USER";
2425 dtypes[dcount] = "STRING";
2428 dtypes[dcount] = "KERBEROS";
2435 descendants[dcount++] = id;
2436 if (dcount >= MAXLISTDEPTH) {
2441 EXEC SQL CLOSE csr104;
2442 if (ingres_errno) return(mr_errcode);
2444 return(MR_INTERNAL);
2446 for (a = 0; a < acount; a++) {
2448 for (d = 0; d < dcount; d++) {
2449 mid = descendants[d];
2451 if (mid == lid && !strcmp(mtype, "LIST")) {
2452 return(MR_LISTLOOP);
2454 EXEC SQL REPEATED SELECT COUNT(ref_count) INTO :rowcnt
2456 WHERE list_id = :lid AND member_id = :mid
2457 AND member_type = :mtype;
2458 ref = aref[a] * dref[d];
2460 if (a == 0 && d == 0) {
2461 EXEC SQL UPDATE imembers
2462 SET ref_count = ref_count+:ref, direct=1
2463 WHERE list_id = :lid AND member_id = :mid
2464 AND member_type = :mtype;
2466 EXEC SQL UPDATE imembers
2467 SET ref_count = ref_count+:ref
2468 WHERE list_id = :lid AND member_id = :mid
2469 AND member_type = :mtype;
2472 incremental_clear_before();
2473 if (a == 0 && d == 0) {
2474 EXEC SQL INSERT INTO imembers
2475 (list_id, member_id, direct, member_type, ref_count)
2476 VALUES (:lid, :mid, 1, :mtype, 1);
2478 EXEC SQL INSERT INTO imembers
2479 (list_id, member_id, member_type, ref_count)
2480 VALUES (:lid, :mid, :mtype, 1);
2482 iargv[0] = (char *)lid;
2484 iargv[2] = (char *)mid;
2485 incremental_after("members", 0, iargv);
2489 lid = *(int *)argv[0];
2490 entity = cl->entity;
2491 who = cl->client_id;
2492 EXEC SQL REPEATED UPDATE list
2493 SET modtime='now', modby = :who, modwith = :entity
2494 WHERE list_id = :lid;
2495 if (ingres_errno) return(mr_errcode);
2500 /* Delete_member_from_list: do list flattening as we go!
2503 int delete_member_from_list(q, argv, cl)
2508 EXEC SQL BEGIN DECLARE SECTION;
2509 int id, lid, mid, cnt, error, who, ref;
2510 char *mtype, dtype[9], *entity;
2511 EXEC SQL END DECLARE SECTION;
2512 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2513 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2514 char *dtypes[MAXLISTDEPTH];
2517 lid = *(int *)argv[0];
2519 mid = *(int *)argv[2];
2520 /* if the member is not a direct member of the list, punt */
2521 EXEC SQL REPEATED SELECT COUNT(list_id) INTO :cnt FROM imembers
2522 WHERE list_id = :lid AND member_id = :mid
2523 AND member_type = :mtype AND direct = 1;
2524 if (ingres_errno) return(mr_errcode);
2526 return(MR_NO_MATCH);
2530 EXEC SQL DECLARE csr105 CURSOR FOR
2531 SELECT list_id, ref_count FROM imembers
2532 WHERE member_id = :lid AND member_type = 'LIST';
2533 EXEC SQL OPEN csr105;
2535 EXEC SQL FETCH csr105 INTO :id, :ref;
2536 if(sqlca.sqlcode!=0) break;
2538 ancestors[acount++] = id;
2539 if (acount >= MAXLISTDEPTH) break;
2541 EXEC SQL CLOSE csr105;
2544 if (acount >= MAXLISTDEPTH)
2545 return(MR_INTERNAL);
2546 descendants[0] = mid;
2551 if (!strcmp(mtype, "LIST")) {
2552 EXEC SQL DECLARE csr106 CURSOR FOR
2553 SELECT member_id, member_type, ref_count FROM imembers
2554 WHERE list_id = :mid;
2555 EXEC SQL OPEN csr106;
2557 EXEC SQL FETCH csr106 INTO :id, :dtype, :ref;
2558 if(sqlca.sqlcode!=0) break;
2561 dtypes[dcount] = "LIST";
2564 dtypes[dcount] = "USER";
2567 dtypes[dcount] = "STRING";
2570 dtypes[dcount] = "KERBEROS";
2577 descendants[dcount++] = id;
2578 if (dcount >= MAXLISTDEPTH) break;
2580 EXEC SQL CLOSE csr106;
2584 return(MR_INTERNAL);
2586 for (a = 0; a < acount; a++) {
2588 for (d = 0; d < dcount; d++) {
2589 mid = descendants[d];
2591 if (mid == lid && !strcmp(mtype, "LIST")) {
2592 return(MR_LISTLOOP);
2594 EXEC SQL REPEATED SELECT ref_count INTO :cnt FROM imembers
2595 WHERE list_id = :lid AND member_id = :mid AND member_type = :mtype;
2596 ref = aref[a] * dref[d];
2598 iargv[0] = (char *)lid;
2600 iargv[2] = (char *)mid;
2601 incremental_before("members", 0, iargv);
2602 EXEC SQL DELETE FROM imembers
2603 WHERE list_id = :lid AND member_id = :mid
2604 AND member_type= :mtype;
2605 incremental_clear_after();
2606 } else if (a == 0 && d == 0) {
2607 EXEC SQL UPDATE imembers
2608 SET ref_count = ref_count - :ref, direct = 0
2609 WHERE list_id = :lid AND member_id = :mid
2610 AND member_type = :mtype;
2612 EXEC SQL UPDATE imembers
2613 SET ref_count = ref_count - :ref
2614 WHERE list_id = :lid AND member_id = :mid
2615 AND member_type = :mtype;
2619 lid = *(int *)argv[0];
2620 entity = cl->entity;
2621 who = cl->client_id;
2622 EXEC SQL UPDATE list SET modtime = 'now', modby = :who, modwith = :entity
2623 WHERE list_id = :lid;
2624 if (ingres_errno) return(mr_errcode);
2629 /* get_ace_use - given a type and a name, return a type and a name.
2630 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2631 * and argv[1] will contain the ID of the entity in question. The R*
2632 * types mean to recursively look at every containing list, not just
2633 * when the object in question is a direct member. On return, the
2634 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2637 int get_ace_use(q, argv, cl, action, actarg)
2645 EXEC SQL BEGIN DECLARE SECTION;
2647 int aid, listid, id;
2648 EXEC SQL END DECLARE SECTION;
2649 struct save_queue *sq, *sq_create();
2652 aid = *(int *)argv[1];
2653 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2654 !strcmp(atype, "KERBEROS")) {
2655 return(get_ace_internal(atype, aid, action, actarg));
2659 if (!strcmp(atype, "RLIST")) {
2660 sq_save_data(sq, aid);
2661 /* get all the list_id's of containing lists */
2662 EXEC SQL DECLARE csr107 CURSOR FOR
2663 SELECT list_id FROM imembers
2664 WHERE member_type='LIST' AND member_id = :aid;
2665 EXEC SQL OPEN csr107;
2667 EXEC SQL FETCH csr107 INTO :listid;
2668 if(sqlca.sqlcode != 0) break;
2669 sq_save_unique_data(sq, listid);
2671 EXEC SQL CLOSE csr107;
2672 /* now process each one */
2673 while (sq_get_data(sq, &id)) {
2674 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2679 if (!strcmp(atype, "RUSER")) {
2680 EXEC SQL DECLARE csr108 CURSOR FOR
2681 SELECT list_id FROM imembers
2682 WHERE member_type='USER' AND member_id = :aid;
2683 EXEC SQL OPEN csr108;
2685 EXEC SQL FETCH csr108 INTO :listid;
2686 if(sqlca.sqlcode != 0) break;
2687 sq_save_data(sq, listid);
2689 EXEC SQL CLOSE csr108;
2690 /* now process each one */
2691 while (sq_get_data(sq, &id)) {
2692 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2695 if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2699 if (!strcmp(atype, "RKERBERO")) {
2700 EXEC SQL DECLARE csr109 CURSOR FOR
2701 SELECT list_id FROM imembers
2702 WHERE member_type='KERBEROS' AND member_id = :aid;
2703 EXEC SQL OPEN csr109;
2705 EXEC SQL FETCH csr109 INTO :listid;
2706 if(sqlca.sqlcode != 0) break;
2707 sq_save_data(sq, listid);
2709 EXEC SQL CLOSE csr109;
2710 /* now process each one */
2711 while (sq_get_data(sq, &id)) {
2712 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2715 if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2720 if (ingres_errno) return(mr_errcode);
2721 if (!found) return(MR_NO_MATCH);
2726 /* This looks up a single list or user for ace use. atype must be "USER"
2727 * or "LIST", and aid is the ID of the corresponding object. This is used
2728 * by get_ace_use above.
2731 get_ace_internal(atype, aid, action, actarg)
2732 EXEC SQL BEGIN DECLARE SECTION;
2735 EXEC SQL END DECLARE SECTION;
2741 EXEC SQL BEGIN DECLARE SECTION;
2743 EXEC SQL END DECLARE SECTION;
2746 if (!strcmp(atype, "LIST")) {
2747 rargv[0] = "FILESYS";
2748 EXEC SQL DECLARE csr110 CURSOR FOR
2749 SELECT label FROM filesys
2750 WHERE owners = :aid;
2751 EXEC SQL OPEN csr110;
2753 EXEC SQL FETCH csr110 INTO :name;
2754 if(sqlca.sqlcode != 0) break;
2755 (*action)(2, rargv, actarg);
2758 EXEC SQL CLOSE csr110;
2761 EXEC SQL DECLARE csr111 CURSOR FOR
2762 SELECT capability FROM capacls
2763 WHERE list_id = :aid ;
2764 EXEC SQL OPEN csr111;
2766 EXEC SQL FETCH csr111 INTO :name ;
2767 if(sqlca.sqlcode != 0) break;
2768 (*action)(2, rargv, actarg);
2771 EXEC SQL CLOSE csr111;
2772 } else if (!strcmp(atype, "USER")) {
2773 rargv[0] = "FILESYS";
2774 EXEC SQL DECLARE csr112 CURSOR FOR
2775 SELECT label FROM filesys
2777 EXEC SQL OPEN csr112;
2779 EXEC SQL FETCH csr112 INTO :name ;
2780 if(sqlca.sqlcode != 0) break;
2781 (*action)(2, rargv, actarg);
2784 EXEC SQL CLOSE csr112;
2788 EXEC SQL DECLARE csr113 CURSOR FOR
2789 SELECT name FROM list
2790 WHERE acl_type = :atype AND acl_id = :aid;
2791 EXEC SQL OPEN csr113;
2793 EXEC SQL FETCH csr113 INTO :name;
2794 if(sqlca.sqlcode != 0) break;
2795 (*action)(2, rargv, actarg);
2798 EXEC SQL CLOSE csr113;
2800 rargv[0] = "SERVICE";
2801 EXEC SQL DECLARE csr114 CURSOR FOR
2802 SELECT name FROM servers
2803 WHERE acl_type = :atype AND acl_id = :aid;
2804 EXEC SQL OPEN csr114;
2806 EXEC SQL FETCH csr114 INTO :name;
2807 if(sqlca.sqlcode != 0) break;
2808 (*action)(2, rargv, actarg);
2811 EXEC SQL CLOSE csr114;
2813 rargv[0] = "HOSTACCESS";
2814 EXEC SQL DECLARE csr115 CURSOR FOR
2815 SELECT name FROM machine m, hostaccess ha
2816 WHERE m.mach_id = ha.mach_id AND ha.acl_type = :atype
2817 AND ha.acl_id = :aid;
2818 EXEC SQL OPEN csr115;
2820 EXEC SQL FETCH csr115 INTO :name;
2821 if(sqlca.sqlcode != 0) break;
2822 (*action)(2, rargv, actarg);
2825 EXEC SQL CLOSE csr115;
2827 rargv[0] = "ZEPHYR";
2828 EXEC SQL DECLARE csr116 CURSOR FOR
2829 SELECT class FROM zephyr z
2830 WHERE z.xmt_type = :atype AND z.xmt_id = :aid
2831 OR z.sub_type = :atype AND z.sub_id = :aid
2832 OR z.iws_type = :atype AND z.iws_id = :aid
2833 OR z.iui_type = :atype AND z.iui_id = :aid;
2834 EXEC SQL OPEN csr116;
2836 EXEC SQL FETCH csr116 INTO :name;
2837 if(sqlca.sqlcode != 0) break;
2838 (*action)(2, rargv, actarg);
2841 EXEC SQL CLOSE csr116;
2843 if (!found) return(MR_NO_MATCH);
2848 /* get_lists_of_member - given a type and a name, return the name and flags
2849 * of all of the lists of the given member. The member_type is one of
2850 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2851 * and argv[1] will contain the ID of the entity in question. The R*
2852 * types mean to recursively look at every containing list, not just
2853 * when the object in question is a direct member.
2856 int get_lists_of_member(q, argv, cl, action, actarg)
2863 int found = 0, direct = 1;
2865 EXEC SQL BEGIN DECLARE SECTION;
2867 int aid, listid, id;
2868 char name[33], active[5], public[5], hidden[5], maillist[5], grouplist[5];
2869 EXEC SQL END DECLARE SECTION;
2872 aid = *(int *)argv[1];
2873 if (!strcmp(atype, "RLIST")) {
2877 if (!strcmp(atype, "RUSER")) {
2881 if (!strcmp(atype, "RSTRING")) {
2885 if (!strcmp(atype, "RKERBEROS")) {
2894 rargv[4] = maillist;
2895 rargv[5] = grouplist;
2897 EXEC SQL DECLARE csr117a CURSOR FOR
2898 SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2899 CHAR(l.maillist), CHAR(l.grouplist)
2900 FROM list l, imembers im
2901 WHERE l.list_id = im.list_id AND im.direct = 1
2902 AND im.member_type = :atype AND im.member_id = :aid;
2903 EXEC SQL OPEN csr117a;
2905 EXEC SQL FETCH csr117a
2906 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2907 if(sqlca.sqlcode != 0) break;
2908 (*action)(6, rargv, actarg);
2911 EXEC SQL CLOSE csr117a;
2913 EXEC SQL DECLARE csr117b CURSOR FOR
2914 SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2915 CHAR(l.maillist), CHAR(l.grouplist)
2916 FROM list l, imembers im
2917 WHERE l.list_id = im.list_id
2918 AND im.member_type = :atype AND im.member_id = :aid;
2919 EXEC SQL OPEN csr117b;
2921 EXEC SQL FETCH csr117b
2922 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2923 if(sqlca.sqlcode != 0) break;
2924 (*action)(6, rargv, actarg);
2927 EXEC SQL CLOSE csr117b;
2930 if (ingres_errno) return(mr_errcode);
2931 if (!found) return(MR_NO_MATCH);
2936 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2937 * the five flags associated with each list. It will return the name of
2938 * each list that meets the quailifications. It does this by building a
2939 * where clause based on the arguments, then doing a retrieve.
2942 static char *lflags[5] = { "active", "publicflg", "hidden", "maillist", "grouplist" };
2944 int qualified_get_lists(q, argv, cl, action, actarg)
2951 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2952 "l", "name", lflags));
2956 /* get_members_of_list - this gets only direct members */
2958 get_members_of_list(q, argv, cl, action, actarg)
2965 return(gmol_internal(q, argv, cl, action, actarg, 1));
2968 /* get_end_members_of_list - this gets direct or indirect members */
2970 get_end_members_of_list(q, argv, cl, action, actarg)
2977 return(gmol_internal(q, argv, cl, action, actarg, 0));
2980 /** gmol_internal - optimized query for retrieval of list members
2981 ** used by both get_members_of_list and get_end_members_of_list
2984 ** argv[0] - list_id
2987 ** - retrieve USER members, then LIST members, then STRING members
2990 gmol_internal(q, argv, cl, action, actarg, flag)
2998 EXEC SQL BEGIN DECLARE SECTION;
2999 int list_id, member_id, direct;
3000 char member_name[129], member_type[9];
3001 EXEC SQL END DECLARE SECTION;
3004 struct save_queue *sq;
3006 /* true/false flag indicates whether to display only direct members. */
3012 list_id = *(int *)argv[0];
3016 EXEC SQL DECLARE csr118 CURSOR FOR
3017 SELECT member_type, member_id FROM imembers
3018 WHERE list_id = :list_id AND direct > :direct;
3019 EXEC SQL OPEN csr118;
3021 EXEC SQL FETCH csr118 INTO :member_type, :member_id;
3022 if (sqlca.sqlcode != 0) break;
3025 sq_save_data(sq, ((int)member_type[0] << 24) | (member_id & 0xffffff));
3027 EXEC SQL CLOSE csr118;
3029 if (members <= 49) {
3030 targv[1] = malloc(0);
3031 while (sq_remove_data(sq, &member_id)) {
3032 switch (member_id >> 24) {
3035 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
3036 (*action)(2, targv, actarg);
3040 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
3041 (*action)(2, targv, actarg);
3044 targv[0] = "STRING";
3045 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
3046 (*action)(2, targv, actarg);
3049 targv[0] = "KERBEROS";
3050 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
3051 (*action)(2, targv, actarg);
3055 return(MR_INTERNAL);
3064 targv[1] = member_name;
3066 EXEC SQL DECLARE csr119 CURSOR FOR
3067 SELECT u.login FROM users u, imembers im
3068 WHERE im.list_id = :list_id AND im.member_type = 'USER'
3069 AND im.member_id = u.users_id AND im.direct > :direct
3071 EXEC SQL OPEN csr119;
3073 EXEC SQL FETCH csr119 INTO :member_name;
3074 if(sqlca.sqlcode != 0) break;
3075 (*action)(2, targv, actarg);
3077 EXEC SQL CLOSE csr119;
3078 if (ingres_errno) return(mr_errcode);
3081 EXEC SQL DECLARE csr120 CURSOR FOR
3082 SELECT l.name FROM list l, imembers im
3083 WHERE im.list_id = :list_id AND im.member_type='LIST'
3084 AND im.member_id = l.list_id AND im.direct > :direct
3086 EXEC SQL OPEN csr120;
3088 EXEC SQL FETCH csr120 INTO :member_name;
3089 if(sqlca.sqlcode != 0) break;
3090 (*action)(2, targv, actarg);
3092 EXEC SQL CLOSE csr120;
3093 if (ingres_errno) return(mr_errcode);
3095 targv[0] = "STRING";
3096 EXEC SQL DECLARE csr121 CURSOR FOR
3097 SELECT CHAR(str.string) FROM strings str, imembers im
3098 WHERE im.list_id = :list_id AND im.member_type='STRING'
3099 AND im.member_id = str.string_id AND im.direct > :direct
3101 EXEC SQL OPEN csr121;
3103 EXEC SQL FETCH csr121 INTO :member_name;
3104 if(sqlca.sqlcode != 0) break;
3105 (*action)(2, targv, actarg);
3107 EXEC SQL CLOSE csr121;
3108 if (ingres_errno) return(mr_errcode);
3110 targv[0] = "KERBEROS";
3111 EXEC SQL DECLARE csr122 CURSOR FOR
3112 SELECT CHAR(str.string) FROM strings str, imembers im
3113 WHERE im.list_id = :list_id AND im.member_type='KERBEROS'
3114 AND im.member_id = str.string_id
3115 AND im.direct > :direct
3117 EXEC SQL OPEN csr122;
3119 EXEC SQL FETCH csr122 INTO :member_name;
3120 if(sqlca.sqlcode != 0) break;
3121 (*action)(2, targv, actarg);
3123 EXEC SQL CLOSE csr122;
3124 if (ingres_errno) return(mr_errcode);
3130 /* count_members_of_list: this is a simple query, but it cannot be done
3131 * through the dispatch table.
3134 int count_members_of_list(q, argv, cl, action, actarg)
3141 EXEC SQL BEGIN DECLARE SECTION;
3143 EXEC SQL END DECLARE SECTION;
3144 char *rargv[1], countbuf[5];
3146 list = *(int *)argv[0];
3147 rargv[0] = countbuf;
3148 EXEC SQL REPEATED SELECT count (*) INTO :ct FROM imembers
3149 WHERE list_id = :list AND direct=1;
3150 if (ingres_errno) return(mr_errcode);
3151 sprintf(countbuf, "%d", ct);
3152 (*action)(1, rargv, actarg);
3157 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
3158 * the three flags associated with each service. It will return the name of
3159 * each service that meets the quailifications. It does this by building a
3160 * where clause based on the arguments, then doing a retrieve.
3163 static char *sflags[3] = { "enable", "inprogress", "harderror" };
3165 int qualified_get_server(q, argv, cl, action, actarg)
3172 return(qualified_get(q, argv, action, actarg, "s.name != ''",
3173 "s", "name", sflags));
3177 /* generic qualified get routine, used by qualified_get_lists,
3178 * qualified_get_server, and qualified_get_serverhost.
3180 * start - a simple where clause, must not be empty
3181 * range - the name of the range variable
3182 * field - the field to return
3183 * flags - an array of strings, names of the flag variables
3186 int qualified_get(q, argv, action, actarg, start, range, field, flags)
3196 char name[33], qual[256];
3198 char *rargv[1], buf[32];
3200 strcpy(qual, start);
3201 for (i = 0; i < q->argc; i++) {
3202 if (!strcmp(argv[i], "TRUE")) {
3203 sprintf(buf, " AND %s.%s != 0", range, flags[i]);
3204 (void) strcat(qual, buf);
3205 } else if (!strcmp(argv[i], "FALSE")) {
3206 sprintf(buf, " AND %s.%s = 0", range, flags[i]);
3207 (void) strcat(qual, buf);
3211 rargv[0] = SQLDA->sqlvar[0].sqldata;
3212 sprintf(stmt_buf,"SELECT CHAR(%s.%s) FROM %s %s WHERE %s",range,field,q->rtable,range,qual);
3213 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3215 return(MR_INTERNAL);
3216 EXEC SQL DECLARE csr123 CURSOR FOR stmt;
3217 EXEC SQL OPEN csr123;
3219 EXEC SQL FETCH csr123 USING DESCRIPTOR :SQLDA;
3220 if(sqlca.sqlcode != 0) break;
3222 (*action)(1, rargv, actarg);
3224 EXEC SQL CLOSE csr123;
3225 if (ingres_errno) return(mr_errcode);
3227 return(MR_NO_MATCH);
3232 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
3233 * the five flags associated with each serverhost. It will return the name of
3234 * each service and host that meets the quailifications. It does this by
3235 * building a where clause based on the arguments, then doing a retrieve.
3238 static char *shflags[6] = { "service", "enable", "override", "success",
3239 "inprogress", "hosterror" };
3241 int qualified_get_serverhost(q, argv, cl, action, actarg)
3248 EXEC SQL BEGIN DECLARE SECTION;
3249 char sname[33], mname[33], qual[256];
3250 EXEC SQL END DECLARE SECTION;
3251 char *rargv[2], buf[32];
3254 sprintf(qual, "m.mach_id = sh.mach_id AND sh.service = uppercase('%s')",
3256 for (i = 1; i < q->argc; i++) {
3257 if (!strcmp(argv[i], "TRUE")) {
3258 sprintf(buf, " AND sh.%s != 0", shflags[i]);
3260 } else if (!strcmp(argv[i], "FALSE")) {
3261 sprintf(buf, " AND sh.%s = 0", shflags[i]);
3268 EXEC SQL DECLARE csr124 CURSOR FOR
3269 SELECT sh.service, m.name FROM serverhosts sh, machine m
3271 EXEC SQL OPEN csr124;
3273 EXEC SQL FETCH csr124 INTO :sname, :mname;
3274 if(sqlca.sqlcode != 0) break;
3276 (*action)(2, rargv, actarg);
3278 EXEC SQL CLOSE csr124;
3280 if (ingres_errno) return(mr_errcode);
3282 return(MR_NO_MATCH);
3287 /* register_user - change user's login name and allocate a pobox, group,
3288 * filesystem, and quota for them. The user's status must start out as 0,
3289 * and is left as 2. Arguments are: user's UID, new login name, and user's
3290 * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY,
3291 * MR_FS_STAFF, MR_FS_MISC).
3294 register_user(q, argv, cl)
3299 EXEC SQL BEGIN DECLARE SECTION;
3300 char *login, dir[65], *entity, directory[129], machname[33];
3301 int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
3302 int size, alloc, pid, ostatus, nstatus, gidval, fsidval, npidval;
3303 static int m_id = 0, def_quota = 0;
3304 EXEC SQL END DECLARE SECTION;
3305 char buffer[256], *aargv[3];
3307 entity = cl->entity;
3308 who = cl->client_id;
3310 uid = atoi(argv[0]);
3312 utype = atoi(argv[2]);
3315 EXEC SQL REPEATED SELECT users_id, status INTO :users_id, :ostatus
3317 WHERE uid = :uid AND (status=0 OR status=5 OR status=6);
3319 if (sqlca.sqlerrd[2] == 0)
3320 return(MR_NO_MATCH);
3321 if (sqlca.sqlerrd[2] > 1)
3322 return(MR_NOT_UNIQUE);
3324 /* check new login name */
3325 EXEC SQL REPEATED SELECT COUNT(login) INTO :rowcount FROM users
3326 WHERE login = LEFT(:login,SIZE(login)) AND users_id != :users_id;
3327 if (ingres_errno) return(mr_errcode);
3328 if (rowcount > 0) return(MR_IN_USE);
3329 EXEC SQL REPEATED SELECT COUNT(name) INTO :rowcount FROM list
3330 WHERE name = LEFT(:login,SIZE(name));
3331 if (ingres_errno) return(mr_errcode);
3332 if (rowcount > 0) return(MR_IN_USE);
3333 EXEC SQL REPEATED SELECT COUNT(label) INTO :rowcount FROM filesys
3334 WHERE label = LEFT(:login,SIZE(label));
3335 if (ingres_errno) return(mr_errcode);
3336 if (rowcount > 0) return(MR_IN_USE);
3337 com_err(whoami, 0, "login name OK");
3339 /* choose place for pobox, put in mid */
3340 EXEC SQL DECLARE csr130 CURSOR FOR
3341 SELECT sh.mach_id, m.name FROM serverhosts sh, machine m
3342 WHERE sh.service='POP' AND sh.mach_id=m.mach_id
3343 AND sh.value2 - sh.value1 =
3344 (SELECT MAX(value2 - value1) FROM serverhosts
3345 WHERE service = 'POP');
3346 EXEC SQL OPEN csr130;
3347 EXEC SQL FETCH csr130 INTO :mid, :machname;
3348 if (sqlca.sqlerrd[2] == 0) {
3349 EXEC SQL CLOSE csr130;
3350 if (ingres_errno) return(mr_errcode);
3351 return(MR_NO_POBOX);
3353 EXEC SQL CLOSE csr130;
3354 if (ingres_errno) return(mr_errcode);
3357 /* change login name, set pobox */
3358 sprintf(buffer, "u.users_id = %d", users_id);
3359 incremental_before("users", buffer, 0);
3361 if (ostatus == 5 || ostatus == 6)
3363 EXEC SQL REPEATED UPDATE users SET login = :login, status = :nstatus,
3364 modtime='now', modby = :who, modwith = :entity, potype='POP',
3365 pop_id = :mid, pmodtime='now', pmodby = :who, pmodwith = :entity
3366 WHERE users_id = :users_id;
3368 if (ingres_errno) return(mr_errcode);
3369 if (sqlca.sqlerrd[2] != 1)
3370 return(MR_INTERNAL);
3371 set_pop_usage(mid, 1);
3372 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
3374 incremental_after("users", buffer, 0);
3376 /* create group list */
3377 if (set_next_object_id("gid", "list", 1))
3379 if (set_next_object_id("list_id", "list", 0))
3381 EXEC SQL REPEATED SELECT value INTO :list_id FROM numvalues
3382 WHERE name='list_id';
3383 if (ingres_errno) return(mr_errcode);
3384 if (sqlca.sqlerrd[2] != 1)
3385 return(MR_INTERNAL);
3386 incremental_clear_before();
3387 EXEC SQL SELECT value INTO :gidval FROM numvalues WHERE name = 'gid';
3388 EXEC SQL REPEATED INSERT INTO list
3389 (name, list_id, active, publicflg, hidden, maillist, grouplist,
3390 gid, description, acl_type, acl_id,
3391 modtime, modby, modwith)
3392 VALUES (:login, :list_id, 1, 0, 0, 0, 1,
3393 :gidval, 'User Group', 'USER', :users_id,
3394 'now', :who, :entity);
3395 if (ingres_errno) return(mr_errcode);
3396 if (sqlca.sqlerrd[2] != 1)
3397 return(MR_INTERNAL);
3398 sprintf(buffer, "l.list_id = %d", list_id);
3399 incremental_after("list", buffer, 0);
3400 aargv[0] = (char *) list_id;
3402 aargv[2] = (char *) users_id;
3403 incremental_clear_before();
3404 EXEC SQL REPEATED INSERT INTO imembers
3405 (list_id, member_type, member_id, ref_count, direct)
3406 VALUES (:list_id, 'USER', :users_id, 1, 1);
3407 if (ingres_errno) return(mr_errcode);
3408 if (sqlca.sqlerrd[2] != 1)
3409 return(MR_INTERNAL);
3410 incremental_after("members", 0, aargv);
3413 /* Cell Name (I know, it shouldn't be hard coded...) */
3414 strcpy(machname, "ATHENA.MIT.EDU");
3415 EXEC SQL SELECT mach_id INTO :m_id FROM machine
3416 WHERE name = :machname;
3419 /* create filesystem */
3420 if (set_next_object_id("filsys_id", "filesys", 0))
3422 incremental_clear_before();
3423 if (islower(login[0]) && islower(login[1])) {
3424 sprintf(directory, "/afs/athena.mit.edu/user/%c/%c/%s",
3425 login[0], login[1], login);
3427 sprintf(directory, "/afs/athena.mit.edu/user/other/%s", login);
3430 EXEC SQL SELECT value INTO :fsidval FROM numvalues
3431 WHERE numvalues.name='filsys_id';
3432 EXEC SQL REPEATED INSERT INTO filesys
3433 (filsys_id, phys_id, label, type, mach_id, name,
3434 mount, access, comments, owner, owners, createflg,
3435 lockertype, modtime, modby, modwith)
3437 (:fsidval, 0, :login, 'AFS', :m_id, :directory,
3438 '/mit/'+:login, 'w', 'User Locker', :users_id, :list_id, 1,
3439 'HOMEDIR', 'now', :who, :entity);
3441 if (ingres_errno) return(mr_errcode);
3442 if (sqlca.sqlerrd[2] != 1)
3443 return(MR_INTERNAL);
3444 sprintf(buffer,"fs.filsys_id = %d",fsidval);
3445 incremental_after("filesys", buffer, 0);
3448 if (def_quota == 0) {
3449 EXEC SQL REPEATED SELECT value INTO :def_quota FROM numvalues
3450 WHERE name='def_quota';
3451 if (ingres_errno) return(mr_errcode);
3452 if (sqlca.sqlerrd[2] != 1)
3453 return(MR_NO_QUOTA);
3456 incremental_clear_before();
3457 EXEC SQL REPEATED INSERT INTO quota
3458 (entity_id, filsys_id, type, quota, phys_id, modtime, modby, modwith)
3460 (0, :fsidval, 'ANY', :def_quota, 0, 'now', :who, :entity);
3461 if (ingres_errno) return(mr_errcode);
3462 if (sqlca.sqlerrd[2] != 1)
3463 return(MR_INTERNAL);
3467 sprintf(buffer, "q.entity_id = 0 and q.filsys_id = %d and q.type = 'ANY'", fsidval);
3468 incremental_after("quota", buffer, aargv);
3469 com_err(whoami, 0, "quota of %d assigned", def_quota);
3470 if (ingres_errno) return(mr_errcode);
3472 cache_entry(login, "USER", users_id);
3474 EXEC SQL REPEATED UPDATE tblstats SET updates=updates+1, modtime='now'
3475 WHERE table_name='users';
3476 EXEC SQL REPEATED UPDATE tblstats SET appends=appends+1, modtime='now'
3477 WHERE table_name='list' OR table_name='filesys' OR table_name='quota';
3478 if (ingres_errno) return(mr_errcode);
3484 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
3488 ** delta (will be +/- 1)
3491 ** - incr/decr value field in serverhosts table for pop/mach_id
3495 static int set_pop_usage(id, cnt)
3496 EXEC SQL BEGIN DECLARE SECTION;
3499 EXEC SQL END DECLARE SECTION;
3501 EXEC SQL REPEATED UPDATE serverhosts SET value1 = value1 + :cnt
3502 WHERE serverhosts.service = 'POP' AND serverhosts.mach_id = :id;
3504 if (ingres_errno) return(mr_errcode);
3508 int _sdl_followup(q, argv, cl)
3517 EXEC SQL set printqry;
3519 EXEC SQL set noprintqry;
3526 /* Validation Routines */
3528 validate_row(q, argv, v)
3529 register struct query *q;
3531 register struct validate *v;
3533 EXEC SQL BEGIN DECLARE SECTION;
3537 EXEC SQL END DECLARE SECTION;
3539 /* build where clause */
3540 build_qual(v->qual, v->argc, argv, qual);
3542 if (log_flags & LOG_VALID)
3543 /* tell the logfile what we're doing */
3544 com_err(whoami, 0, "validating row: %s", qual);
3546 /* look for the record */
3547 sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",q->rtable,qual);
3548 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3550 return(MR_INTERNAL);
3551 EXEC SQL DECLARE csr126 CURSOR FOR stmt;
3552 EXEC SQL OPEN csr126;
3553 EXEC SQL FETCH csr126 USING DESCRIPTOR :SQLDA;
3554 EXEC SQL CLOSE csr126;
3555 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3557 if (ingres_errno) return(mr_errcode);
3558 if (rowcount == 0) return(MR_NO_MATCH);
3559 if (rowcount > 1) return(MR_NOT_UNIQUE);
3563 validate_fields(q, argv, vo, n)
3565 register char *argv[];
3566 register struct valobj *vo;
3569 register int status;
3574 if (log_flags & LOG_VALID)
3575 com_err(whoami, 0, "validating %s in %s: %s",
3576 vo->namefield, vo->table, argv[vo->index]);
3577 status = validate_name(argv, vo);
3581 if (log_flags & LOG_VALID)
3582 com_err(whoami, 0, "validating %s in %s: %s",
3583 vo->idfield, vo->table, argv[vo->index]);
3584 status = validate_id(q, argv, vo);
3588 if (log_flags & LOG_VALID)
3589 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
3590 status = validate_date(argv, vo);
3594 if (log_flags & LOG_VALID)
3595 com_err(whoami, 0, "validating %s type: %s",
3596 vo->table, argv[vo->index]);
3597 status = validate_type(argv, vo);
3601 if (log_flags & LOG_VALID)
3602 com_err(whoami, 0, "validating typed data (%s): %s",
3603 argv[vo->index - 1], argv[vo->index]);
3604 status = validate_typedata(q, argv, vo);
3608 if (log_flags & LOG_VALID)
3609 com_err(whoami, 0, "validating rename %s in %s",
3610 argv[vo->index], vo->table);
3611 status = validate_rename(argv, vo);
3615 if (log_flags & LOG_VALID)
3616 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
3617 status = validate_chars(argv[vo->index]);
3625 status = lock_table(vo);
3629 status = convert_wildcards(argv[vo->index]);
3633 status = convert_wildcards_uppercase(argv[vo->index]);
3638 if (status != MR_EXISTS) return(status);
3642 if (ingres_errno) return(mr_errcode);
3647 /* validate_chars: verify that there are no illegal characters in
3648 * the string. Legal characters are printing chars other than
3649 * ", *, ?, \, [ and ].
3651 static int illegalchars[] = {
3652 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
3653 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
3654 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
3655 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
3656 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
3657 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
3658 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
3659 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
3660 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3661 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3662 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3663 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3664 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3665 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3666 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3667 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3674 if (illegalchars[*s++])
3675 return(MR_BAD_CHAR);
3680 validate_id(q, argv, vo)
3683 register struct valobj *vo;
3685 EXEC SQL BEGIN DECLARE SECTION;
3686 char *name, *tbl, *namefield, *idfield;
3688 EXEC SQL END DECLARE SECTION;
3692 name = argv[vo->index];
3694 namefield = vo->namefield;
3695 idfield = vo->idfield;
3697 if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
3698 !strcmp(tbl, "machine") ||
3699 !strcmp(tbl, "filesys") ||
3700 !strcmp(tbl, "list") ||
3701 !strcmp(tbl, "cluster") ||
3702 !strcmp(tbl, "strings")) {
3703 if (!strcmp(tbl, "machine"))
3704 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3705 status = name_to_id(name, tbl, &id);
3707 *(int *)argv[vo->index] = id;
3709 } else if (status == MR_NO_MATCH && !strcmp(tbl, "strings") &&
3710 (q->type == APPEND || q->type == UPDATE)) {
3711 EXEC SQL SELECT value INTO :id FROM numvalues
3712 WHERE name = 'strings_id';
3714 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3715 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3716 cache_entry(name, "STRING", id);
3717 *(int *)argv[vo->index] = id;
3719 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
3725 if (!strcmp(namefield, "uid")) {
3726 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = %s",idfield,tbl,namefield,name);
3728 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",idfield,tbl,namefield,name);
3730 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3732 return(MR_INTERNAL);
3733 EXEC SQL DECLARE csr127 CURSOR FOR stmt;
3734 EXEC SQL OPEN csr127;
3736 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3737 if(sqlca.sqlcode == 0) {
3739 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3740 if(sqlca.sqlcode == 0) rowcount++;
3742 EXEC SQL CLOSE csr127;
3746 if (rowcount != 1) return(vo->error);
3747 bcopy(SQLDA->sqlvar[0].sqldata,argv[vo->index],sizeof(int));
3751 validate_name(argv, vo)
3753 register struct valobj *vo;
3755 EXEC SQL BEGIN DECLARE SECTION;
3756 char *name, *tbl, *namefield;
3758 EXEC SQL END DECLARE SECTION;
3761 name = argv[vo->index];
3763 namefield = vo->namefield;
3764 if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
3765 for (c = name; *c; c++)
3769 sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
3770 tbl,tbl,namefield,name);
3771 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3773 return(MR_INTERNAL);
3774 EXEC SQL DECLARE csr128 CURSOR FOR stmt;
3775 EXEC SQL OPEN csr128;
3776 EXEC SQL FETCH csr128 USING DESCRIPTOR :SQLDA;
3777 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3778 EXEC SQL CLOSE csr128;
3780 if (ingres_errno) return(mr_errcode);
3781 return ((rowcount == 1) ? MR_EXISTS : vo->error);
3784 validate_date(argv, vo)
3788 EXEC SQL BEGIN DECLARE SECTION;
3792 EXEC SQL END DECLARE SECTION;
3794 idate = argv[vo->index];
3795 EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
3797 if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
3802 validate_rename(argv, vo)
3806 EXEC SQL BEGIN DECLARE SECTION;
3807 char *name, *tbl, *namefield, *idfield;
3809 EXEC SQL END DECLARE SECTION;
3813 c = name = argv[vo->index];
3815 if (illegalchars[*c++])
3816 return(MR_BAD_CHAR);
3818 /* minor kludge to upcasify machine names */
3819 if (!strcmp(tbl, "machine"))
3820 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3821 namefield = vo->namefield;
3822 idfield = vo->idfield;
3825 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3827 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = LEFT('%s',SIZE(%s))",
3828 namefield,tbl,namefield,name,namefield);
3829 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3831 return(MR_INTERNAL);
3832 EXEC SQL DECLARE csr129 CURSOR FOR stmt;
3833 EXEC SQL OPEN csr129;
3834 EXEC SQL FETCH csr129 USING DESCRIPTOR :SQLDA;
3835 if(sqlca.sqlcode == 0) id=1; else id=0;
3836 EXEC SQL CLOSE csr129;
3838 if (ingres_errno) return(mr_errcode);
3844 status = name_to_id(name, tbl, &id);
3845 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3852 validate_type(argv, vo)
3854 register struct valobj *vo;
3856 EXEC SQL BEGIN DECLARE SECTION;
3860 EXEC SQL END DECLARE SECTION;
3863 typename = vo->table;
3864 c = val = argv[vo->index];
3866 if (illegalchars[*c++])
3867 return(MR_BAD_CHAR);
3870 /* uppercase type fields */
3871 for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
3873 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
3874 WHERE name = :typename AND type='TYPE' AND trans = :val;
3875 if (ingres_errno) return(mr_errcode);
3876 return (cnt ? MR_EXISTS : vo->error);
3879 /* validate member or type-specific data field */
3881 validate_typedata(q, argv, vo)
3882 register struct query *q;
3883 register char *argv[];
3884 register struct valobj *vo;
3886 EXEC SQL BEGIN DECLARE SECTION;
3889 char data_type[129];
3891 EXEC SQL END DECLARE SECTION;
3896 /* get named object */
3897 name = argv[vo->index];
3899 /* get field type string (known to be at index-1) */
3900 field_type = argv[vo->index-1];
3902 /* get corresponding data type associated with field type name */
3903 EXEC SQL SELECT trans INTO :data_type FROM alias
3904 WHERE name = :field_type AND type='TYPEDATA';
3905 if (ingres_errno) return(mr_errcode);
3906 if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
3908 /* now retrieve the record id corresponding to the named object */
3909 if (index(data_type, ' '))
3910 *index(data_type, ' ') = 0;
3911 if (!strcmp(data_type, "user")) {
3913 status = name_to_id(name, data_type, &id);
3914 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3916 if (status) return(status);
3917 } else if (!strcmp(data_type, "list")) {
3919 status = name_to_id(name, data_type, &id);
3920 if (status && status == MR_NOT_UNIQUE)
3922 if (status == MR_NO_MATCH) {
3923 /* if idfield is non-zero, then if argv[0] matches the string
3924 * that we're trying to resolve, we should get the value of
3925 * numvalues.[idfield] for the id.
3927 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3928 set_next_object_id(q->validate->object_id, q->rtable, 0);
3930 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
3932 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
3935 } else if (status) return(status);
3936 } else if (!strcmp(data_type, "machine")) {
3938 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3939 status = name_to_id(name, data_type, &id);
3940 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3942 if (status) return(status);
3943 } else if (!strcmp(data_type, "string")) {
3945 status = name_to_id(name, data_type, &id);
3946 if (status && status == MR_NOT_UNIQUE)
3948 if (status == MR_NO_MATCH) {
3949 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3950 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
3952 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3953 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3954 cache_entry(name, "STRING", id);
3955 } else if (status) return(status);
3956 } else if (!strcmp(data_type, "none")) {
3962 /* now set value in argv */
3963 *(int *)argv[vo->index] = id;
3969 /* Lock the table named by the validation object */
3974 sprintf(stmt_buf,"UPDATE %s SET modtime='now' WHERE %s.%s = 0",
3975 vo->table,vo->table,vo->idfield);
3976 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
3977 if (ingres_errno) return(mr_errcode);
3978 if (sqlca.sqlerrd[2] != 1)
3985 /* Check the database at startup time. For now this just resets the
3986 * inprogress flags that the DCM uses.
3989 sanity_check_database()
3994 /* Dynamic SQL support routines */
3995 MR_SQLDA_T *mr_alloc_SQLDA()
3998 short *null_indicators;
4001 if((it=(MR_SQLDA_T *)malloc(sizeof(MR_SQLDA_T)))==NULL) {
4002 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
4006 if((null_indicators=(short *)calloc(QMAXARGS,sizeof(short)))==NULL) {
4007 com_err(whoami, MR_NO_MEM, "setting up SQLDA null indicators");
4011 for(j=0; j<QMAXARGS; j++) {
4012 if((it->sqlvar[j].sqldata=malloc(sizeof(short)+QMAXARGSIZE))==NULL) {
4013 com_err(whoami, MR_NO_MEM, "setting up SQLDA variables");
4016 it->sqlvar[j].sqllen=QMAXARGSIZE;
4017 it->sqlvar[j].sqlind=null_indicators+j;
4018 null_indicators[j]=0;
4025 /* Use this after FETCH USING DESCRIPTOR one or more
4026 * result columns may contain NULLs. This routine is
4027 * not currently needed, since db/schema creates all
4028 * columns with a NOT NULL WITH DEFAULT clause.
4030 * This is currently dead flesh, since no Moira columns
4031 * allow null values; all use default values.
4033 mr_fix_nulls_in_SQLDA(da)
4036 register IISQLVAR *var;
4040 for(j=0, var=da->sqlvar; j<da->sqld; j++, var++) {
4041 switch(var->sqltype) {
4042 case -IISQ_CHA_TYPE:
4046 case -IISQ_INT_TYPE:
4048 intp=(int *)var->sqldata;
4056 /* prefetch_value():
4057 * This routine fetches an appropriate value from the numvalues table.
4058 * It is a little hack to get around the fact that SQL doesn't let you
4059 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
4061 * It is called from the query table as (*v->pre_rtn)(q,Argv,cl) or
4062 * from within a setup_...() routine with the appropriate arguments.
4064 * Correct functioning of this routine may depend on the assumption
4065 * that this query is an APPEND.
4068 prefetch_value(q,argv,cl)
4073 EXEC SQL BEGIN DECLARE SECTION;
4074 char *name = q->validate->object_id;
4076 EXEC SQL END DECLARE SECTION;
4077 int status, limit, argc;
4079 /* set next object id, limiting it if necessary */
4080 if(!strcmp(name, "uid") || !strcmp(name, "gid"))
4081 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
4084 if((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
4087 /* fetch object id */
4088 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name=:name;
4089 if(ingres_errno) return(mr_errcode);
4090 if(sqlca.sqlerrd[2] != 1) return(MR_INTERNAL);
4092 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
4093 sprintf(argv[argc],"%d",value); /** Could save this step by changing tlist from %s to %d **/
4098 /* prefetch_filesys():
4099 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
4100 * Appends the filsys_id and the phys_id to the argv so they can be
4101 * referenced in an INSERT into a table other than filesys. Also
4102 * see comments at prefetch_value().
4104 * Assumes the existence of a row where filsys_id = argv[0], since a
4105 * filesys label has already been resolved to a filsys_id.
4107 prefetch_filesys(q,argv,cl)
4112 EXEC SQL BEGIN DECLARE SECTION;
4114 EXEC SQL END DECLARE SECTION;
4117 fid = *(int *)argv[0];
4118 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
4119 if(ingres_errno) return(mr_errcode);
4121 argc=q->argc+q->vcnt;
4122 sprintf(argv[argc++],"%d",phid);
4123 sprintf(argv[argc],"%d",fid);
4128 /* Convert normal Unix-style wildcards to SQL voodoo */
4129 convert_wildcards(arg)
4132 static char buffer[QMAXARGSIZE];
4133 register char *s, *d;
4135 for(d=buffer,s=arg;*s;s++) {
4137 case '*': *d++='%'; *d++='%'; break;
4138 case '?': *d++='_'; break;
4141 case ']': *d++='*'; *d++ = *s; break;
4142 case '%': *d++='*'; *d++='%'; *d++='%'; break;
4143 default: *d++ = *s; break;
4148 /* Copy back into argv */
4154 /* This version includes uppercase conversion, for things like gmac.
4155 * This is necessary because "LIKE" doesn't work with "uppercase()".
4156 * Including it in a wildcard routine saves making two passes over
4157 * the argument string.
4159 convert_wildcards_uppercase(arg)
4162 static char buffer[QMAXARGSIZE];
4163 register char *s, *d;
4165 for(d=buffer,s=arg;*s;s++) {
4167 case '*': *d++='%'; *d++='%'; break;
4168 case '?': *d++='_'; break;
4171 case ']': *d++='*'; *d++ = *s; break;
4172 case '%': *d++='*'; *d++='%'; *d++='%'; break;
4173 default: *d++=toupper(*s); break; /* This is the only diff. */
4178 /* Copy back into argv */
4185 /* Looks like it's time to build an abstraction barrier, Yogi */
4187 EXEC SQL BEGIN DECLARE SECTION;
4189 EXEC SQL END DECLARE SECTION;
4193 EXEC SQL PREPARE stmt FROM :stmt;
4194 EXEC SQL DESCRIBE stmt INTO :SQLDA;
4195 if(SQLDA->sqld==0) /* Not a SELECT */
4196 return(MR_INTERNAL);
4197 EXEC SQL DECLARE csr CURSOR FOR stmt;
4199 EXEC SQL FETCH csr USING DESCRIPTOR :SQLDA;
4200 if(sqlca.sqlcode==0)
4202 else if((sqlca.sqlcode<0) && mr_errcode)
4218 fprintf(stderr, "Size: %d\n", strlen(p));
4219 while (strlen(p) >= 8) {
4220 fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
4221 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
4224 switch (strlen(p)) {
4226 fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x\n",
4227 p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
4230 fprintf(stderr, "%02x %02x %02x %02x %02x %02x\n",
4231 p[0], p[1], p[2], p[3], p[4], p[5]);
4234 fprintf(stderr, "%02x %02x %02x %02x %02x\n",
4235 p[0], p[1], p[2], p[3], p[4]);
4238 fprintf(stderr, "%02x %02x %02x %02x\n",
4239 p[0], p[1], p[2], p[3]);
4242 fprintf(stderr, "%02x %02x %02x\n",
4246 fprintf(stderr, "%02x %02x\n",
4250 fprintf(stderr, "%02x\n",
4258 /* eof:qsupport.dc */