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 /* unquote ' chars in signature */
1521 for (dst = src = argv[U_SIGNATURE]; *src; ) {
1526 sprintf(databuf, "%s:%s", argv[U_NAME], argv[U_MITID]);
1527 /* skip bytes for timestamp & kname */
1528 si.rawsig = (unsigned char *) rawsig;
1529 status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE], &si);
1530 if (strlen(rawsig) > mr_sig_length) {
1531 com_err(whoami, 0, "GDSS signature would be truncated."); /** untested **/
1532 return(MR_INTERNAL);
1535 name = kname_unparse(si.pname, si.pinst, si.prealm);
1536 status = name_to_id(name, "STRING", &sigwho);
1537 if (status == MR_NO_MATCH) {
1538 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1539 WHERE name='strings_id';
1541 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1542 WHERE name='strings_id';
1543 EXEC SQL INSERT INTO strings (string_id, string)
1544 VALUES (:sigwho, :name);
1547 timestamp = si.timestamp;
1549 if (log_flags & LOG_GDSS)
1550 hex_dump(argv[U_SIGNATURE]);
1551 return(gdss2et(status));
1561 who = cl->client_id;
1562 entity = cl->entity;
1564 /* create finger entry, pobox & set modtime on user */
1566 EXEC SQL REPEATED UPDATE users
1567 SET modtime='now', modby=:who, modwith = :entity,
1568 fullname = :fullname, affiliation = type,
1569 signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho,
1570 fmodtime='now', fmodby = :who, fmodwith = :entity,
1571 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1572 WHERE login = :login;
1574 EXEC SQL REPEATED UPDATE users
1575 SET modtime='now', modby=:who, modwith = :entity,
1576 fullname = :fullname, affiliation = type,
1577 fmodtime='now', fmodby = :who, fmodwith = :entity,
1578 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1579 WHERE login = :login;
1587 ** followup_uusr - do signature, set_user_modtime
1590 ** argv[0] - login (add_user)
1591 ** argv[U_SIGNATURE] - sig
1595 followup_uuac(q, argv, cl)
1600 EXEC SQL BEGIN DECLARE SECTION;
1601 int who, status, id;
1602 char *entity, *name, *src, *dst;
1603 EXEC SQL END DECLARE SECTION;
1605 char databuf[32], *kname_unparse();
1606 EXEC SQL BEGIN DECLARE SECTION;
1609 int sigwho, timestamp;
1610 EXEC SQL END DECLARE SECTION;
1614 id = *(int *)argv[0];
1615 who = cl->client_id;
1616 entity = cl->entity;
1619 if (q->vcnt == U_MODTIME && *argv[U_SIGNATURE + 1]) {
1620 /* unquote ' chars in signature */
1621 for (dst = src = argv[U_SIGNATURE+1]; *src; ) {
1627 status = id_to_name(id, "USER", &login);
1628 sprintf(databuf, "%s:%s", login, argv[U_MITID+1]);
1630 /* skip bytes for timestamp & kname */
1631 si.rawsig = (unsigned char *) rawsig;
1633 com_err(whoami, 0, "verifying sig");
1635 status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE+1], &si);
1637 com_err(whoami, 0, "verified");
1639 if (strlen(rawsig) > mr_sig_length) {
1640 com_err(whoami, 0, "GDSS signature would be truncated."); /** untested **/
1641 return(MR_INTERNAL);
1644 name = kname_unparse(si.pname, si.pinst, si.prealm);
1645 status = name_to_id(name, "STRING", &sigwho);
1646 if (status == MR_NO_MATCH) {
1647 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1648 WHERE name='strings_id';
1650 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1651 WHERE name='strings_id';
1652 EXEC SQL INSERT INTO strings (string_id, string)
1653 VALUES (:sigwho, :name);
1656 timestamp = si.timestamp;
1658 if (log_flags & LOG_GDSS)
1659 hex_dump(argv[U_SIGNATURE+1]);
1660 return(gdss2et(status));
1669 /* create finger entry, pobox & set modtime on user */
1672 EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity,
1673 signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho
1674 WHERE users_id = :id;
1676 EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity
1677 WHERE users_id = :id;
1683 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1684 * type in argv[1]. Then completes the upcall to the user.
1686 * argv[2] is of the form "123:234" where the first integer is the machine
1687 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1688 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1692 followup_gpob(q, sq, v, action, actarg, cl)
1693 register struct query *q;
1694 register struct save_queue *sq;
1695 register struct validate *v;
1696 register int (*action)();
1700 char **argv, *index();
1702 int mid, sid, status, i;
1705 while (sq_get_data(sq, &argv)) {
1706 mr_trim_args(2, argv);
1708 p = index(argv[2], ':');
1710 mid = atoi(argv[2]);
1713 if (!strcmp(ptype, "POP")) {
1714 status = id_to_name(mid, "MACHINE", &argv[2]);
1715 if (status == MR_NO_MATCH)
1717 } else if (!strcmp(ptype, "SMTP")) {
1718 status = id_to_name(sid, "STRING", &argv[2]);
1719 if (status == MR_NO_MATCH)
1721 } else /* ptype == "NONE" */ {
1724 if (status) return(status);
1726 if (!strcmp(q->shortname, "gpob")) {
1727 sid = atoi(argv[4]);
1729 status = id_to_name(sid, "USER", &argv[4]);
1731 status = id_to_name(-sid, "STRING", &argv[4]);
1733 if (status && status != MR_NO_MATCH) return(status);
1735 (*action)(q->vcnt, argv, actarg);
1737 /* free saved data */
1738 for (i = 0; i < q->vcnt; i++)
1744 return (MR_SUCCESS);
1748 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1749 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1750 * proper name based on the type, and repace that string in the argv.
1751 * Also fixes the modby field by called followup_fix_modby.
1754 followup_glin(q, sq, v, action, actarg, cl)
1755 register struct query *q;
1756 register struct save_queue *sq;
1757 register struct validate *v;
1758 register int (*action)();
1762 char **argv, *malloc(), *realloc(), *type;
1763 int id, i, idx, status;
1766 if (!strcmp(q->shortname, "gsin"))
1769 while (sq_get_data(sq, &argv)) {
1770 mr_trim_args(q->vcnt, argv);
1772 id = atoi(argv[i = q->vcnt - 2]);
1774 status = id_to_name(id, "USER", &argv[i]);
1776 status = id_to_name(-id, "STRING", &argv[i]);
1777 if (status && status != MR_NO_MATCH)
1780 id = atoi(argv[idx]);
1781 type = argv[idx - 1];
1783 if (!strcmp(type, "LIST")) {
1784 status = id_to_name(id, "LIST", &argv[idx]);
1785 } else if (!strcmp(type, "USER")) {
1786 status = id_to_name(id, "USER", &argv[idx]);
1787 } else if (!strcmp(type, "KERBEROS")) {
1788 status = id_to_name(id, "STRING", &argv[idx]);
1789 } else if (!strcmp(type, "NONE")) {
1792 argv[idx] = strsave("NONE");
1796 argv[idx] = strsave("???");
1798 if (status && status != MR_NO_MATCH)
1801 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1802 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1803 strcpy(argv[6], UNIQUE_GID);
1807 (*action)(q->vcnt, argv, actarg);
1809 /* free saved data */
1810 for (i = 0; i < q->vcnt; i++)
1816 return (MR_SUCCESS);
1820 /* followup_gqot: Fix the entity name, directory name & modby fields
1821 * argv[0] = filsys_id
1823 * argv[2] = entity_id
1824 * argv[3] = ascii(quota)
1827 followup_gqot(q, sq, v, action, actarg, cl)
1829 register struct save_queue *sq;
1831 register int (*action)();
1832 register int actarg;
1836 char **argv, *malloc();
1837 EXEC SQL BEGIN DECLARE SECTION;
1840 EXEC SQL END DECLARE SECTION;
1843 if (!strcmp(q->name, "get_quota") ||
1844 !strcmp(q->name, "get_quota_by_filesys"))
1848 while (sq_get_data(sq, &argv)) {
1850 switch (argv[1][0]) {
1852 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1856 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1860 argv[2] = strsave("system:anyuser");
1864 argv[2] = malloc(8);
1865 sprintf(argv[2], "%d", id);
1868 id = atoi(argv[idx]);
1870 argv[idx] = malloc(256);
1874 EXEC SQL REPEATED SELECT name INTO :name FROM filesys
1875 WHERE label = :label;
1877 EXEC SQL REPEATED SELECT dir INTO :name FROM nfsphys
1878 WHERE nfsphys_id = :id;
1880 if (sqlca.sqlerrd[2] != 1) {
1881 sprintf(argv[idx], "#%d", id);
1884 id = atoi(argv[idx+3]);
1886 status = id_to_name(id, "USER", &argv[idx+3]);
1888 status = id_to_name(-id, "STRING", &argv[idx+3]);
1889 if (status && status != MR_NO_MATCH)
1891 (*action)(q->vcnt, argv, actarg);
1892 for (j = 0; j < q->vcnt; j++)
1901 /* followup_aqot: Add allocation to nfsphys after creating quota.
1902 * argv[0] = filsys_id
1903 * argv[1] = type if "add_quota" or "update_quota"
1905 * argv[3 or 2] = ascii(quota)
1908 followup_aqot(q, argv, cl)
1913 EXEC SQL BEGIN DECLARE SECTION;
1914 int quota, id, fs, who, physid;
1915 char *entity, *qtype, *table_name;
1916 EXEC SQL END DECLARE SECTION;
1921 table_name=q->rtable;
1922 fs = *(int *)argv[0];
1923 EXEC SQL REPEATED SELECT phys_id INTO :physid FROM filesys
1924 WHERE filsys_id = :fs;
1928 if (!strcmp(q->shortname, "aqot") || !strcmp(q->shortname, "uqot")) {
1930 id = *(int *)argv[2];
1931 quota = atoi(argv[3]);
1932 sprintf(incr_qual,"q.filsys_id = %d",fs);
1935 id = *(int *)argv[1];
1936 quota = atoi(argv[2]);
1937 sprintf(incr_qual,"q.filsys_id=%d AND q.type='%s' AND q.entity_id=%d",
1941 /* quota case of incremental_{before|after} only looks at slot 1 */
1944 /* Follows one of many possible gross hacks to fix these particular
1945 * conflicts between what is possible in the query table and what
1946 * is possible in SQL.
1948 if(q->type==APPEND) {
1949 incremental_clear_before();
1950 EXEC SQL INSERT INTO quota
1951 (filsys_id, type, entity_id, quota, phys_id)
1952 VALUES (:fs, :qtype, :id, :quota, :physid);
1953 incremental_after(table_name, incr_qual, incr_argv);
1955 incremental_before(table_name, incr_qual, incr_argv);
1956 EXEC SQL UPDATE quota SET quota = :quota
1957 WHERE filsys_id = :fs AND type = :qtype AND entity_id = :id;
1958 status = mr_errcode;
1959 incremental_after(table_name, incr_qual, incr_argv);
1964 flush_name(argv[0], q->rtable);
1965 if(q->type==APPEND) {
1966 EXEC SQL UPDATE tblstats SET appends = appends + 1, modtime = 'now'
1967 WHERE table_name = :table_name;
1969 EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = 'now'
1970 WHERE table_name = :table_name;
1973 /* Proceed with original followup */
1974 who = cl->client_id;
1975 entity = cl->entity;
1977 EXEC SQL REPEATED UPDATE quota
1978 SET modtime = 'now', modby = :who, modwith = :entity
1979 WHERE filsys_id = :fs and type = :qtype and entity_id = :id;
1980 EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated + :quota
1981 WHERE nfsphys_id = :physid;
1982 if (ingres_errno) return(mr_errcode);
1987 /* Necessitated by the requirement of a correlation name by the incremental
1988 * routines, since query table deletes don't provide one.
1990 followup_dqot(q,argv,cl)
1998 EXEC SQL BEGIN DECLARE SECTION;
2001 EXEC SQL END DECLARE SECTION;
2003 fs = *(int *)argv[0];
2004 if (!strcmp(q->shortname, "dqot")) {
2006 id = *(int *)argv[2];
2009 id = *(int *)argv[1];
2011 sprintf(incr_qual,"q.filsys_id=%d AND q.type='%s' AND q.entity_id=%d",
2014 /* quota case of incremental_{before|after} only looks at slot 1 */
2017 incremental_before(q->rtable, incr_qual, incr_argv);
2018 EXEC SQL DELETE FROM quota q WHERE :incr_qual;
2019 incremental_clear_after();
2023 flush_name(argv[0], q->rtable);
2025 tblname = q->rtable;
2026 EXEC SQL UPDATE tblstats SET deletes = deletes + 1, modtime = 'now'
2027 WHERE table_name = :tblname;
2032 followup_gpce(q, sq, v, action, actarg, cl)
2034 register struct save_queue *sq;
2036 register int (*action)();
2037 register int actarg;
2041 char **argv, *malloc();
2045 while (sq_get_data(sq, &argv)) {
2046 id = atoi(argv[PCAP_QSERVER]);
2047 status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
2048 if (status) return (status);
2051 status = id_to_name(id, "USER", &argv[i]);
2053 status = id_to_name(-id, "STRING", &argv[i]);
2054 if (status && status != MR_NO_MATCH)
2056 (*action)(q->vcnt, argv, actarg);
2057 for (j = 0; j < q->vcnt; j++)
2069 followup_gzcl(q, sq, v, action, actarg, cl)
2070 register struct query *q;
2071 register struct save_queue *sq;
2072 register struct validate *v;
2073 register int (*action)();
2080 while (sq_get_data(sq, &argv)) {
2081 mr_trim_args(q->vcnt, argv);
2083 id = atoi(argv[i = q->vcnt - 2]);
2085 status = id_to_name(id, "USER", &argv[i]);
2087 status = id_to_name(-id, "STRING", &argv[i]);
2088 if (status && status != MR_NO_MATCH)
2091 for (i = 1; i < 8; i+=2) {
2092 id = atoi(argv[i+1]);
2093 if (!strcmp(argv[i], "LIST")) {
2094 status = id_to_name(id, "LIST", &argv[i+1]);
2095 } else if (!strcmp(argv[i], "USER")) {
2096 status = id_to_name(id, "USER", &argv[i+1]);
2097 } else if (!strcmp(argv[i], "KERBEROS")) {
2098 status = id_to_name(id, "STRING", &argv[i+1]);
2099 } else if (!strcmp(argv[i], "NONE")) {
2102 argv[i+1] = strsave("NONE");
2106 argv[i+1] = strsave("???");
2108 if (status && status != MR_NO_MATCH)
2113 (*action)(q->vcnt, argv, actarg);
2115 /* free saved data */
2116 for (i = 0; i < q->vcnt; i++)
2128 followup_gsha(q, sq, v, action, actarg, cl)
2129 register struct query *q;
2130 register struct save_queue *sq;
2131 register struct validate *v;
2132 register int (*action)();
2139 while (sq_get_data(sq, &argv)) {
2140 mr_trim_args(q->vcnt, argv);
2144 status = id_to_name(id, "USER", &argv[4]);
2146 status = id_to_name(-id, "STRING", &argv[4]);
2147 if (status && status != MR_NO_MATCH)
2151 if (!strcmp(argv[1], "LIST")) {
2152 status = id_to_name(id, "LIST", &argv[2]);
2153 } else if (!strcmp(argv[1], "USER")) {
2154 status = id_to_name(id, "USER", &argv[2]);
2155 } else if (!strcmp(argv[1], "KERBEROS")) {
2156 status = id_to_name(id, "STRING", &argv[2]);
2157 } else if (!strcmp(argv[1], "NONE")) {
2160 argv[2] = strsave("NONE");
2164 argv[2] = strsave("???");
2166 if (status && status != MR_NO_MATCH)
2170 (*action)(q->vcnt, argv, actarg);
2172 /* free saved data */
2173 for (i = 0; i < q->vcnt; i++)
2183 /* Special query routines */
2185 /* set_pobox - this does all of the real work.
2186 * argv = user_id, type, box
2187 * if type is POP, then box should be a machine, and its ID should be put in
2188 * pop_id. If type is SMTP, then box should be a string and its ID should
2189 * be put in box_id. If type is NONE, then box doesn't matter.
2192 int set_pobox(q, argv, cl)
2197 EXEC SQL BEGIN DECLARE SECTION;
2199 char *box, potype[9];
2200 EXEC SQL END DECLARE SECTION;
2204 user = *(int *)argv[0];
2206 EXEC SQL REPEATED SELECT pop_id, potype INTO :id, :potype FROM users
2207 WHERE users_id = :user;
2208 if (ingres_errno) return(mr_errcode);
2209 if (!strcmp(strtrim(potype), "POP"))
2210 set_pop_usage(id, -1);
2212 if (!strcmp(argv[1], "POP")) {
2213 status = name_to_id(box, "MACHINE", &id);
2214 if (status == MR_NO_MATCH)
2218 EXEC SQL REPEATED UPDATE users SET potype = 'POP', pop_id = :id
2219 WHERE users_id = :user;
2220 set_pop_usage(id, 1);
2221 } else if (!strcmp(argv[1], "SMTP")) {
2222 if (index(box, '/') || index(box, '|'))
2223 return(MR_BAD_CHAR);
2224 status = name_to_id(box, "STRING", &id);
2225 if (status == MR_NO_MATCH) {
2226 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
2227 WHERE name='strings_id';
2229 EXEC SQL REPEATED UPDATE numvalues SET value = :id
2230 WHERE name='strings_id';
2231 EXEC SQL INSERT INTO strings (string_id, string)
2235 EXEC SQL REPEATED UPDATE users SET potype='SMTP', box_id = :id
2236 WHERE users_id = :user;
2237 } else /* argv[1] == "NONE" */ {
2238 EXEC SQL REPEATED UPDATE users SET potype='NONE'
2239 WHERE users_id = :user;
2242 set_pobox_modtime(q, argv, cl);
2243 EXEC SQL REPEATED UPDATE tblstats SET updates = updates+1, modtime='now'
2244 WHERE table_name='users';
2245 if (ingres_errno) return(mr_errcode);
2250 /* get_list_info: passed a wildcard list name, returns lots of stuff about
2251 * each list. This is tricky: first build a queue of all requested
2252 * data. Rest of processing consists of fixing gid, ace_name, and modby.
2255 get_list_info(q, aargv, cl, action, actarg)
2256 register struct query *q;
2259 register int (*action)();
2262 char *argv[13], *malloc(), *realloc();
2263 EXEC SQL BEGIN DECLARE SECTION;
2264 char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
2265 char maillist[5], grouplist[5], gid_str[6], acl_name[256], desc[256];
2266 char modtime[27], modby[256], modwith[9];
2267 int id, rowcount, acl_id, hid, modby_id;
2269 EXEC SQL END DECLARE SECTION;
2270 int returned, status;
2271 struct save_queue *sq, *sq_create();
2273 returned = rowcount = 0;
2275 convert_wildcards(name);
2278 sprintf(qual,"name LIKE '%s' ESCAPE '*'",name);
2279 optimize_sql_stmt(qual);
2280 EXEC SQL DECLARE csr102 CURSOR FOR SELECT list_id FROM list
2282 EXEC SQL OPEN csr102;
2285 EXEC SQL FETCH csr102 INTO :id;
2286 if(sqlca.sqlcode!=0) break;
2287 sq_save_data(sq, id);
2290 EXEC SQL CLOSE csr102;
2292 if (ingres_errno) return(mr_errcode);
2294 return(MR_NO_MATCH);
2296 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
2297 argv[4] = maillist; argv[5] = grouplist; argv[6] = gid_str;
2298 argv[7] = acl_type; argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
2300 while (sq_get_data(sq, &id)) {
2304 EXEC SQL REPEATED SELECT name, CHAR(active), CHAR(publicflg),
2305 CHAR(hidden), hidden, CHAR(maillist), CHAR(grouplist), CHAR(gid),
2306 TRIM(acl_type), acl_id, description, CHAR(modtime), modby, modwith
2307 INTO :listname, :active, :public, :hidden, :hid, :maillist,
2308 :grouplist, :gid_str, :acl_type, :acl_id, :desc,
2309 :modtime, :modby_id, :modwith
2310 FROM list WHERE list_id = :id;
2312 if (ingres_errno) return(mr_errcode);
2314 if (atoi(gid_str) == -1)
2315 argv[6] = UNIQUE_GID;
2317 argv[8] = malloc(0);
2318 if (!strcmp(acl_type, "LIST")) {
2319 status = id_to_name(acl_id, "LIST", &argv[8]);
2320 } else if (!strcmp(acl_type, "USER")) {
2321 status = id_to_name(acl_id, "USER", &argv[8]);
2322 } else if (!strcmp(acl_type, "KERBEROS")) {
2323 status = id_to_name(acl_id, "STRING", &argv[8]);
2324 } else if (!strcmp(acl_type, "NONE")) {
2327 argv[8] = strsave("NONE");
2331 argv[8] = strsave("???");
2333 if (status && status != MR_NO_MATCH) return(status);
2335 argv[11] = malloc(0);
2337 status = id_to_name(modby_id, "USER", &argv[11]);
2339 status = id_to_name(-modby_id, "STRING", &argv[11]);
2340 if (status && status != MR_NO_MATCH) return(status);
2342 mr_trim_args(q->vcnt, argv);
2344 (*action)(q->vcnt, argv, actarg);
2350 if (ingres_errno) return(mr_errcode);
2351 return (MR_SUCCESS);
2355 /* Add_member_to_list: do list flattening as we go! MAXLISTDEPTH is
2356 * how many different ancestors a member is allowed to have.
2359 #define MAXLISTDEPTH 1024
2361 int add_member_to_list(q, argv, cl)
2366 EXEC SQL BEGIN DECLARE SECTION;
2367 int id, lid, mid, error, who, ref, rowcnt;
2368 char *mtype, dtype[9], *entity;
2369 EXEC SQL END DECLARE SECTION;
2370 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2371 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2373 char *dtypes[MAXLISTDEPTH];
2374 char *iargv[3], *buf;
2376 lid = *(int *)argv[0];
2378 mid = *(int *)argv[2];
2379 /* if the member is already a direct member of the list, punt */
2380 EXEC SQL REPEATED SELECT COUNT(list_id) INTO :rowcnt FROM imembers
2381 WHERE list_id = :lid AND member_id = :mid
2382 AND member_type = :mtype AND direct = 1;
2385 if (!strcasecmp(mtype, "STRING")) {
2387 status = id_to_name(mid, "STRING", &buf);
2388 if (status) return(status);
2389 if (index(buf, '/') || index(buf, '|')) {
2391 return(MR_BAD_CHAR);
2399 EXEC SQL DECLARE csr103 CURSOR FOR
2400 SELECT list_id, ref_count FROM imembers
2401 WHERE member_id = :lid AND member_type='LIST';
2402 EXEC SQL OPEN csr103;
2404 EXEC SQL FETCH csr103 INTO :id, :ref;
2405 if(sqlca.sqlcode != 0) break;
2407 ancestors[acount++] = id;
2408 if (acount >= MAXLISTDEPTH) break;
2410 EXEC SQL CLOSE csr103;
2411 if (ingres_errno) return(mr_errcode);
2412 if (acount >= MAXLISTDEPTH) {
2413 return(MR_INTERNAL);
2415 descendants[0] = mid;
2420 if (!strcmp(mtype, "LIST")) {
2421 EXEC SQL DECLARE csr104 CURSOR FOR
2422 SELECT member_id, member_type, ref_count
2424 WHERE list_id = :mid;
2425 EXEC SQL OPEN csr104;
2427 EXEC SQL FETCH csr104 INTO :id, :dtype, :ref;
2428 if(sqlca.sqlcode != 0) break;
2431 dtypes[dcount] = "LIST";
2434 dtypes[dcount] = "USER";
2437 dtypes[dcount] = "STRING";
2440 dtypes[dcount] = "KERBEROS";
2447 descendants[dcount++] = id;
2448 if (dcount >= MAXLISTDEPTH) {
2453 EXEC SQL CLOSE csr104;
2454 if (ingres_errno) return(mr_errcode);
2456 return(MR_INTERNAL);
2458 for (a = 0; a < acount; a++) {
2460 for (d = 0; d < dcount; d++) {
2461 mid = descendants[d];
2463 if (mid == lid && !strcmp(mtype, "LIST")) {
2464 return(MR_LISTLOOP);
2466 EXEC SQL REPEATED SELECT COUNT(ref_count) INTO :rowcnt
2468 WHERE list_id = :lid AND member_id = :mid
2469 AND member_type = :mtype;
2470 ref = aref[a] * dref[d];
2472 if (a == 0 && d == 0) {
2473 EXEC SQL UPDATE imembers
2474 SET ref_count = ref_count+:ref, direct=1
2475 WHERE list_id = :lid AND member_id = :mid
2476 AND member_type = :mtype;
2478 EXEC SQL UPDATE imembers
2479 SET ref_count = ref_count+:ref
2480 WHERE list_id = :lid AND member_id = :mid
2481 AND member_type = :mtype;
2484 incremental_clear_before();
2485 if (a == 0 && d == 0) {
2486 EXEC SQL INSERT INTO imembers
2487 (list_id, member_id, direct, member_type, ref_count)
2488 VALUES (:lid, :mid, 1, :mtype, 1);
2490 EXEC SQL INSERT INTO imembers
2491 (list_id, member_id, member_type, ref_count)
2492 VALUES (:lid, :mid, :mtype, 1);
2494 iargv[0] = (char *)lid;
2496 iargv[2] = (char *)mid;
2497 incremental_after("members", 0, iargv);
2501 lid = *(int *)argv[0];
2502 entity = cl->entity;
2503 who = cl->client_id;
2504 EXEC SQL REPEATED UPDATE list
2505 SET modtime='now', modby = :who, modwith = :entity
2506 WHERE list_id = :lid;
2507 if (ingres_errno) return(mr_errcode);
2512 /* Delete_member_from_list: do list flattening as we go!
2515 int delete_member_from_list(q, argv, cl)
2520 EXEC SQL BEGIN DECLARE SECTION;
2521 int id, lid, mid, cnt, error, who, ref;
2522 char *mtype, dtype[9], *entity;
2523 EXEC SQL END DECLARE SECTION;
2524 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2525 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2526 char *dtypes[MAXLISTDEPTH];
2529 lid = *(int *)argv[0];
2531 mid = *(int *)argv[2];
2532 /* if the member is not a direct member of the list, punt */
2533 EXEC SQL REPEATED SELECT COUNT(list_id) INTO :cnt FROM imembers
2534 WHERE list_id = :lid AND member_id = :mid
2535 AND member_type = :mtype AND direct = 1;
2536 if (ingres_errno) return(mr_errcode);
2538 return(MR_NO_MATCH);
2542 EXEC SQL DECLARE csr105 CURSOR FOR
2543 SELECT list_id, ref_count FROM imembers
2544 WHERE member_id = :lid AND member_type = 'LIST';
2545 EXEC SQL OPEN csr105;
2547 EXEC SQL FETCH csr105 INTO :id, :ref;
2548 if(sqlca.sqlcode!=0) break;
2550 ancestors[acount++] = id;
2551 if (acount >= MAXLISTDEPTH) break;
2553 EXEC SQL CLOSE csr105;
2556 if (acount >= MAXLISTDEPTH)
2557 return(MR_INTERNAL);
2558 descendants[0] = mid;
2563 if (!strcmp(mtype, "LIST")) {
2564 EXEC SQL DECLARE csr106 CURSOR FOR
2565 SELECT member_id, member_type, ref_count FROM imembers
2566 WHERE list_id = :mid;
2567 EXEC SQL OPEN csr106;
2569 EXEC SQL FETCH csr106 INTO :id, :dtype, :ref;
2570 if(sqlca.sqlcode!=0) break;
2573 dtypes[dcount] = "LIST";
2576 dtypes[dcount] = "USER";
2579 dtypes[dcount] = "STRING";
2582 dtypes[dcount] = "KERBEROS";
2589 descendants[dcount++] = id;
2590 if (dcount >= MAXLISTDEPTH) break;
2592 EXEC SQL CLOSE csr106;
2596 return(MR_INTERNAL);
2598 for (a = 0; a < acount; a++) {
2600 for (d = 0; d < dcount; d++) {
2601 mid = descendants[d];
2603 if (mid == lid && !strcmp(mtype, "LIST")) {
2604 return(MR_LISTLOOP);
2606 EXEC SQL REPEATED SELECT ref_count INTO :cnt FROM imembers
2607 WHERE list_id = :lid AND member_id = :mid AND member_type = :mtype;
2608 ref = aref[a] * dref[d];
2610 iargv[0] = (char *)lid;
2612 iargv[2] = (char *)mid;
2613 incremental_before("members", 0, iargv);
2614 EXEC SQL DELETE FROM imembers
2615 WHERE list_id = :lid AND member_id = :mid
2616 AND member_type= :mtype;
2617 incremental_clear_after();
2618 } else if (a == 0 && d == 0) {
2619 EXEC SQL UPDATE imembers
2620 SET ref_count = ref_count - :ref, direct = 0
2621 WHERE list_id = :lid AND member_id = :mid
2622 AND member_type = :mtype;
2624 EXEC SQL UPDATE imembers
2625 SET ref_count = ref_count - :ref
2626 WHERE list_id = :lid AND member_id = :mid
2627 AND member_type = :mtype;
2631 lid = *(int *)argv[0];
2632 entity = cl->entity;
2633 who = cl->client_id;
2634 EXEC SQL UPDATE list SET modtime = 'now', modby = :who, modwith = :entity
2635 WHERE list_id = :lid;
2636 if (ingres_errno) return(mr_errcode);
2641 /* get_ace_use - given a type and a name, return a type and a name.
2642 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2643 * and argv[1] will contain the ID of the entity in question. The R*
2644 * types mean to recursively look at every containing list, not just
2645 * when the object in question is a direct member. On return, the
2646 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2649 int get_ace_use(q, argv, cl, action, actarg)
2657 EXEC SQL BEGIN DECLARE SECTION;
2659 int aid, listid, id;
2660 EXEC SQL END DECLARE SECTION;
2661 struct save_queue *sq, *sq_create();
2664 aid = *(int *)argv[1];
2665 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2666 !strcmp(atype, "KERBEROS")) {
2667 return(get_ace_internal(atype, aid, action, actarg));
2671 if (!strcmp(atype, "RLIST")) {
2672 sq_save_data(sq, aid);
2673 /* get all the list_id's of containing lists */
2674 EXEC SQL DECLARE csr107 CURSOR FOR
2675 SELECT list_id FROM imembers
2676 WHERE member_type='LIST' AND member_id = :aid;
2677 EXEC SQL OPEN csr107;
2679 EXEC SQL FETCH csr107 INTO :listid;
2680 if(sqlca.sqlcode != 0) break;
2681 sq_save_unique_data(sq, listid);
2683 EXEC SQL CLOSE csr107;
2684 /* now process each one */
2685 while (sq_get_data(sq, &id)) {
2686 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2691 if (!strcmp(atype, "RUSER")) {
2692 EXEC SQL DECLARE csr108 CURSOR FOR
2693 SELECT list_id FROM imembers
2694 WHERE member_type='USER' AND member_id = :aid;
2695 EXEC SQL OPEN csr108;
2697 EXEC SQL FETCH csr108 INTO :listid;
2698 if(sqlca.sqlcode != 0) break;
2699 sq_save_data(sq, listid);
2701 EXEC SQL CLOSE csr108;
2702 /* now process each one */
2703 while (sq_get_data(sq, &id)) {
2704 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2707 if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2711 if (!strcmp(atype, "RKERBERO")) {
2712 EXEC SQL DECLARE csr109 CURSOR FOR
2713 SELECT list_id FROM imembers
2714 WHERE member_type='KERBEROS' AND member_id = :aid;
2715 EXEC SQL OPEN csr109;
2717 EXEC SQL FETCH csr109 INTO :listid;
2718 if(sqlca.sqlcode != 0) break;
2719 sq_save_data(sq, listid);
2721 EXEC SQL CLOSE csr109;
2722 /* now process each one */
2723 while (sq_get_data(sq, &id)) {
2724 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2727 if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2732 if (ingres_errno) return(mr_errcode);
2733 if (!found) return(MR_NO_MATCH);
2738 /* This looks up a single list or user for ace use. atype must be "USER"
2739 * or "LIST", and aid is the ID of the corresponding object. This is used
2740 * by get_ace_use above.
2743 get_ace_internal(atype, aid, action, actarg)
2744 EXEC SQL BEGIN DECLARE SECTION;
2747 EXEC SQL END DECLARE SECTION;
2753 EXEC SQL BEGIN DECLARE SECTION;
2755 EXEC SQL END DECLARE SECTION;
2758 if (!strcmp(atype, "LIST")) {
2759 rargv[0] = "FILESYS";
2760 EXEC SQL DECLARE csr110 CURSOR FOR
2761 SELECT label FROM filesys
2762 WHERE owners = :aid;
2763 EXEC SQL OPEN csr110;
2765 EXEC SQL FETCH csr110 INTO :name;
2766 if(sqlca.sqlcode != 0) break;
2767 (*action)(2, rargv, actarg);
2770 EXEC SQL CLOSE csr110;
2773 EXEC SQL DECLARE csr111 CURSOR FOR
2774 SELECT capability FROM capacls
2775 WHERE list_id = :aid ;
2776 EXEC SQL OPEN csr111;
2778 EXEC SQL FETCH csr111 INTO :name ;
2779 if(sqlca.sqlcode != 0) break;
2780 (*action)(2, rargv, actarg);
2783 EXEC SQL CLOSE csr111;
2784 } else if (!strcmp(atype, "USER")) {
2785 rargv[0] = "FILESYS";
2786 EXEC SQL DECLARE csr112 CURSOR FOR
2787 SELECT label FROM filesys
2789 EXEC SQL OPEN csr112;
2791 EXEC SQL FETCH csr112 INTO :name ;
2792 if(sqlca.sqlcode != 0) break;
2793 (*action)(2, rargv, actarg);
2796 EXEC SQL CLOSE csr112;
2800 EXEC SQL DECLARE csr113 CURSOR FOR
2801 SELECT name FROM list
2802 WHERE acl_type = :atype AND acl_id = :aid;
2803 EXEC SQL OPEN csr113;
2805 EXEC SQL FETCH csr113 INTO :name;
2806 if(sqlca.sqlcode != 0) break;
2807 (*action)(2, rargv, actarg);
2810 EXEC SQL CLOSE csr113;
2812 rargv[0] = "SERVICE";
2813 EXEC SQL DECLARE csr114 CURSOR FOR
2814 SELECT name FROM servers
2815 WHERE acl_type = :atype AND acl_id = :aid;
2816 EXEC SQL OPEN csr114;
2818 EXEC SQL FETCH csr114 INTO :name;
2819 if(sqlca.sqlcode != 0) break;
2820 (*action)(2, rargv, actarg);
2823 EXEC SQL CLOSE csr114;
2825 rargv[0] = "HOSTACCESS";
2826 EXEC SQL DECLARE csr115 CURSOR FOR
2827 SELECT name FROM machine m, hostaccess ha
2828 WHERE m.mach_id = ha.mach_id AND ha.acl_type = :atype
2829 AND ha.acl_id = :aid;
2830 EXEC SQL OPEN csr115;
2832 EXEC SQL FETCH csr115 INTO :name;
2833 if(sqlca.sqlcode != 0) break;
2834 (*action)(2, rargv, actarg);
2837 EXEC SQL CLOSE csr115;
2839 rargv[0] = "ZEPHYR";
2840 EXEC SQL DECLARE csr116 CURSOR FOR
2841 SELECT class FROM zephyr z
2842 WHERE z.xmt_type = :atype AND z.xmt_id = :aid
2843 OR z.sub_type = :atype AND z.sub_id = :aid
2844 OR z.iws_type = :atype AND z.iws_id = :aid
2845 OR z.iui_type = :atype AND z.iui_id = :aid;
2846 EXEC SQL OPEN csr116;
2848 EXEC SQL FETCH csr116 INTO :name;
2849 if(sqlca.sqlcode != 0) break;
2850 (*action)(2, rargv, actarg);
2853 EXEC SQL CLOSE csr116;
2855 if (!found) return(MR_NO_MATCH);
2860 /* get_lists_of_member - given a type and a name, return the name and flags
2861 * of all of the lists of the given member. The member_type is one of
2862 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2863 * and argv[1] will contain the ID of the entity in question. The R*
2864 * types mean to recursively look at every containing list, not just
2865 * when the object in question is a direct member.
2868 int get_lists_of_member(q, argv, cl, action, actarg)
2875 int found = 0, direct = 1;
2877 EXEC SQL BEGIN DECLARE SECTION;
2879 int aid, listid, id;
2880 char name[33], active[5], public[5], hidden[5], maillist[5], grouplist[5];
2881 EXEC SQL END DECLARE SECTION;
2884 aid = *(int *)argv[1];
2885 if (!strcmp(atype, "RLIST")) {
2889 if (!strcmp(atype, "RUSER")) {
2893 if (!strcmp(atype, "RSTRING")) {
2897 if (!strcmp(atype, "RKERBEROS")) {
2906 rargv[4] = maillist;
2907 rargv[5] = grouplist;
2909 EXEC SQL DECLARE csr117a CURSOR FOR
2910 SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2911 CHAR(l.maillist), CHAR(l.grouplist)
2912 FROM list l, imembers im
2913 WHERE l.list_id = im.list_id AND im.direct = 1
2914 AND im.member_type = :atype AND im.member_id = :aid;
2915 EXEC SQL OPEN csr117a;
2917 EXEC SQL FETCH csr117a
2918 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2919 if(sqlca.sqlcode != 0) break;
2920 (*action)(6, rargv, actarg);
2923 EXEC SQL CLOSE csr117a;
2925 EXEC SQL DECLARE csr117b CURSOR FOR
2926 SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2927 CHAR(l.maillist), CHAR(l.grouplist)
2928 FROM list l, imembers im
2929 WHERE l.list_id = im.list_id
2930 AND im.member_type = :atype AND im.member_id = :aid;
2931 EXEC SQL OPEN csr117b;
2933 EXEC SQL FETCH csr117b
2934 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2935 if(sqlca.sqlcode != 0) break;
2936 (*action)(6, rargv, actarg);
2939 EXEC SQL CLOSE csr117b;
2942 if (ingres_errno) return(mr_errcode);
2943 if (!found) return(MR_NO_MATCH);
2948 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2949 * the five flags associated with each list. It will return the name of
2950 * each list that meets the quailifications. It does this by building a
2951 * where clause based on the arguments, then doing a retrieve.
2954 static char *lflags[5] = { "active", "publicflg", "hidden", "maillist", "grouplist" };
2956 int qualified_get_lists(q, argv, cl, action, actarg)
2963 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2964 "l", "name", lflags));
2968 /* get_members_of_list - this gets only direct members */
2970 get_members_of_list(q, argv, cl, action, actarg)
2977 return(gmol_internal(q, argv, cl, action, actarg, 1));
2980 /* get_end_members_of_list - this gets direct or indirect members */
2982 get_end_members_of_list(q, argv, cl, action, actarg)
2989 return(gmol_internal(q, argv, cl, action, actarg, 0));
2992 /** gmol_internal - optimized query for retrieval of list members
2993 ** used by both get_members_of_list and get_end_members_of_list
2996 ** argv[0] - list_id
2999 ** - retrieve USER members, then LIST members, then STRING members
3002 gmol_internal(q, argv, cl, action, actarg, flag)
3010 EXEC SQL BEGIN DECLARE SECTION;
3011 int list_id, member_id, direct;
3012 char member_name[129], member_type[9];
3013 EXEC SQL END DECLARE SECTION;
3016 struct save_queue *sq;
3018 /* true/false flag indicates whether to display only direct members. */
3024 list_id = *(int *)argv[0];
3028 EXEC SQL DECLARE csr118 CURSOR FOR
3029 SELECT member_type, member_id FROM imembers
3030 WHERE list_id = :list_id AND direct > :direct;
3031 EXEC SQL OPEN csr118;
3033 EXEC SQL FETCH csr118 INTO :member_type, :member_id;
3034 if (sqlca.sqlcode != 0) break;
3037 sq_save_data(sq, ((int)member_type[0] << 24) | (member_id & 0xffffff));
3039 EXEC SQL CLOSE csr118;
3041 if (members <= 49) {
3042 targv[1] = malloc(0);
3043 while (sq_remove_data(sq, &member_id)) {
3044 switch (member_id >> 24) {
3047 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
3048 (*action)(2, targv, actarg);
3052 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
3053 (*action)(2, targv, actarg);
3056 targv[0] = "STRING";
3057 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
3058 (*action)(2, targv, actarg);
3061 targv[0] = "KERBEROS";
3062 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
3063 (*action)(2, targv, actarg);
3067 return(MR_INTERNAL);
3076 targv[1] = member_name;
3078 EXEC SQL DECLARE csr119 CURSOR FOR
3079 SELECT u.login FROM users u, imembers im
3080 WHERE im.list_id = :list_id AND im.member_type = 'USER'
3081 AND im.member_id = u.users_id AND im.direct > :direct
3083 EXEC SQL OPEN csr119;
3085 EXEC SQL FETCH csr119 INTO :member_name;
3086 if(sqlca.sqlcode != 0) break;
3087 (*action)(2, targv, actarg);
3089 EXEC SQL CLOSE csr119;
3090 if (ingres_errno) return(mr_errcode);
3093 EXEC SQL DECLARE csr120 CURSOR FOR
3094 SELECT l.name FROM list l, imembers im
3095 WHERE im.list_id = :list_id AND im.member_type='LIST'
3096 AND im.member_id = l.list_id AND im.direct > :direct
3098 EXEC SQL OPEN csr120;
3100 EXEC SQL FETCH csr120 INTO :member_name;
3101 if(sqlca.sqlcode != 0) break;
3102 (*action)(2, targv, actarg);
3104 EXEC SQL CLOSE csr120;
3105 if (ingres_errno) return(mr_errcode);
3107 targv[0] = "STRING";
3108 EXEC SQL DECLARE csr121 CURSOR FOR
3109 SELECT CHAR(str.string) FROM strings str, imembers im
3110 WHERE im.list_id = :list_id AND im.member_type='STRING'
3111 AND im.member_id = str.string_id AND im.direct > :direct
3113 EXEC SQL OPEN csr121;
3115 EXEC SQL FETCH csr121 INTO :member_name;
3116 if(sqlca.sqlcode != 0) break;
3117 (*action)(2, targv, actarg);
3119 EXEC SQL CLOSE csr121;
3120 if (ingres_errno) return(mr_errcode);
3122 targv[0] = "KERBEROS";
3123 EXEC SQL DECLARE csr122 CURSOR FOR
3124 SELECT CHAR(str.string) FROM strings str, imembers im
3125 WHERE im.list_id = :list_id AND im.member_type='KERBEROS'
3126 AND im.member_id = str.string_id
3127 AND im.direct > :direct
3129 EXEC SQL OPEN csr122;
3131 EXEC SQL FETCH csr122 INTO :member_name;
3132 if(sqlca.sqlcode != 0) break;
3133 (*action)(2, targv, actarg);
3135 EXEC SQL CLOSE csr122;
3136 if (ingres_errno) return(mr_errcode);
3142 /* count_members_of_list: this is a simple query, but it cannot be done
3143 * through the dispatch table.
3146 int count_members_of_list(q, argv, cl, action, actarg)
3153 EXEC SQL BEGIN DECLARE SECTION;
3155 EXEC SQL END DECLARE SECTION;
3156 char *rargv[1], countbuf[5];
3158 list = *(int *)argv[0];
3159 rargv[0] = countbuf;
3160 EXEC SQL REPEATED SELECT count (*) INTO :ct FROM imembers
3161 WHERE list_id = :list AND direct=1;
3162 if (ingres_errno) return(mr_errcode);
3163 sprintf(countbuf, "%d", ct);
3164 (*action)(1, rargv, actarg);
3169 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
3170 * the three flags associated with each service. It will return the name of
3171 * each service that meets the quailifications. It does this by building a
3172 * where clause based on the arguments, then doing a retrieve.
3175 static char *sflags[3] = { "enable", "inprogress", "harderror" };
3177 int qualified_get_server(q, argv, cl, action, actarg)
3184 return(qualified_get(q, argv, action, actarg, "s.name != ''",
3185 "s", "name", sflags));
3189 /* generic qualified get routine, used by qualified_get_lists,
3190 * qualified_get_server, and qualified_get_serverhost.
3192 * start - a simple where clause, must not be empty
3193 * range - the name of the range variable
3194 * field - the field to return
3195 * flags - an array of strings, names of the flag variables
3198 int qualified_get(q, argv, action, actarg, start, range, field, flags)
3208 char name[33], qual[256];
3210 char *rargv[1], buf[32];
3212 strcpy(qual, start);
3213 for (i = 0; i < q->argc; i++) {
3214 if (!strcmp(argv[i], "TRUE")) {
3215 sprintf(buf, " AND %s.%s != 0", range, flags[i]);
3216 (void) strcat(qual, buf);
3217 } else if (!strcmp(argv[i], "FALSE")) {
3218 sprintf(buf, " AND %s.%s = 0", range, flags[i]);
3219 (void) strcat(qual, buf);
3223 rargv[0] = SQLDA->sqlvar[0].sqldata;
3224 sprintf(stmt_buf,"SELECT CHAR(%s.%s) FROM %s %s WHERE %s",range,field,q->rtable,range,qual);
3225 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3227 return(MR_INTERNAL);
3228 EXEC SQL DECLARE csr123 CURSOR FOR stmt;
3229 EXEC SQL OPEN csr123;
3231 EXEC SQL FETCH csr123 USING DESCRIPTOR :SQLDA;
3232 if(sqlca.sqlcode != 0) break;
3234 (*action)(1, rargv, actarg);
3236 EXEC SQL CLOSE csr123;
3237 if (ingres_errno) return(mr_errcode);
3239 return(MR_NO_MATCH);
3244 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
3245 * the five flags associated with each serverhost. It will return the name of
3246 * each service and host that meets the quailifications. It does this by
3247 * building a where clause based on the arguments, then doing a retrieve.
3250 static char *shflags[6] = { "service", "enable", "override", "success",
3251 "inprogress", "hosterror" };
3253 int qualified_get_serverhost(q, argv, cl, action, actarg)
3260 EXEC SQL BEGIN DECLARE SECTION;
3261 char sname[33], mname[33], qual[256];
3262 EXEC SQL END DECLARE SECTION;
3263 char *rargv[2], buf[32];
3266 sprintf(qual, "m.mach_id = sh.mach_id AND sh.service = uppercase('%s')",
3268 for (i = 1; i < q->argc; i++) {
3269 if (!strcmp(argv[i], "TRUE")) {
3270 sprintf(buf, " AND sh.%s != 0", shflags[i]);
3272 } else if (!strcmp(argv[i], "FALSE")) {
3273 sprintf(buf, " AND sh.%s = 0", shflags[i]);
3280 EXEC SQL DECLARE csr124 CURSOR FOR
3281 SELECT sh.service, m.name FROM serverhosts sh, machine m
3283 EXEC SQL OPEN csr124;
3285 EXEC SQL FETCH csr124 INTO :sname, :mname;
3286 if(sqlca.sqlcode != 0) break;
3288 (*action)(2, rargv, actarg);
3290 EXEC SQL CLOSE csr124;
3292 if (ingres_errno) return(mr_errcode);
3294 return(MR_NO_MATCH);
3299 /* register_user - change user's login name and allocate a pobox, group,
3300 * filesystem, and quota for them. The user's status must start out as 0,
3301 * and is left as 2. Arguments are: user's UID, new login name, and user's
3302 * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY,
3303 * MR_FS_STAFF, MR_FS_MISC).
3306 register_user(q, argv, cl)
3311 EXEC SQL BEGIN DECLARE SECTION;
3312 char *login, dir[65], *entity, directory[129], machname[33];
3313 int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
3314 int size, alloc, pid, ostatus, nstatus, gidval, fsidval, npidval;
3315 static int m_id = 0, def_quota = 0;
3316 EXEC SQL END DECLARE SECTION;
3317 char buffer[256], *aargv[3];
3319 entity = cl->entity;
3320 who = cl->client_id;
3322 uid = atoi(argv[0]);
3324 utype = atoi(argv[2]);
3327 EXEC SQL REPEATED SELECT users_id, status INTO :users_id, :ostatus
3329 WHERE uid = :uid AND (status=0 OR status=5 OR status=6);
3331 if (sqlca.sqlerrd[2] == 0)
3332 return(MR_NO_MATCH);
3333 if (sqlca.sqlerrd[2] > 1)
3334 return(MR_NOT_UNIQUE);
3336 /* check new login name */
3337 EXEC SQL REPEATED SELECT COUNT(login) INTO :rowcount FROM users
3338 WHERE login = LEFT(:login,SIZE(login)) AND users_id != :users_id;
3339 if (ingres_errno) return(mr_errcode);
3340 if (rowcount > 0) return(MR_IN_USE);
3341 EXEC SQL REPEATED SELECT COUNT(name) INTO :rowcount FROM list
3342 WHERE name = LEFT(:login,SIZE(name));
3343 if (ingres_errno) return(mr_errcode);
3344 if (rowcount > 0) return(MR_IN_USE);
3345 EXEC SQL REPEATED SELECT COUNT(label) INTO :rowcount FROM filesys
3346 WHERE label = LEFT(:login,SIZE(label));
3347 if (ingres_errno) return(mr_errcode);
3348 if (rowcount > 0) return(MR_IN_USE);
3349 com_err(whoami, 0, "login name OK");
3351 /* choose place for pobox, put in mid */
3352 EXEC SQL DECLARE csr130 CURSOR FOR
3353 SELECT sh.mach_id, m.name FROM serverhosts sh, machine m
3354 WHERE sh.service='POP' AND sh.mach_id=m.mach_id
3355 AND sh.value2 - sh.value1 =
3356 (SELECT MAX(value2 - value1) FROM serverhosts
3357 WHERE service = 'POP');
3358 EXEC SQL OPEN csr130;
3359 EXEC SQL FETCH csr130 INTO :mid, :machname;
3360 if (sqlca.sqlerrd[2] == 0) {
3361 EXEC SQL CLOSE csr130;
3362 if (ingres_errno) return(mr_errcode);
3363 return(MR_NO_POBOX);
3365 EXEC SQL CLOSE csr130;
3366 if (ingres_errno) return(mr_errcode);
3369 /* change login name, set pobox */
3370 sprintf(buffer, "u.users_id = %d", users_id);
3371 incremental_before("users", buffer, 0);
3373 if (ostatus == 5 || ostatus == 6)
3375 EXEC SQL REPEATED UPDATE users SET login = :login, status = :nstatus,
3376 modtime='now', modby = :who, modwith = :entity, potype='POP',
3377 pop_id = :mid, pmodtime='now', pmodby = :who, pmodwith = :entity
3378 WHERE users_id = :users_id;
3380 if (ingres_errno) return(mr_errcode);
3381 if (sqlca.sqlerrd[2] != 1)
3382 return(MR_INTERNAL);
3383 set_pop_usage(mid, 1);
3384 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
3386 incremental_after("users", buffer, 0);
3388 /* create group list */
3389 if (set_next_object_id("gid", "list", 1))
3391 if (set_next_object_id("list_id", "list", 0))
3393 EXEC SQL REPEATED SELECT value INTO :list_id FROM numvalues
3394 WHERE name='list_id';
3395 if (ingres_errno) return(mr_errcode);
3396 if (sqlca.sqlerrd[2] != 1)
3397 return(MR_INTERNAL);
3398 incremental_clear_before();
3399 EXEC SQL SELECT value INTO :gidval FROM numvalues WHERE name = 'gid';
3400 EXEC SQL REPEATED INSERT INTO list
3401 (name, list_id, active, publicflg, hidden, maillist, grouplist,
3402 gid, description, acl_type, acl_id,
3403 modtime, modby, modwith)
3404 VALUES (:login, :list_id, 1, 0, 0, 0, 1,
3405 :gidval, 'User Group', 'USER', :users_id,
3406 'now', :who, :entity);
3407 if (ingres_errno) return(mr_errcode);
3408 if (sqlca.sqlerrd[2] != 1)
3409 return(MR_INTERNAL);
3410 sprintf(buffer, "l.list_id = %d", list_id);
3411 incremental_after("list", buffer, 0);
3412 aargv[0] = (char *) list_id;
3414 aargv[2] = (char *) users_id;
3415 incremental_clear_before();
3416 EXEC SQL REPEATED INSERT INTO imembers
3417 (list_id, member_type, member_id, ref_count, direct)
3418 VALUES (:list_id, 'USER', :users_id, 1, 1);
3419 if (ingres_errno) return(mr_errcode);
3420 if (sqlca.sqlerrd[2] != 1)
3421 return(MR_INTERNAL);
3422 incremental_after("members", 0, aargv);
3425 /* Cell Name (I know, it shouldn't be hard coded...) */
3426 strcpy(machname, "ATHENA.MIT.EDU");
3427 EXEC SQL SELECT mach_id INTO :m_id FROM machine
3428 WHERE name = :machname;
3431 /* create filesystem */
3432 if (set_next_object_id("filsys_id", "filesys", 0))
3434 incremental_clear_before();
3435 if (islower(login[0]) && islower(login[1])) {
3436 sprintf(directory, "/afs/athena.mit.edu/user/%c/%c/%s",
3437 login[0], login[1], login);
3439 sprintf(directory, "/afs/athena.mit.edu/user/other/%s", login);
3442 EXEC SQL SELECT value INTO :fsidval FROM numvalues
3443 WHERE numvalues.name='filsys_id';
3444 EXEC SQL REPEATED INSERT INTO filesys
3445 (filsys_id, phys_id, label, type, mach_id, name,
3446 mount, access, comments, owner, owners, createflg,
3447 lockertype, modtime, modby, modwith)
3449 (:fsidval, 0, :login, 'AFS', :m_id, :directory,
3450 '/mit/'+:login, 'w', 'User Locker', :users_id, :list_id, 1,
3451 'HOMEDIR', 'now', :who, :entity);
3453 if (ingres_errno) return(mr_errcode);
3454 if (sqlca.sqlerrd[2] != 1)
3455 return(MR_INTERNAL);
3456 sprintf(buffer,"fs.filsys_id = %d",fsidval);
3457 incremental_after("filesys", buffer, 0);
3460 if (def_quota == 0) {
3461 EXEC SQL REPEATED SELECT value INTO :def_quota FROM numvalues
3462 WHERE name='def_quota';
3463 if (ingres_errno) return(mr_errcode);
3464 if (sqlca.sqlerrd[2] != 1)
3465 return(MR_NO_QUOTA);
3468 incremental_clear_before();
3469 EXEC SQL REPEATED INSERT INTO quota
3470 (entity_id, filsys_id, type, quota, phys_id, modtime, modby, modwith)
3472 (0, :fsidval, 'ANY', :def_quota, 0, 'now', :who, :entity);
3473 if (ingres_errno) return(mr_errcode);
3474 if (sqlca.sqlerrd[2] != 1)
3475 return(MR_INTERNAL);
3479 sprintf(buffer, "q.entity_id = 0 and q.filsys_id = %d and q.type = 'ANY'", fsidval);
3480 incremental_after("quota", buffer, aargv);
3481 com_err(whoami, 0, "quota of %d assigned", def_quota);
3482 if (ingres_errno) return(mr_errcode);
3484 cache_entry(login, "USER", users_id);
3486 EXEC SQL REPEATED UPDATE tblstats SET updates=updates+1, modtime='now'
3487 WHERE table_name='users';
3488 EXEC SQL REPEATED UPDATE tblstats SET appends=appends+1, modtime='now'
3489 WHERE table_name='list' OR table_name='filesys' OR table_name='quota';
3490 if (ingres_errno) return(mr_errcode);
3496 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
3500 ** delta (will be +/- 1)
3503 ** - incr/decr value field in serverhosts table for pop/mach_id
3507 static int set_pop_usage(id, cnt)
3508 EXEC SQL BEGIN DECLARE SECTION;
3511 EXEC SQL END DECLARE SECTION;
3513 EXEC SQL REPEATED UPDATE serverhosts SET value1 = value1 + :cnt
3514 WHERE serverhosts.service = 'POP' AND serverhosts.mach_id = :id;
3516 if (ingres_errno) return(mr_errcode);
3520 int _sdl_followup(q, argv, cl)
3529 EXEC SQL set printqry;
3531 EXEC SQL set noprintqry;
3538 /* Validation Routines */
3540 validate_row(q, argv, v)
3541 register struct query *q;
3543 register struct validate *v;
3545 EXEC SQL BEGIN DECLARE SECTION;
3549 EXEC SQL END DECLARE SECTION;
3551 /* build where clause */
3552 build_qual(v->qual, v->argc, argv, qual);
3554 if (log_flags & LOG_VALID)
3555 /* tell the logfile what we're doing */
3556 com_err(whoami, 0, "validating row: %s", qual);
3558 /* look for the record */
3559 sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",q->rtable,qual);
3560 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3562 return(MR_INTERNAL);
3563 EXEC SQL DECLARE csr126 CURSOR FOR stmt;
3564 EXEC SQL OPEN csr126;
3565 EXEC SQL FETCH csr126 USING DESCRIPTOR :SQLDA;
3566 EXEC SQL CLOSE csr126;
3567 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3569 if (ingres_errno) return(mr_errcode);
3570 if (rowcount == 0) return(MR_NO_MATCH);
3571 if (rowcount > 1) return(MR_NOT_UNIQUE);
3575 validate_fields(q, argv, vo, n)
3577 register char *argv[];
3578 register struct valobj *vo;
3581 register int status;
3586 if (log_flags & LOG_VALID)
3587 com_err(whoami, 0, "validating %s in %s: %s",
3588 vo->namefield, vo->table, argv[vo->index]);
3589 status = validate_name(argv, vo);
3593 if (log_flags & LOG_VALID)
3594 com_err(whoami, 0, "validating %s in %s: %s",
3595 vo->idfield, vo->table, argv[vo->index]);
3596 status = validate_id(q, argv, vo);
3600 if (log_flags & LOG_VALID)
3601 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
3602 status = validate_date(argv, vo);
3606 if (log_flags & LOG_VALID)
3607 com_err(whoami, 0, "validating %s type: %s",
3608 vo->table, argv[vo->index]);
3609 status = validate_type(argv, vo);
3613 if (log_flags & LOG_VALID)
3614 com_err(whoami, 0, "validating typed data (%s): %s",
3615 argv[vo->index - 1], argv[vo->index]);
3616 status = validate_typedata(q, argv, vo);
3620 if (log_flags & LOG_VALID)
3621 com_err(whoami, 0, "validating rename %s in %s",
3622 argv[vo->index], vo->table);
3623 status = validate_rename(argv, vo);
3627 if (log_flags & LOG_VALID)
3628 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
3629 status = validate_chars(argv[vo->index]);
3637 status = lock_table(vo);
3641 status = convert_wildcards(argv[vo->index]);
3645 status = convert_wildcards_uppercase(argv[vo->index]);
3650 if (status != MR_EXISTS) return(status);
3654 if (ingres_errno) return(mr_errcode);
3659 /* validate_chars: verify that there are no illegal characters in
3660 * the string. Legal characters are printing chars other than
3661 * ", *, ?, \, [ and ].
3663 static int illegalchars[] = {
3664 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
3665 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
3666 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
3667 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
3668 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
3669 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
3670 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
3671 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
3672 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3673 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3674 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3675 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3676 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3677 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3678 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3679 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3686 if (illegalchars[*s++])
3687 return(MR_BAD_CHAR);
3692 validate_id(q, argv, vo)
3695 register struct valobj *vo;
3697 EXEC SQL BEGIN DECLARE SECTION;
3698 char *name, *tbl, *namefield, *idfield;
3700 EXEC SQL END DECLARE SECTION;
3704 name = argv[vo->index];
3706 namefield = vo->namefield;
3707 idfield = vo->idfield;
3709 if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
3710 !strcmp(tbl, "machine") ||
3711 !strcmp(tbl, "filesys") ||
3712 !strcmp(tbl, "list") ||
3713 !strcmp(tbl, "cluster") ||
3714 !strcmp(tbl, "strings")) {
3715 if (!strcmp(tbl, "machine"))
3716 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3717 status = name_to_id(name, tbl, &id);
3719 *(int *)argv[vo->index] = id;
3721 } else if (status == MR_NO_MATCH && !strcmp(tbl, "strings") &&
3722 (q->type == APPEND || q->type == UPDATE)) {
3723 EXEC SQL SELECT value INTO :id FROM numvalues
3724 WHERE name = 'strings_id';
3726 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3727 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3728 cache_entry(name, "STRING", id);
3729 *(int *)argv[vo->index] = id;
3731 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
3737 if (!strcmp(namefield, "uid")) {
3738 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = %s",idfield,tbl,namefield,name);
3740 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",idfield,tbl,namefield,name);
3742 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3744 return(MR_INTERNAL);
3745 EXEC SQL DECLARE csr127 CURSOR FOR stmt;
3746 EXEC SQL OPEN csr127;
3748 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3749 if(sqlca.sqlcode == 0) {
3751 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3752 if(sqlca.sqlcode == 0) rowcount++;
3754 EXEC SQL CLOSE csr127;
3758 if (rowcount != 1) return(vo->error);
3759 bcopy(SQLDA->sqlvar[0].sqldata,argv[vo->index],sizeof(int));
3763 validate_name(argv, vo)
3765 register struct valobj *vo;
3767 EXEC SQL BEGIN DECLARE SECTION;
3768 char *name, *tbl, *namefield;
3770 EXEC SQL END DECLARE SECTION;
3773 name = argv[vo->index];
3775 namefield = vo->namefield;
3776 if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
3777 for (c = name; *c; c++)
3781 sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
3782 tbl,tbl,namefield,name);
3783 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3785 return(MR_INTERNAL);
3786 EXEC SQL DECLARE csr128 CURSOR FOR stmt;
3787 EXEC SQL OPEN csr128;
3788 EXEC SQL FETCH csr128 USING DESCRIPTOR :SQLDA;
3789 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3790 EXEC SQL CLOSE csr128;
3792 if (ingres_errno) return(mr_errcode);
3793 return ((rowcount == 1) ? MR_EXISTS : vo->error);
3796 validate_date(argv, vo)
3800 EXEC SQL BEGIN DECLARE SECTION;
3804 EXEC SQL END DECLARE SECTION;
3806 idate = argv[vo->index];
3807 EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
3809 if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
3814 validate_rename(argv, vo)
3818 EXEC SQL BEGIN DECLARE SECTION;
3819 char *name, *tbl, *namefield, *idfield;
3821 EXEC SQL END DECLARE SECTION;
3825 c = name = argv[vo->index];
3827 if (illegalchars[*c++])
3828 return(MR_BAD_CHAR);
3830 /* minor kludge to upcasify machine names */
3831 if (!strcmp(tbl, "machine"))
3832 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3833 namefield = vo->namefield;
3834 idfield = vo->idfield;
3837 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3839 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = LEFT('%s',SIZE(%s))",
3840 namefield,tbl,namefield,name,namefield);
3841 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3843 return(MR_INTERNAL);
3844 EXEC SQL DECLARE csr129 CURSOR FOR stmt;
3845 EXEC SQL OPEN csr129;
3846 EXEC SQL FETCH csr129 USING DESCRIPTOR :SQLDA;
3847 if(sqlca.sqlcode == 0) id=1; else id=0;
3848 EXEC SQL CLOSE csr129;
3850 if (ingres_errno) return(mr_errcode);
3856 status = name_to_id(name, tbl, &id);
3857 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3864 validate_type(argv, vo)
3866 register struct valobj *vo;
3868 EXEC SQL BEGIN DECLARE SECTION;
3872 EXEC SQL END DECLARE SECTION;
3875 typename = vo->table;
3876 c = val = argv[vo->index];
3878 if (illegalchars[*c++])
3879 return(MR_BAD_CHAR);
3882 /* uppercase type fields */
3883 for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
3885 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
3886 WHERE name = :typename AND type='TYPE' AND trans = :val;
3887 if (ingres_errno) return(mr_errcode);
3888 return (cnt ? MR_EXISTS : vo->error);
3891 /* validate member or type-specific data field */
3893 validate_typedata(q, argv, vo)
3894 register struct query *q;
3895 register char *argv[];
3896 register struct valobj *vo;
3898 EXEC SQL BEGIN DECLARE SECTION;
3901 char data_type[129];
3903 EXEC SQL END DECLARE SECTION;
3908 /* get named object */
3909 name = argv[vo->index];
3911 /* get field type string (known to be at index-1) */
3912 field_type = argv[vo->index-1];
3914 /* get corresponding data type associated with field type name */
3915 EXEC SQL SELECT trans INTO :data_type FROM alias
3916 WHERE name = :field_type AND type='TYPEDATA';
3917 if (ingres_errno) return(mr_errcode);
3918 if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
3920 /* now retrieve the record id corresponding to the named object */
3921 if (index(data_type, ' '))
3922 *index(data_type, ' ') = 0;
3923 if (!strcmp(data_type, "user")) {
3925 status = name_to_id(name, data_type, &id);
3926 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3928 if (status) return(status);
3929 } else if (!strcmp(data_type, "list")) {
3931 status = name_to_id(name, data_type, &id);
3932 if (status && status == MR_NOT_UNIQUE)
3934 if (status == MR_NO_MATCH) {
3935 /* if idfield is non-zero, then if argv[0] matches the string
3936 * that we're trying to resolve, we should get the value of
3937 * numvalues.[idfield] for the id.
3939 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3940 set_next_object_id(q->validate->object_id, q->rtable, 0);
3942 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
3944 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
3947 } else if (status) return(status);
3948 } else if (!strcmp(data_type, "machine")) {
3950 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3951 status = name_to_id(name, data_type, &id);
3952 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3954 if (status) return(status);
3955 } else if (!strcmp(data_type, "string")) {
3957 status = name_to_id(name, data_type, &id);
3958 if (status && status == MR_NOT_UNIQUE)
3960 if (status == MR_NO_MATCH) {
3961 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3962 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
3964 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3965 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3966 cache_entry(name, "STRING", id);
3967 } else if (status) return(status);
3968 } else if (!strcmp(data_type, "none")) {
3974 /* now set value in argv */
3975 *(int *)argv[vo->index] = id;
3981 /* Lock the table named by the validation object */
3986 sprintf(stmt_buf,"UPDATE %s SET modtime='now' WHERE %s.%s = 0",
3987 vo->table,vo->table,vo->idfield);
3988 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
3989 if (ingres_errno) return(mr_errcode);
3990 if (sqlca.sqlerrd[2] != 1)
3997 /* Check the database at startup time. For now this just resets the
3998 * inprogress flags that the DCM uses.
4001 sanity_check_database()
4006 /* Dynamic SQL support routines */
4007 MR_SQLDA_T *mr_alloc_SQLDA()
4010 short *null_indicators;
4013 if((it=(MR_SQLDA_T *)malloc(sizeof(MR_SQLDA_T)))==NULL) {
4014 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
4018 if((null_indicators=(short *)calloc(QMAXARGS,sizeof(short)))==NULL) {
4019 com_err(whoami, MR_NO_MEM, "setting up SQLDA null indicators");
4023 for(j=0; j<QMAXARGS; j++) {
4024 if((it->sqlvar[j].sqldata=malloc(sizeof(short)+QMAXARGSIZE))==NULL) {
4025 com_err(whoami, MR_NO_MEM, "setting up SQLDA variables");
4028 it->sqlvar[j].sqllen=QMAXARGSIZE;
4029 it->sqlvar[j].sqlind=null_indicators+j;
4030 null_indicators[j]=0;
4037 /* Use this after FETCH USING DESCRIPTOR one or more
4038 * result columns may contain NULLs. This routine is
4039 * not currently needed, since db/schema creates all
4040 * columns with a NOT NULL WITH DEFAULT clause.
4042 * This is currently dead flesh, since no Moira columns
4043 * allow null values; all use default values.
4045 mr_fix_nulls_in_SQLDA(da)
4048 register IISQLVAR *var;
4052 for(j=0, var=da->sqlvar; j<da->sqld; j++, var++) {
4053 switch(var->sqltype) {
4054 case -IISQ_CHA_TYPE:
4058 case -IISQ_INT_TYPE:
4060 intp=(int *)var->sqldata;
4068 /* prefetch_value():
4069 * This routine fetches an appropriate value from the numvalues table.
4070 * It is a little hack to get around the fact that SQL doesn't let you
4071 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
4073 * It is called from the query table as (*v->pre_rtn)(q,Argv,cl) or
4074 * from within a setup_...() routine with the appropriate arguments.
4076 * Correct functioning of this routine may depend on the assumption
4077 * that this query is an APPEND.
4080 prefetch_value(q,argv,cl)
4085 EXEC SQL BEGIN DECLARE SECTION;
4086 char *name = q->validate->object_id;
4088 EXEC SQL END DECLARE SECTION;
4089 int status, limit, argc;
4091 /* set next object id, limiting it if necessary */
4092 if(!strcmp(name, "uid") || !strcmp(name, "gid"))
4093 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
4096 if((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
4099 /* fetch object id */
4100 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name=:name;
4101 if(ingres_errno) return(mr_errcode);
4102 if(sqlca.sqlerrd[2] != 1) return(MR_INTERNAL);
4104 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
4105 sprintf(argv[argc],"%d",value); /** Could save this step by changing tlist from %s to %d **/
4110 /* prefetch_filesys():
4111 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
4112 * Appends the filsys_id and the phys_id to the argv so they can be
4113 * referenced in an INSERT into a table other than filesys. Also
4114 * see comments at prefetch_value().
4116 * Assumes the existence of a row where filsys_id = argv[0], since a
4117 * filesys label has already been resolved to a filsys_id.
4119 prefetch_filesys(q,argv,cl)
4124 EXEC SQL BEGIN DECLARE SECTION;
4126 EXEC SQL END DECLARE SECTION;
4129 fid = *(int *)argv[0];
4130 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
4131 if(ingres_errno) return(mr_errcode);
4133 argc=q->argc+q->vcnt;
4134 sprintf(argv[argc++],"%d",phid);
4135 sprintf(argv[argc],"%d",fid);
4140 /* Convert normal Unix-style wildcards to SQL voodoo */
4141 convert_wildcards(arg)
4144 static char buffer[QMAXARGSIZE];
4145 register char *s, *d;
4147 for(d=buffer,s=arg;*s;s++) {
4149 case '*': *d++='%'; *d++='%'; break;
4150 case '?': *d++='_'; break;
4153 case ']': *d++='*'; *d++ = *s; break;
4154 case '%': *d++='*'; *d++='%'; *d++='%'; break;
4155 default: *d++ = *s; break;
4160 /* Copy back into argv */
4166 /* This version includes uppercase conversion, for things like gmac.
4167 * This is necessary because "LIKE" doesn't work with "uppercase()".
4168 * Including it in a wildcard routine saves making two passes over
4169 * the argument string.
4171 convert_wildcards_uppercase(arg)
4174 static char buffer[QMAXARGSIZE];
4175 register char *s, *d;
4177 for(d=buffer,s=arg;*s;s++) {
4179 case '*': *d++='%'; *d++='%'; break;
4180 case '?': *d++='_'; break;
4183 case ']': *d++='*'; *d++ = *s; break;
4184 case '%': *d++='*'; *d++='%'; *d++='%'; break;
4185 default: *d++=toupper(*s); break; /* This is the only diff. */
4190 /* Copy back into argv */
4197 /* Looks like it's time to build an abstraction barrier, Yogi */
4199 EXEC SQL BEGIN DECLARE SECTION;
4201 EXEC SQL END DECLARE SECTION;
4205 EXEC SQL PREPARE stmt FROM :stmt;
4206 EXEC SQL DESCRIBE stmt INTO :SQLDA;
4207 if(SQLDA->sqld==0) /* Not a SELECT */
4208 return(MR_INTERNAL);
4209 EXEC SQL DECLARE csr CURSOR FOR stmt;
4211 EXEC SQL FETCH csr USING DESCRIPTOR :SQLDA;
4212 if(sqlca.sqlcode==0)
4214 else if((sqlca.sqlcode<0) && mr_errcode)
4230 fprintf(stderr, "Size: %d\n", strlen(p));
4231 while (strlen(p) >= 8) {
4232 fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
4233 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
4236 switch (strlen(p)) {
4238 fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x\n",
4239 p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
4242 fprintf(stderr, "%02x %02x %02x %02x %02x %02x\n",
4243 p[0], p[1], p[2], p[3], p[4], p[5]);
4246 fprintf(stderr, "%02x %02x %02x %02x %02x\n",
4247 p[0], p[1], p[2], p[3], p[4]);
4250 fprintf(stderr, "%02x %02x %02x %02x\n",
4251 p[0], p[1], p[2], p[3]);
4254 fprintf(stderr, "%02x %02x %02x\n",
4258 fprintf(stderr, "%02x %02x\n",
4262 fprintf(stderr, "%02x\n",
4270 /* eof:qsupport.dc */