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 1, 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 fs.tid 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; ) {
1527 sprintf(databuf, "%s:%s", argv[U_NAME], argv[U_MITID]);
1528 /* skip bytes for timestamp & kname */
1529 si.rawsig = (unsigned char *) rawsig;
1530 status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE], &si);
1531 if (strlen(rawsig) > mr_sig_length) {
1532 com_err(whoami, 0, "GDSS signature would be truncated."); /** untested **/
1533 return(MR_INTERNAL);
1536 name = kname_unparse(si.pname, si.pinst, si.prealm);
1537 status = name_to_id(name, "STRING", &sigwho);
1538 if (status == MR_NO_MATCH) {
1539 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1540 WHERE name='strings_id';
1542 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1543 WHERE name='strings_id';
1544 EXEC SQL INSERT INTO strings (string_id, string)
1545 VALUES (:sigwho, :name);
1548 timestamp = si.timestamp;
1550 if (log_flags & LOG_GDSS)
1551 hex_dump(argv[U_SIGNATURE]);
1552 return(gdss2et(status));
1562 who = cl->client_id;
1563 entity = cl->entity;
1565 /* create finger entry, pobox & set modtime on user */
1567 EXEC SQL REPEATED UPDATE users
1568 SET modtime='now', modby=:who, modwith = :entity,
1569 fullname = :fullname, affiliation = type,
1570 signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho,
1571 fmodtime='now', fmodby = :who, fmodwith = :entity,
1572 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1573 WHERE login = :login;
1575 EXEC SQL REPEATED UPDATE users
1576 SET modtime='now', modby=:who, modwith = :entity,
1577 fullname = :fullname, affiliation = type,
1578 fmodtime='now', fmodby = :who, fmodwith = :entity,
1579 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1580 WHERE login = :login;
1588 ** followup_uusr - do signature, set_user_modtime
1591 ** argv[0] - login (add_user)
1592 ** argv[U_SIGNATURE] - sig
1596 followup_uuac(q, argv, cl)
1601 EXEC SQL BEGIN DECLARE SECTION;
1602 int who, status, id;
1603 char *entity, *name, *src, *dst;
1604 EXEC SQL END DECLARE SECTION;
1606 char databuf[32], *kname_unparse();
1607 EXEC SQL BEGIN DECLARE SECTION;
1610 int sigwho, timestamp;
1611 EXEC SQL END DECLARE SECTION;
1615 id = *(int *)argv[0];
1616 who = cl->client_id;
1617 entity = cl->entity;
1620 if (q->vcnt == U_MODTIME && *argv[U_SIGNATURE + 1]) {
1621 /* unquote ' chars in signature */
1622 for (dst = src = argv[U_SIGNATURE+1]; *src; ) {
1629 status = id_to_name(id, "USER", &login);
1630 sprintf(databuf, "%s:%s", login, argv[U_MITID+1]);
1632 /* skip bytes for timestamp & kname */
1633 si.rawsig = (unsigned char *) rawsig;
1635 com_err(whoami, 0, "verifying sig");
1637 status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE+1], &si);
1639 com_err(whoami, 0, "verified");
1641 if (strlen(rawsig) > mr_sig_length) {
1642 com_err(whoami, 0, "GDSS signature would be truncated."); /** untested **/
1643 return(MR_INTERNAL);
1646 name = kname_unparse(si.pname, si.pinst, si.prealm);
1647 status = name_to_id(name, "STRING", &sigwho);
1648 if (status == MR_NO_MATCH) {
1649 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1650 WHERE name='strings_id';
1652 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1653 WHERE name='strings_id';
1654 EXEC SQL INSERT INTO strings (string_id, string)
1655 VALUES (:sigwho, :name);
1658 timestamp = si.timestamp;
1660 if (log_flags & LOG_GDSS)
1661 hex_dump(argv[U_SIGNATURE+1]);
1662 return(gdss2et(status));
1671 /* create finger entry, pobox & set modtime on user */
1674 EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity,
1675 signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho
1676 WHERE users_id = :id;
1678 EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity
1679 WHERE users_id = :id;
1685 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1686 * type in argv[1]. Then completes the upcall to the user.
1688 * argv[2] is of the form "123:234" where the first integer is the machine
1689 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1690 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1694 followup_gpob(q, sq, v, action, actarg, cl)
1695 register struct query *q;
1696 register struct save_queue *sq;
1697 register struct validate *v;
1698 register int (*action)();
1702 char **argv, *index();
1704 int mid, sid, status, i;
1707 while (sq_get_data(sq, &argv)) {
1708 mr_trim_args(2, argv);
1710 p = index(argv[2], ':');
1712 mid = atoi(argv[2]);
1715 if (!strcmp(ptype, "POP")) {
1716 status = id_to_name(mid, "MACHINE", &argv[2]);
1717 if (status == MR_NO_MATCH)
1719 } else if (!strcmp(ptype, "SMTP")) {
1720 status = id_to_name(sid, "STRING", &argv[2]);
1721 if (status == MR_NO_MATCH)
1723 } else /* ptype == "NONE" */ {
1726 if (status) return(status);
1728 if (!strcmp(q->shortname, "gpob")) {
1729 sid = atoi(argv[4]);
1731 status = id_to_name(sid, "USER", &argv[4]);
1733 status = id_to_name(-sid, "STRING", &argv[4]);
1735 if (status && status != MR_NO_MATCH) return(status);
1737 (*action)(q->vcnt, argv, actarg);
1739 /* free saved data */
1740 for (i = 0; i < q->vcnt; i++)
1746 return (MR_SUCCESS);
1750 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1751 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1752 * proper name based on the type, and repace that string in the argv.
1753 * Also fixes the modby field by called followup_fix_modby.
1756 followup_glin(q, sq, v, action, actarg, cl)
1757 register struct query *q;
1758 register struct save_queue *sq;
1759 register struct validate *v;
1760 register int (*action)();
1764 char **argv, *malloc(), *realloc(), *type;
1765 int id, i, idx, status;
1768 if (!strcmp(q->shortname, "gsin"))
1771 while (sq_get_data(sq, &argv)) {
1772 mr_trim_args(q->vcnt, argv);
1774 id = atoi(argv[i = q->vcnt - 2]);
1776 status = id_to_name(id, "USER", &argv[i]);
1778 status = id_to_name(-id, "STRING", &argv[i]);
1779 if (status && status != MR_NO_MATCH)
1782 id = atoi(argv[idx]);
1783 type = argv[idx - 1];
1785 if (!strcmp(type, "LIST")) {
1786 status = id_to_name(id, "LIST", &argv[idx]);
1787 } else if (!strcmp(type, "USER")) {
1788 status = id_to_name(id, "USER", &argv[idx]);
1789 } else if (!strcmp(type, "KERBEROS")) {
1790 status = id_to_name(id, "STRING", &argv[idx]);
1791 } else if (!strcmp(type, "NONE")) {
1794 argv[idx] = strsave("NONE");
1798 argv[idx] = strsave("???");
1800 if (status && status != MR_NO_MATCH)
1803 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1804 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1805 strcpy(argv[6], UNIQUE_GID);
1809 (*action)(q->vcnt, argv, actarg);
1811 /* free saved data */
1812 for (i = 0; i < q->vcnt; i++)
1818 return (MR_SUCCESS);
1822 /* followup_gqot: Fix the entity name, directory name & modby fields
1823 * argv[0] = filsys_id
1825 * argv[2] = entity_id
1826 * argv[3] = ascii(quota)
1829 followup_gqot(q, sq, v, action, actarg, cl)
1831 register struct save_queue *sq;
1833 register int (*action)();
1834 register int actarg;
1838 char **argv, *malloc();
1839 EXEC SQL BEGIN DECLARE SECTION;
1842 EXEC SQL END DECLARE SECTION;
1845 if (!strcmp(q->name, "get_quota") ||
1846 !strcmp(q->name, "get_quota_by_filesys"))
1850 while (sq_get_data(sq, &argv)) {
1852 switch (argv[1][0]) {
1854 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1858 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1862 argv[2] = strsave("system:anyuser");
1866 argv[2] = malloc(8);
1867 sprintf(argv[2], "%d", id);
1870 id = atoi(argv[idx]);
1872 argv[idx] = malloc(256);
1876 EXEC SQL REPEATED SELECT name INTO :name FROM filesys
1877 WHERE label = :label;
1879 EXEC SQL REPEATED SELECT dir INTO :name FROM nfsphys
1880 WHERE nfsphys_id = :id;
1882 if (sqlca.sqlerrd[2] != 1) {
1883 sprintf(argv[idx], "#%d", id);
1886 id = atoi(argv[idx+3]);
1888 status = id_to_name(id, "USER", &argv[idx+3]);
1890 status = id_to_name(-id, "STRING", &argv[idx+3]);
1891 if (status && status != MR_NO_MATCH)
1893 (*action)(q->vcnt, argv, actarg);
1894 for (j = 0; j < q->vcnt; j++)
1903 /* followup_aqot: Add allocation to nfsphys after creating quota.
1904 * argv[0] = filsys_id
1905 * argv[1] = type if "add_quota" or "update_quota"
1907 * argv[3 or 2] = ascii(quota)
1910 followup_aqot(q, argv, cl)
1915 EXEC SQL BEGIN DECLARE SECTION;
1916 int quota, id, fs, who, physid;
1917 char *entity, *qtype, *table_name;
1918 EXEC SQL END DECLARE SECTION;
1923 table_name=q->rtable;
1924 fs = *(int *)argv[0];
1925 EXEC SQL REPEATED SELECT phys_id INTO :physid FROM filesys
1926 WHERE filsys_id = :fs;
1930 if (!strcmp(q->shortname, "aqot") || !strcmp(q->shortname, "uqot")) {
1932 id = *(int *)argv[2];
1933 quota = atoi(argv[3]);
1934 sprintf(incr_qual,"q.filsys_id = %d",fs);
1937 id = *(int *)argv[1];
1938 quota = atoi(argv[2]);
1939 sprintf(incr_qual,"q.filsys_id=%d AND q.type='%s' AND q.entity_id=%d",
1943 /* quota case of incremental_{before|after} only looks at slot 1 */
1946 /* Follows one of many possible gross hacks to fix these particular
1947 * conflicts between what is possible in the query table and what
1948 * is possible in SQL.
1950 if(q->type==APPEND) {
1951 incremental_clear_before();
1952 EXEC SQL INSERT INTO quota
1953 (filsys_id, type, entity_id, quota, phys_id)
1954 VALUES (:fs, :qtype, :id, :quota, :physid);
1955 incremental_after(table_name, incr_qual, incr_argv);
1957 incremental_before(table_name, incr_qual, incr_argv);
1958 EXEC SQL UPDATE quota SET quota = :quota
1959 WHERE filsys_id = :fs AND type = :qtype AND entity_id = :id;
1960 status = mr_errcode;
1961 incremental_after(table_name, incr_qual, incr_argv);
1966 flush_name(argv[0], q->rtable);
1967 if(q->type==APPEND) {
1968 EXEC SQL UPDATE tblstats SET appends = appends + 1, modtime = 'now'
1969 WHERE table_name = :table_name;
1971 EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = 'now'
1972 WHERE table_name = :table_name;
1975 /* Proceed with original followup */
1976 who = cl->client_id;
1977 entity = cl->entity;
1979 EXEC SQL REPEATED UPDATE quota
1980 SET modtime = 'now', modby = :who, modwith = :entity
1981 WHERE filsys_id = :fs and type = :qtype and entity_id = :id;
1982 EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated + :quota
1983 WHERE nfsphys_id = :physid;
1984 if (ingres_errno) return(mr_errcode);
1989 /* Necessitated by the requirement of a correlation name by the incremental
1990 * routines, since query table deletes don't provide one.
1992 followup_dqot(q,argv,cl)
2000 EXEC SQL BEGIN DECLARE SECTION;
2003 EXEC SQL END DECLARE SECTION;
2005 fs = *(int *)argv[0];
2006 if (!strcmp(q->shortname, "dqot")) {
2008 id = *(int *)argv[2];
2011 id = *(int *)argv[1];
2013 sprintf(incr_qual,"q.filsys_id=%d AND q.type='%s' AND q.entity_id=%d",
2016 /* quota case of incremental_{before|after} only looks at slot 1 */
2019 incremental_before(q->rtable, incr_qual, incr_argv);
2020 EXEC SQL DELETE FROM quota q WHERE :incr_qual;
2021 incremental_clear_after();
2025 flush_name(argv[0], q->rtable);
2027 tblname = q->rtable;
2028 EXEC SQL UPDATE tblstats SET deletes = deletes + 1, modtime = 'now'
2029 WHERE table_name = :tblname;
2034 followup_gpce(q, sq, v, action, actarg, cl)
2036 register struct save_queue *sq;
2038 register int (*action)();
2039 register int actarg;
2043 char **argv, *malloc();
2047 while (sq_get_data(sq, &argv)) {
2048 id = atoi(argv[PCAP_QSERVER]);
2049 status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
2050 if (status) return (status);
2053 status = id_to_name(id, "USER", &argv[i]);
2055 status = id_to_name(-id, "STRING", &argv[i]);
2056 if (status && status != MR_NO_MATCH)
2058 (*action)(q->vcnt, argv, actarg);
2059 for (j = 0; j < q->vcnt; j++)
2071 followup_gzcl(q, sq, v, action, actarg, cl)
2072 register struct query *q;
2073 register struct save_queue *sq;
2074 register struct validate *v;
2075 register int (*action)();
2082 while (sq_get_data(sq, &argv)) {
2083 mr_trim_args(q->vcnt, argv);
2085 id = atoi(argv[i = q->vcnt - 2]);
2087 status = id_to_name(id, "USER", &argv[i]);
2089 status = id_to_name(-id, "STRING", &argv[i]);
2090 if (status && status != MR_NO_MATCH)
2093 for (i = 1; i < 8; i+=2) {
2094 id = atoi(argv[i+1]);
2095 if (!strcmp(argv[i], "LIST")) {
2096 status = id_to_name(id, "LIST", &argv[i+1]);
2097 } else if (!strcmp(argv[i], "USER")) {
2098 status = id_to_name(id, "USER", &argv[i+1]);
2099 } else if (!strcmp(argv[i], "KERBEROS")) {
2100 status = id_to_name(id, "STRING", &argv[i+1]);
2101 } else if (!strcmp(argv[i], "NONE")) {
2104 argv[i+1] = strsave("NONE");
2108 argv[i+1] = strsave("???");
2110 if (status && status != MR_NO_MATCH)
2115 (*action)(q->vcnt, argv, actarg);
2117 /* free saved data */
2118 for (i = 0; i < q->vcnt; i++)
2130 followup_gsha(q, sq, v, action, actarg, cl)
2131 register struct query *q;
2132 register struct save_queue *sq;
2133 register struct validate *v;
2134 register int (*action)();
2141 while (sq_get_data(sq, &argv)) {
2142 mr_trim_args(q->vcnt, argv);
2146 status = id_to_name(id, "USER", &argv[4]);
2148 status = id_to_name(-id, "STRING", &argv[4]);
2149 if (status && status != MR_NO_MATCH)
2153 if (!strcmp(argv[1], "LIST")) {
2154 status = id_to_name(id, "LIST", &argv[2]);
2155 } else if (!strcmp(argv[1], "USER")) {
2156 status = id_to_name(id, "USER", &argv[2]);
2157 } else if (!strcmp(argv[1], "KERBEROS")) {
2158 status = id_to_name(id, "STRING", &argv[2]);
2159 } else if (!strcmp(argv[1], "NONE")) {
2162 argv[2] = strsave("NONE");
2166 argv[2] = strsave("???");
2168 if (status && status != MR_NO_MATCH)
2172 (*action)(q->vcnt, argv, actarg);
2174 /* free saved data */
2175 for (i = 0; i < q->vcnt; i++)
2185 /* Special query routines */
2187 /* set_pobox - this does all of the real work.
2188 * argv = user_id, type, box
2189 * if type is POP, then box should be a machine, and its ID should be put in
2190 * pop_id. If type is SMTP, then box should be a string and its ID should
2191 * be put in box_id. If type is NONE, then box doesn't matter.
2194 int set_pobox(q, argv, cl)
2199 EXEC SQL BEGIN DECLARE SECTION;
2201 char *box, potype[9];
2202 EXEC SQL END DECLARE SECTION;
2206 user = *(int *)argv[0];
2208 EXEC SQL REPEATED SELECT pop_id, potype INTO :id, :potype FROM users
2209 WHERE users_id = :user;
2210 if (ingres_errno) return(mr_errcode);
2211 if (!strcmp(strtrim(potype), "POP"))
2212 set_pop_usage(id, -1);
2214 if (!strcmp(argv[1], "POP")) {
2215 status = name_to_id(box, "MACHINE", &id);
2216 if (status == MR_NO_MATCH)
2220 EXEC SQL REPEATED UPDATE users SET potype = 'POP', pop_id = :id
2221 WHERE users_id = :user;
2222 set_pop_usage(id, 1);
2223 } else if (!strcmp(argv[1], "SMTP")) {
2224 if (index(box, '/') || index(box, '|'))
2225 return(MR_BAD_CHAR);
2226 status = name_to_id(box, "STRING", &id);
2227 if (status == MR_NO_MATCH) {
2228 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
2229 WHERE name='strings_id';
2231 EXEC SQL REPEATED UPDATE numvalues SET value = :id
2232 WHERE name='strings_id';
2233 EXEC SQL INSERT INTO strings (string_id, string)
2237 EXEC SQL REPEATED UPDATE users SET potype='SMTP', box_id = :id
2238 WHERE users_id = :user;
2239 } else /* argv[1] == "NONE" */ {
2240 EXEC SQL REPEATED UPDATE users SET potype='NONE'
2241 WHERE users_id = :user;
2244 set_pobox_modtime(q, argv, cl);
2245 EXEC SQL REPEATED UPDATE tblstats SET updates = updates+1, modtime='now'
2246 WHERE table_name='users';
2247 if (ingres_errno) return(mr_errcode);
2252 /* get_list_info: passed a wildcard list name, returns lots of stuff about
2253 * each list. This is tricky: first build a queue of all requested
2254 * data. Rest of processing consists of fixing gid, ace_name, and modby.
2257 get_list_info(q, aargv, cl, action, actarg)
2258 register struct query *q;
2261 register int (*action)();
2264 char *argv[13], *malloc(), *realloc();
2265 EXEC SQL BEGIN DECLARE SECTION;
2266 char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
2267 char maillist[5], grouplist[5], gid_str[6], acl_name[256], desc[256];
2268 char modtime[27], modby[256], modwith[9];
2269 int id, rowcount, acl_id, hid, modby_id;
2271 EXEC SQL END DECLARE SECTION;
2272 int returned, status;
2273 struct save_queue *sq, *sq_create();
2275 returned = rowcount = 0;
2277 convert_wildcards(name);
2280 sprintf(qual,"name LIKE '%s' ESCAPE '*'",name);
2281 optimize_sql_stmt(qual);
2282 EXEC SQL DECLARE csr102 CURSOR FOR SELECT list_id FROM list
2284 EXEC SQL OPEN csr102;
2287 EXEC SQL FETCH csr102 INTO :id;
2288 if(sqlca.sqlcode!=0) break;
2289 sq_save_data(sq, id);
2292 EXEC SQL CLOSE csr102;
2294 if (ingres_errno) return(mr_errcode);
2296 return(MR_NO_MATCH);
2298 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
2299 argv[4] = maillist; argv[5] = grouplist; argv[6] = gid_str;
2300 argv[7] = acl_type; argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
2302 while (sq_get_data(sq, &id)) {
2306 EXEC SQL REPEATED SELECT name, CHAR(active), CHAR(publicflg),
2307 CHAR(hidden), hidden, CHAR(maillist), CHAR(grouplist), CHAR(gid),
2308 TRIM(acl_type), acl_id, description, CHAR(modtime), modby, modwith
2309 INTO :listname, :active, :public, :hidden, :hid, :maillist,
2310 :grouplist, :gid_str, :acl_type, :acl_id, :desc,
2311 :modtime, :modby_id, :modwith
2312 FROM list WHERE list_id = :id;
2314 if (ingres_errno) return(mr_errcode);
2316 if (atoi(gid_str) == -1)
2317 argv[6] = UNIQUE_GID;
2319 argv[8] = malloc(0);
2320 if (!strcmp(acl_type, "LIST")) {
2321 status = id_to_name(acl_id, "LIST", &argv[8]);
2322 } else if (!strcmp(acl_type, "USER")) {
2323 status = id_to_name(acl_id, "USER", &argv[8]);
2324 } else if (!strcmp(acl_type, "KERBEROS")) {
2325 status = id_to_name(acl_id, "STRING", &argv[8]);
2326 } else if (!strcmp(acl_type, "NONE")) {
2329 argv[8] = strsave("NONE");
2333 argv[8] = strsave("???");
2335 if (status && status != MR_NO_MATCH) return(status);
2337 argv[11] = malloc(0);
2339 status = id_to_name(modby_id, "USER", &argv[11]);
2341 status = id_to_name(-modby_id, "STRING", &argv[11]);
2342 if (status && status != MR_NO_MATCH) return(status);
2344 mr_trim_args(q->vcnt, argv);
2346 (*action)(q->vcnt, argv, actarg);
2352 if (ingres_errno) return(mr_errcode);
2353 return (MR_SUCCESS);
2357 /* Add_member_to_list: do list flattening as we go! MAXLISTDEPTH is
2358 * how many different ancestors a member is allowed to have.
2361 #define MAXLISTDEPTH 1024
2363 int add_member_to_list(q, argv, cl)
2368 EXEC SQL BEGIN DECLARE SECTION;
2369 int id, lid, mid, error, who, ref, rowcnt;
2370 char *mtype, dtype[9], *entity;
2371 EXEC SQL END DECLARE SECTION;
2372 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2373 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2375 char *dtypes[MAXLISTDEPTH];
2376 char *iargv[3], *buf;
2378 lid = *(int *)argv[0];
2380 mid = *(int *)argv[2];
2381 /* if the member is already a direct member of the list, punt */
2382 EXEC SQL REPEATED SELECT COUNT(list_id) INTO :rowcnt FROM imembers
2383 WHERE list_id = :lid AND member_id = :mid
2384 AND member_type = :mtype AND direct = 1;
2387 if (!strcasecmp(mtype, "STRING")) {
2389 status = id_to_name(mid, "STRING", &buf);
2390 if (status) return(status);
2391 if (index(buf, '/') || index(buf, '|')) {
2393 return(MR_BAD_CHAR);
2401 EXEC SQL DECLARE csr103 CURSOR FOR
2402 SELECT list_id, ref_count FROM imembers
2403 WHERE member_id = :lid AND member_type='LIST';
2404 EXEC SQL OPEN csr103;
2406 EXEC SQL FETCH csr103 INTO :id, :ref;
2407 if(sqlca.sqlcode != 0) break;
2409 ancestors[acount++] = id;
2410 if (acount >= MAXLISTDEPTH) break;
2412 EXEC SQL CLOSE csr103;
2413 if (ingres_errno) return(mr_errcode);
2414 if (acount >= MAXLISTDEPTH) {
2415 return(MR_INTERNAL);
2417 descendants[0] = mid;
2422 if (!strcmp(mtype, "LIST")) {
2423 EXEC SQL DECLARE csr104 CURSOR FOR
2424 SELECT member_id, member_type, ref_count
2426 WHERE list_id = :mid;
2427 EXEC SQL OPEN csr104;
2429 EXEC SQL FETCH csr104 INTO :id, :dtype, :ref;
2430 if(sqlca.sqlcode != 0) break;
2433 dtypes[dcount] = "LIST";
2436 dtypes[dcount] = "USER";
2439 dtypes[dcount] = "STRING";
2442 dtypes[dcount] = "KERBEROS";
2449 descendants[dcount++] = id;
2450 if (dcount >= MAXLISTDEPTH) {
2455 EXEC SQL CLOSE csr104;
2456 if (ingres_errno) return(mr_errcode);
2458 return(MR_INTERNAL);
2460 for (a = 0; a < acount; a++) {
2462 for (d = 0; d < dcount; d++) {
2463 mid = descendants[d];
2465 if (mid == lid && !strcmp(mtype, "LIST")) {
2466 return(MR_LISTLOOP);
2468 EXEC SQL REPEATED SELECT COUNT(ref_count) INTO :rowcnt
2470 WHERE list_id = :lid AND member_id = :mid
2471 AND member_type = :mtype;
2472 ref = aref[a] * dref[d];
2474 if (a == 0 && d == 0) {
2475 EXEC SQL UPDATE imembers
2476 SET ref_count = ref_count+:ref, direct=1
2477 WHERE list_id = :lid AND member_id = :mid
2478 AND member_type = :mtype;
2480 EXEC SQL UPDATE imembers
2481 SET ref_count = ref_count+:ref
2482 WHERE list_id = :lid AND member_id = :mid
2483 AND member_type = :mtype;
2486 incremental_clear_before();
2487 if (a == 0 && d == 0) {
2488 EXEC SQL INSERT INTO imembers
2489 (list_id, member_id, direct, member_type, ref_count)
2490 VALUES (:lid, :mid, 1, :mtype, 1);
2492 EXEC SQL INSERT INTO imembers
2493 (list_id, member_id, member_type, ref_count)
2494 VALUES (:lid, :mid, :mtype, 1);
2496 iargv[0] = (char *)lid;
2498 iargv[2] = (char *)mid;
2499 incremental_after("members", 0, iargv);
2503 lid = *(int *)argv[0];
2504 entity = cl->entity;
2505 who = cl->client_id;
2506 EXEC SQL REPEATED UPDATE list
2507 SET modtime='now', modby = :who, modwith = :entity
2508 WHERE list_id = :lid;
2509 if (ingres_errno) return(mr_errcode);
2514 /* Delete_member_from_list: do list flattening as we go!
2517 int delete_member_from_list(q, argv, cl)
2522 EXEC SQL BEGIN DECLARE SECTION;
2523 int id, lid, mid, cnt, error, who, ref;
2524 char *mtype, dtype[9], *entity;
2525 EXEC SQL END DECLARE SECTION;
2526 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2527 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2528 char *dtypes[MAXLISTDEPTH];
2531 lid = *(int *)argv[0];
2533 mid = *(int *)argv[2];
2534 /* if the member is not a direct member of the list, punt */
2535 EXEC SQL REPEATED SELECT COUNT(list_id) INTO :cnt FROM imembers
2536 WHERE list_id = :lid AND member_id = :mid
2537 AND member_type = :mtype AND direct = 1;
2538 if (ingres_errno) return(mr_errcode);
2540 return(MR_NO_MATCH);
2544 EXEC SQL DECLARE csr105 CURSOR FOR
2545 SELECT list_id, ref_count FROM imembers
2546 WHERE member_id = :lid AND member_type = 'LIST';
2547 EXEC SQL OPEN csr105;
2549 EXEC SQL FETCH csr105 INTO :id, :ref;
2550 if(sqlca.sqlcode!=0) break;
2552 ancestors[acount++] = id;
2553 if (acount >= MAXLISTDEPTH) break;
2555 EXEC SQL CLOSE csr105;
2558 if (acount >= MAXLISTDEPTH)
2559 return(MR_INTERNAL);
2560 descendants[0] = mid;
2565 if (!strcmp(mtype, "LIST")) {
2566 EXEC SQL DECLARE csr106 CURSOR FOR
2567 SELECT member_id, member_type, ref_count FROM imembers
2568 WHERE list_id = :mid;
2569 EXEC SQL OPEN csr106;
2571 EXEC SQL FETCH csr106 INTO :id, :dtype, :ref;
2572 if(sqlca.sqlcode!=0) break;
2575 dtypes[dcount] = "LIST";
2578 dtypes[dcount] = "USER";
2581 dtypes[dcount] = "STRING";
2584 dtypes[dcount] = "KERBEROS";
2591 descendants[dcount++] = id;
2592 if (dcount >= MAXLISTDEPTH) break;
2594 EXEC SQL CLOSE csr106;
2598 return(MR_INTERNAL);
2600 for (a = 0; a < acount; a++) {
2602 for (d = 0; d < dcount; d++) {
2603 mid = descendants[d];
2605 if (mid == lid && !strcmp(mtype, "LIST")) {
2606 return(MR_LISTLOOP);
2608 EXEC SQL REPEATED SELECT ref_count INTO :cnt FROM imembers
2609 WHERE list_id = :lid AND member_id = :mid AND member_type = :mtype;
2610 ref = aref[a] * dref[d];
2612 iargv[0] = (char *)lid;
2614 iargv[2] = (char *)mid;
2615 incremental_before("members", 0, iargv);
2616 EXEC SQL DELETE FROM imembers
2617 WHERE list_id = :lid AND member_id = :mid
2618 AND member_type= :mtype;
2619 incremental_clear_after();
2620 } else if (a == 0 && d == 0) {
2621 EXEC SQL UPDATE imembers
2622 SET ref_count = ref_count - :ref, direct = 0
2623 WHERE list_id = :lid AND member_id = :mid
2624 AND member_type = :mtype;
2626 EXEC SQL UPDATE imembers
2627 SET ref_count = ref_count - :ref
2628 WHERE list_id = :lid AND member_id = :mid
2629 AND member_type = :mtype;
2633 lid = *(int *)argv[0];
2634 entity = cl->entity;
2635 who = cl->client_id;
2636 EXEC SQL UPDATE list SET modtime = 'now', modby = :who, modwith = :entity
2637 WHERE list_id = :lid;
2638 if (ingres_errno) return(mr_errcode);
2643 /* get_ace_use - given a type and a name, return a type and a name.
2644 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2645 * and argv[1] will contain the ID of the entity in question. The R*
2646 * types mean to recursively look at every containing list, not just
2647 * when the object in question is a direct member. On return, the
2648 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2651 int get_ace_use(q, argv, cl, action, actarg)
2659 EXEC SQL BEGIN DECLARE SECTION;
2661 int aid, listid, id;
2662 EXEC SQL END DECLARE SECTION;
2663 struct save_queue *sq, *sq_create();
2666 aid = *(int *)argv[1];
2667 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2668 !strcmp(atype, "KERBEROS")) {
2669 return(get_ace_internal(atype, aid, action, actarg));
2673 if (!strcmp(atype, "RLIST")) {
2674 sq_save_data(sq, aid);
2675 /* get all the list_id's of containing lists */
2676 EXEC SQL DECLARE csr107 CURSOR FOR
2677 SELECT list_id FROM imembers
2678 WHERE member_type='LIST' AND member_id = :aid;
2679 EXEC SQL OPEN csr107;
2681 EXEC SQL FETCH csr107 INTO :listid;
2682 if(sqlca.sqlcode != 0) break;
2683 sq_save_unique_data(sq, listid);
2685 EXEC SQL CLOSE csr107;
2686 /* now process each one */
2687 while (sq_get_data(sq, &id)) {
2688 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2693 if (!strcmp(atype, "RUSER")) {
2694 EXEC SQL DECLARE csr108 CURSOR FOR
2695 SELECT list_id FROM imembers
2696 WHERE member_type='USER' AND member_id = :aid;
2697 EXEC SQL OPEN csr108;
2699 EXEC SQL FETCH csr108 INTO :listid;
2700 if(sqlca.sqlcode != 0) break;
2701 sq_save_data(sq, listid);
2703 EXEC SQL CLOSE csr108;
2704 /* now process each one */
2705 while (sq_get_data(sq, &id)) {
2706 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2709 if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2713 if (!strcmp(atype, "RKERBERO")) {
2714 EXEC SQL DECLARE csr109 CURSOR FOR
2715 SELECT list_id FROM imembers
2716 WHERE member_type='KERBEROS' AND member_id = :aid;
2717 EXEC SQL OPEN csr109;
2719 EXEC SQL FETCH csr109 INTO :listid;
2720 if(sqlca.sqlcode != 0) break;
2721 sq_save_data(sq, listid);
2723 EXEC SQL CLOSE csr109;
2724 /* now process each one */
2725 while (sq_get_data(sq, &id)) {
2726 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2729 if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2734 if (ingres_errno) return(mr_errcode);
2735 if (!found) return(MR_NO_MATCH);
2740 /* This looks up a single list or user for ace use. atype must be "USER"
2741 * or "LIST", and aid is the ID of the corresponding object. This is used
2742 * by get_ace_use above.
2745 get_ace_internal(atype, aid, action, actarg)
2746 EXEC SQL BEGIN DECLARE SECTION;
2749 EXEC SQL END DECLARE SECTION;
2755 EXEC SQL BEGIN DECLARE SECTION;
2757 EXEC SQL END DECLARE SECTION;
2760 if (!strcmp(atype, "LIST")) {
2761 rargv[0] = "FILESYS";
2762 EXEC SQL DECLARE csr110 CURSOR FOR
2763 SELECT label FROM filesys
2764 WHERE owners = :aid;
2765 EXEC SQL OPEN csr110;
2767 EXEC SQL FETCH csr110 INTO :name;
2768 if(sqlca.sqlcode != 0) break;
2769 (*action)(2, rargv, actarg);
2772 EXEC SQL CLOSE csr110;
2775 EXEC SQL DECLARE csr111 CURSOR FOR
2776 SELECT capability FROM capacls
2777 WHERE list_id = :aid ;
2778 EXEC SQL OPEN csr111;
2780 EXEC SQL FETCH csr111 INTO :name ;
2781 if(sqlca.sqlcode != 0) break;
2782 (*action)(2, rargv, actarg);
2785 EXEC SQL CLOSE csr111;
2786 } else if (!strcmp(atype, "USER")) {
2787 rargv[0] = "FILESYS";
2788 EXEC SQL DECLARE csr112 CURSOR FOR
2789 SELECT label FROM filesys
2791 EXEC SQL OPEN csr112;
2793 EXEC SQL FETCH csr112 INTO :name ;
2794 if(sqlca.sqlcode != 0) break;
2795 (*action)(2, rargv, actarg);
2798 EXEC SQL CLOSE csr112;
2802 EXEC SQL DECLARE csr113 CURSOR FOR
2803 SELECT name FROM list
2804 WHERE acl_type = :atype AND acl_id = :aid;
2805 EXEC SQL OPEN csr113;
2807 EXEC SQL FETCH csr113 INTO :name;
2808 if(sqlca.sqlcode != 0) break;
2809 (*action)(2, rargv, actarg);
2812 EXEC SQL CLOSE csr113;
2814 rargv[0] = "SERVICE";
2815 EXEC SQL DECLARE csr114 CURSOR FOR
2816 SELECT name FROM servers
2817 WHERE acl_type = :atype AND acl_id = :aid;
2818 EXEC SQL OPEN csr114;
2820 EXEC SQL FETCH csr114 INTO :name;
2821 if(sqlca.sqlcode != 0) break;
2822 (*action)(2, rargv, actarg);
2825 EXEC SQL CLOSE csr114;
2827 rargv[0] = "HOSTACCESS";
2828 EXEC SQL DECLARE csr115 CURSOR FOR
2829 SELECT name FROM machine m, hostaccess ha
2830 WHERE m.mach_id = ha.mach_id AND ha.acl_type = :atype
2831 AND ha.acl_id = :aid;
2832 EXEC SQL OPEN csr115;
2834 EXEC SQL FETCH csr115 INTO :name;
2835 if(sqlca.sqlcode != 0) break;
2836 (*action)(2, rargv, actarg);
2839 EXEC SQL CLOSE csr115;
2841 rargv[0] = "ZEPHYR";
2842 EXEC SQL DECLARE csr116 CURSOR FOR
2843 SELECT class FROM zephyr z
2844 WHERE z.xmt_type = :atype AND z.xmt_id = :aid
2845 OR z.sub_type = :atype AND z.sub_id = :aid
2846 OR z.iws_type = :atype AND z.iws_id = :aid
2847 OR z.iui_type = :atype AND z.iui_id = :aid;
2848 EXEC SQL OPEN csr116;
2850 EXEC SQL FETCH csr116 INTO :name;
2851 if(sqlca.sqlcode != 0) break;
2852 (*action)(2, rargv, actarg);
2855 EXEC SQL CLOSE csr116;
2857 if (!found) return(MR_NO_MATCH);
2862 /* get_lists_of_member - given a type and a name, return the name and flags
2863 * of all of the lists of the given member. The member_type is one of
2864 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2865 * and argv[1] will contain the ID of the entity in question. The R*
2866 * types mean to recursively look at every containing list, not just
2867 * when the object in question is a direct member.
2870 int get_lists_of_member(q, argv, cl, action, actarg)
2877 int found = 0, direct = 1;
2879 EXEC SQL BEGIN DECLARE SECTION;
2881 int aid, listid, id;
2882 char name[33], active[5], public[5], hidden[5], maillist[5], grouplist[5];
2883 EXEC SQL END DECLARE SECTION;
2886 aid = *(int *)argv[1];
2887 if (!strcmp(atype, "RLIST")) {
2891 if (!strcmp(atype, "RUSER")) {
2895 if (!strcmp(atype, "RSTRING")) {
2899 if (!strcmp(atype, "RKERBEROS")) {
2908 rargv[4] = maillist;
2909 rargv[5] = grouplist;
2911 EXEC SQL DECLARE csr117a CURSOR FOR
2912 SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2913 CHAR(l.maillist), CHAR(l.grouplist)
2914 FROM list l, imembers im
2915 WHERE l.list_id = im.list_id AND im.direct = 1
2916 AND im.member_type = :atype AND im.member_id = :aid;
2917 EXEC SQL OPEN csr117a;
2919 EXEC SQL FETCH csr117a
2920 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2921 if(sqlca.sqlcode != 0) break;
2922 (*action)(6, rargv, actarg);
2925 EXEC SQL CLOSE csr117a;
2927 EXEC SQL DECLARE csr117b CURSOR FOR
2928 SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2929 CHAR(l.maillist), CHAR(l.grouplist)
2930 FROM list l, imembers im
2931 WHERE l.list_id = im.list_id
2932 AND im.member_type = :atype AND im.member_id = :aid;
2933 EXEC SQL OPEN csr117b;
2935 EXEC SQL FETCH csr117b
2936 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2937 if(sqlca.sqlcode != 0) break;
2938 (*action)(6, rargv, actarg);
2941 EXEC SQL CLOSE csr117b;
2944 if (ingres_errno) return(mr_errcode);
2945 if (!found) return(MR_NO_MATCH);
2950 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2951 * the five flags associated with each list. It will return the name of
2952 * each list that meets the quailifications. It does this by building a
2953 * where clause based on the arguments, then doing a retrieve.
2956 static char *lflags[5] = { "active", "publicflg", "hidden", "maillist", "grouplist" };
2958 int qualified_get_lists(q, argv, cl, action, actarg)
2965 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2966 "l", "name", lflags));
2970 /* get_members_of_list - this gets only direct members */
2972 get_members_of_list(q, argv, cl, action, actarg)
2979 return(gmol_internal(q, argv, cl, action, actarg, 1));
2982 /* get_end_members_of_list - this gets direct or indirect members */
2984 get_end_members_of_list(q, argv, cl, action, actarg)
2991 return(gmol_internal(q, argv, cl, action, actarg, 0));
2994 /** gmol_internal - optimized query for retrieval of list members
2995 ** used by both get_members_of_list and get_end_members_of_list
2998 ** argv[0] - list_id
3001 ** - retrieve USER members, then LIST members, then STRING members
3004 gmol_internal(q, argv, cl, action, actarg, flag)
3012 EXEC SQL BEGIN DECLARE SECTION;
3013 int list_id, member_id, direct;
3014 char member_name[129], member_type[9];
3015 EXEC SQL END DECLARE SECTION;
3018 struct save_queue *sq;
3020 /* true/false flag indicates whether to display only direct members. */
3026 list_id = *(int *)argv[0];
3030 EXEC SQL DECLARE csr118 CURSOR FOR
3031 SELECT member_type, member_id FROM imembers
3032 WHERE list_id = :list_id AND direct > :direct;
3033 EXEC SQL OPEN csr118;
3035 EXEC SQL FETCH csr118 INTO :member_type, :member_id;
3036 if (sqlca.sqlcode != 0) break;
3039 sq_save_data(sq, ((int)member_type[0] << 24) | (member_id & 0xffffff));
3041 EXEC SQL CLOSE csr118;
3043 if (members <= 49) {
3044 targv[1] = malloc(0);
3045 while (sq_remove_data(sq, &member_id)) {
3046 switch (member_id >> 24) {
3049 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
3050 (*action)(2, targv, actarg);
3054 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
3055 (*action)(2, targv, actarg);
3058 targv[0] = "STRING";
3059 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
3060 (*action)(2, targv, actarg);
3063 targv[0] = "KERBEROS";
3064 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
3065 (*action)(2, targv, actarg);
3069 return(MR_INTERNAL);
3078 targv[1] = member_name;
3080 EXEC SQL DECLARE csr119 CURSOR FOR
3081 SELECT u.login FROM users u, imembers im
3082 WHERE im.list_id = :list_id AND im.member_type = 'USER'
3083 AND im.member_id = u.users_id AND im.direct > :direct
3085 EXEC SQL OPEN csr119;
3087 EXEC SQL FETCH csr119 INTO :member_name;
3088 if(sqlca.sqlcode != 0) break;
3089 (*action)(2, targv, actarg);
3091 EXEC SQL CLOSE csr119;
3092 if (ingres_errno) return(mr_errcode);
3095 EXEC SQL DECLARE csr120 CURSOR FOR
3096 SELECT l.name FROM list l, imembers im
3097 WHERE im.list_id = :list_id AND im.member_type='LIST'
3098 AND im.member_id = l.list_id AND im.direct > :direct
3100 EXEC SQL OPEN csr120;
3102 EXEC SQL FETCH csr120 INTO :member_name;
3103 if(sqlca.sqlcode != 0) break;
3104 (*action)(2, targv, actarg);
3106 EXEC SQL CLOSE csr120;
3107 if (ingres_errno) return(mr_errcode);
3109 targv[0] = "STRING";
3110 EXEC SQL DECLARE csr121 CURSOR FOR
3111 SELECT CHAR(str.string) FROM strings str, imembers im
3112 WHERE im.list_id = :list_id AND im.member_type='STRING'
3113 AND im.member_id = str.string_id AND im.direct > :direct
3115 EXEC SQL OPEN csr121;
3117 EXEC SQL FETCH csr121 INTO :member_name;
3118 if(sqlca.sqlcode != 0) break;
3119 (*action)(2, targv, actarg);
3121 EXEC SQL CLOSE csr121;
3122 if (ingres_errno) return(mr_errcode);
3124 targv[0] = "KERBEROS";
3125 EXEC SQL DECLARE csr122 CURSOR FOR
3126 SELECT CHAR(str.string) FROM strings str, imembers im
3127 WHERE im.list_id = :list_id AND im.member_type='KERBEROS'
3128 AND im.member_id = str.string_id
3129 AND im.direct > :direct
3131 EXEC SQL OPEN csr122;
3133 EXEC SQL FETCH csr122 INTO :member_name;
3134 if(sqlca.sqlcode != 0) break;
3135 (*action)(2, targv, actarg);
3137 EXEC SQL CLOSE csr122;
3138 if (ingres_errno) return(mr_errcode);
3144 /* count_members_of_list: this is a simple query, but it cannot be done
3145 * through the dispatch table.
3148 int count_members_of_list(q, argv, cl, action, actarg)
3155 EXEC SQL BEGIN DECLARE SECTION;
3157 EXEC SQL END DECLARE SECTION;
3158 char *rargv[1], countbuf[5];
3160 list = *(int *)argv[0];
3161 rargv[0] = countbuf;
3162 EXEC SQL REPEATED SELECT count (*) INTO :ct FROM imembers
3163 WHERE list_id = :list AND direct=1;
3164 if (ingres_errno) return(mr_errcode);
3165 sprintf(countbuf, "%d", ct);
3166 (*action)(1, rargv, actarg);
3171 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
3172 * the three flags associated with each service. It will return the name of
3173 * each service that meets the quailifications. It does this by building a
3174 * where clause based on the arguments, then doing a retrieve.
3177 static char *sflags[3] = { "enable", "inprogress", "harderror" };
3179 int qualified_get_server(q, argv, cl, action, actarg)
3186 return(qualified_get(q, argv, action, actarg, "s.name != ''",
3187 "s", "name", sflags));
3191 /* generic qualified get routine, used by qualified_get_lists,
3192 * qualified_get_server, and qualified_get_serverhost.
3194 * start - a simple where clause, must not be empty
3195 * range - the name of the range variable
3196 * field - the field to return
3197 * flags - an array of strings, names of the flag variables
3200 int qualified_get(q, argv, action, actarg, start, range, field, flags)
3210 char name[33], qual[256];
3212 char *rargv[1], buf[32];
3214 strcpy(qual, start);
3215 for (i = 0; i < q->argc; i++) {
3216 if (!strcmp(argv[i], "TRUE")) {
3217 sprintf(buf, " AND %s.%s != 0", range, flags[i]);
3218 (void) strcat(qual, buf);
3219 } else if (!strcmp(argv[i], "FALSE")) {
3220 sprintf(buf, " AND %s.%s = 0", range, flags[i]);
3221 (void) strcat(qual, buf);
3225 rargv[0] = SQLDA->sqlvar[0].sqldata;
3226 sprintf(stmt_buf,"SELECT CHAR(%s.%s) FROM %s %s WHERE %s",range,field,q->rtable,range,qual);
3227 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3229 return(MR_INTERNAL);
3230 EXEC SQL DECLARE csr123 CURSOR FOR stmt;
3231 EXEC SQL OPEN csr123;
3233 EXEC SQL FETCH csr123 USING DESCRIPTOR :SQLDA;
3234 if(sqlca.sqlcode != 0) break;
3236 (*action)(1, rargv, actarg);
3238 EXEC SQL CLOSE csr123;
3239 if (ingres_errno) return(mr_errcode);
3241 return(MR_NO_MATCH);
3246 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
3247 * the five flags associated with each serverhost. It will return the name of
3248 * each service and host that meets the quailifications. It does this by
3249 * building a where clause based on the arguments, then doing a retrieve.
3252 static char *shflags[6] = { "service", "enable", "override", "success",
3253 "inprogress", "hosterror" };
3255 int qualified_get_serverhost(q, argv, cl, action, actarg)
3262 EXEC SQL BEGIN DECLARE SECTION;
3263 char sname[33], mname[33], qual[256];
3264 EXEC SQL END DECLARE SECTION;
3265 char *rargv[2], buf[32];
3268 sprintf(qual, "m.mach_id = sh.mach_id AND sh.service = uppercase('%s')",
3270 for (i = 1; i < q->argc; i++) {
3271 if (!strcmp(argv[i], "TRUE")) {
3272 sprintf(buf, " AND sh.%s != 0", shflags[i]);
3274 } else if (!strcmp(argv[i], "FALSE")) {
3275 sprintf(buf, " AND sh.%s = 0", shflags[i]);
3282 EXEC SQL DECLARE csr124 CURSOR FOR
3283 SELECT sh.service, m.name FROM serverhosts sh, machine m
3285 EXEC SQL OPEN csr124;
3287 EXEC SQL FETCH csr124 INTO :sname, :mname;
3288 if(sqlca.sqlcode != 0) break;
3290 (*action)(2, rargv, actarg);
3292 EXEC SQL CLOSE csr124;
3294 if (ingres_errno) return(mr_errcode);
3296 return(MR_NO_MATCH);
3301 /* register_user - change user's login name and allocate a pobox, group,
3302 * filesystem, and quota for them. The user's status must start out as 0,
3303 * and is left as 2. Arguments are: user's UID, new login name, and user's
3304 * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY,
3305 * MR_FS_STAFF, MR_FS_MISC).
3308 register_user(q, argv, cl)
3313 EXEC SQL BEGIN DECLARE SECTION;
3314 char *login, dir[65], *entity, directory[129], machname[33];
3315 int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
3316 int size, alloc, pid, ostatus, nstatus, gidval, fsidval, npidval;
3317 static int m_id = 0, def_quota = 0;
3318 EXEC SQL END DECLARE SECTION;
3319 char buffer[256], *aargv[3];
3321 entity = cl->entity;
3322 who = cl->client_id;
3324 uid = atoi(argv[0]);
3326 utype = atoi(argv[2]);
3329 EXEC SQL REPEATED SELECT users_id, status INTO :users_id, :ostatus
3331 WHERE uid = :uid AND (status=0 OR status=5 OR status=6);
3333 if (sqlca.sqlerrd[2] == 0)
3334 return(MR_NO_MATCH);
3335 if (sqlca.sqlerrd[2] > 1)
3336 return(MR_NOT_UNIQUE);
3338 /* check new login name */
3339 EXEC SQL REPEATED SELECT COUNT(login) INTO :rowcount FROM users
3340 WHERE login = LEFT(:login,SIZE(login)) AND users_id != :users_id;
3341 if (ingres_errno) return(mr_errcode);
3342 if (rowcount > 0) return(MR_IN_USE);
3343 EXEC SQL REPEATED SELECT COUNT(name) INTO :rowcount FROM list
3344 WHERE name = LEFT(:login,SIZE(name));
3345 if (ingres_errno) return(mr_errcode);
3346 if (rowcount > 0) return(MR_IN_USE);
3347 EXEC SQL REPEATED SELECT COUNT(label) INTO :rowcount FROM filesys
3348 WHERE label = LEFT(:login,SIZE(label));
3349 if (ingres_errno) return(mr_errcode);
3350 if (rowcount > 0) return(MR_IN_USE);
3351 com_err(whoami, 0, "login name OK");
3353 /* choose place for pobox, put in mid */
3354 EXEC SQL DECLARE csr130 CURSOR FOR
3355 SELECT sh.mach_id, m.name FROM serverhosts sh, machine m
3356 WHERE sh.service='POP' AND sh.mach_id=m.mach_id
3357 AND sh.value2 - sh.value1 =
3358 (SELECT MAX(value2 - value1) FROM serverhosts
3359 WHERE service = 'POP');
3360 EXEC SQL OPEN csr130;
3361 EXEC SQL FETCH csr130 INTO :mid, :machname;
3362 if (sqlca.sqlerrd[2] == 0) {
3363 EXEC SQL CLOSE csr130;
3364 if (ingres_errno) return(mr_errcode);
3365 return(MR_NO_POBOX);
3367 EXEC SQL CLOSE csr130;
3368 if (ingres_errno) return(mr_errcode);
3371 /* change login name, set pobox */
3372 sprintf(buffer, "u.users_id = %d", users_id);
3373 incremental_before("users", buffer, 0);
3375 if (ostatus == 5 || ostatus == 6)
3377 EXEC SQL REPEATED UPDATE users SET login = :login, status = :nstatus,
3378 modtime='now', modby = :who, modwith = :entity, potype='POP',
3379 pop_id = :mid, pmodtime='now', pmodby = :who, pmodwith = :entity
3380 WHERE users_id = :users_id;
3382 if (ingres_errno) return(mr_errcode);
3383 if (sqlca.sqlerrd[2] != 1)
3384 return(MR_INTERNAL);
3385 set_pop_usage(mid, 1);
3386 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
3388 incremental_after("users", buffer, 0);
3390 /* create group list */
3391 if (set_next_object_id("gid", "list", 1))
3393 if (set_next_object_id("list_id", "list", 0))
3395 EXEC SQL REPEATED SELECT value INTO :list_id FROM numvalues
3396 WHERE name='list_id';
3397 if (ingres_errno) return(mr_errcode);
3398 if (sqlca.sqlerrd[2] != 1)
3399 return(MR_INTERNAL);
3400 incremental_clear_before();
3401 EXEC SQL SELECT value INTO :gidval FROM numvalues WHERE name = 'gid';
3402 EXEC SQL REPEATED INSERT INTO list
3403 (name, list_id, active, publicflg, hidden, maillist, grouplist,
3404 gid, description, acl_type, acl_id,
3405 modtime, modby, modwith)
3406 VALUES (:login, :list_id, 1, 0, 0, 0, 1,
3407 :gidval, 'User Group', 'USER', :users_id,
3408 'now', :who, :entity);
3409 if (ingres_errno) return(mr_errcode);
3410 if (sqlca.sqlerrd[2] != 1)
3411 return(MR_INTERNAL);
3412 sprintf(buffer, "l.list_id = %d", list_id);
3413 incremental_after("list", buffer, 0);
3414 aargv[0] = (char *) list_id;
3416 aargv[2] = (char *) users_id;
3417 incremental_clear_before();
3418 EXEC SQL REPEATED INSERT INTO imembers
3419 (list_id, member_type, member_id, ref_count, direct)
3420 VALUES (:list_id, 'USER', :users_id, 1, 1);
3421 if (ingres_errno) return(mr_errcode);
3422 if (sqlca.sqlerrd[2] != 1)
3423 return(MR_INTERNAL);
3424 incremental_after("members", 0, aargv);
3427 /* Cell Name (I know, it shouldn't be hard coded...) */
3428 strcpy(machname, "ATHENA.MIT.EDU");
3429 EXEC SQL SELECT mach_id INTO :m_id FROM machine
3430 WHERE name = :machname;
3433 /* create filesystem */
3434 if (set_next_object_id("filsys_id", "filesys", 0))
3436 incremental_clear_before();
3437 if (islower(login[0]) && islower(login[1])) {
3438 sprintf(directory, "/afs/athena.mit.edu/user/%c/%c/%s",
3439 login[0], login[1], login);
3441 sprintf(directory, "/afs/athena.mit.edu/user/other/%s", login);
3444 EXEC SQL SELECT value INTO :fsidval FROM numvalues
3445 WHERE numvalues.name='filsys_id';
3446 EXEC SQL REPEATED INSERT INTO filesys
3447 (filsys_id, phys_id, label, type, mach_id, name,
3448 mount, access, comments, owner, owners, createflg,
3449 lockertype, modtime, modby, modwith)
3451 (:fsidval, 0, :login, 'AFS', :m_id, :directory,
3452 '/mit/'+:login, 'w', 'User Locker', :users_id, :list_id, 1,
3453 'HOMEDIR', 'now', :who, :entity);
3455 if (ingres_errno) return(mr_errcode);
3456 if (sqlca.sqlerrd[2] != 1)
3457 return(MR_INTERNAL);
3458 sprintf(buffer,"fs.filsys_id = %d",fsidval);
3459 incremental_after("filesys", buffer, 0);
3462 if (def_quota == 0) {
3463 EXEC SQL REPEATED SELECT value INTO :def_quota FROM numvalues
3464 WHERE name='def_quota';
3465 if (ingres_errno) return(mr_errcode);
3466 if (sqlca.sqlerrd[2] != 1)
3467 return(MR_NO_QUOTA);
3470 incremental_clear_before();
3471 EXEC SQL REPEATED INSERT INTO quota
3472 (entity_id, filsys_id, type, quota, phys_id, modtime, modby, modwith)
3474 (0, :fsidval, 'ANY', :def_quota, 0, 'now', :who, :entity);
3475 if (ingres_errno) return(mr_errcode);
3476 if (sqlca.sqlerrd[2] != 1)
3477 return(MR_INTERNAL);
3481 sprintf(buffer, "q.entity_id = 0 and q.filsys_id = %d and q.type = 'ANY'", fsidval);
3482 incremental_after("quota", buffer, aargv);
3483 com_err(whoami, 0, "quota of %d assigned", def_quota);
3484 if (ingres_errno) return(mr_errcode);
3486 cache_entry(login, "USER", users_id);
3488 EXEC SQL REPEATED UPDATE tblstats SET updates=updates+1, modtime='now'
3489 WHERE table_name='users';
3490 EXEC SQL REPEATED UPDATE tblstats SET appends=appends+1, modtime='now'
3491 WHERE table_name='list' OR table_name='filesys' OR table_name='quota';
3492 if (ingres_errno) return(mr_errcode);
3498 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
3502 ** delta (will be +/- 1)
3505 ** - incr/decr value field in serverhosts table for pop/mach_id
3509 static int set_pop_usage(id, cnt)
3510 EXEC SQL BEGIN DECLARE SECTION;
3513 EXEC SQL END DECLARE SECTION;
3515 EXEC SQL REPEATED UPDATE serverhosts SET value1 = value1 + :cnt
3516 WHERE serverhosts.service = 'POP' AND serverhosts.mach_id = :id;
3518 if (ingres_errno) return(mr_errcode);
3522 int _sdl_followup(q, argv, cl)
3531 EXEC SQL set printqry;
3533 EXEC SQL set noprintqry;
3540 /* Validation Routines */
3542 validate_row(q, argv, v)
3543 register struct query *q;
3545 register struct validate *v;
3547 EXEC SQL BEGIN DECLARE SECTION;
3551 EXEC SQL END DECLARE SECTION;
3553 /* build where clause */
3554 build_qual(v->qual, v->argc, argv, qual);
3556 if (log_flags & LOG_VALID)
3557 /* tell the logfile what we're doing */
3558 com_err(whoami, 0, "validating row: %s", qual);
3560 /* look for the record */
3561 sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",q->rtable,qual);
3562 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3564 return(MR_INTERNAL);
3565 EXEC SQL DECLARE csr126 CURSOR FOR stmt;
3566 EXEC SQL OPEN csr126;
3567 EXEC SQL FETCH csr126 USING DESCRIPTOR :SQLDA;
3568 EXEC SQL CLOSE csr126;
3569 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3571 if (ingres_errno) return(mr_errcode);
3572 if (rowcount == 0) return(MR_NO_MATCH);
3573 if (rowcount > 1) return(MR_NOT_UNIQUE);
3577 validate_fields(q, argv, vo, n)
3579 register char *argv[];
3580 register struct valobj *vo;
3583 register int status;
3588 if (log_flags & LOG_VALID)
3589 com_err(whoami, 0, "validating %s in %s: %s",
3590 vo->namefield, vo->table, argv[vo->index]);
3591 status = validate_name(argv, vo);
3595 if (log_flags & LOG_VALID)
3596 com_err(whoami, 0, "validating %s in %s: %s",
3597 vo->idfield, vo->table, argv[vo->index]);
3598 status = validate_id(q, argv, vo);
3602 if (log_flags & LOG_VALID)
3603 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
3604 status = validate_date(argv, vo);
3608 if (log_flags & LOG_VALID)
3609 com_err(whoami, 0, "validating %s type: %s",
3610 vo->table, argv[vo->index]);
3611 status = validate_type(argv, vo);
3615 if (log_flags & LOG_VALID)
3616 com_err(whoami, 0, "validating typed data (%s): %s",
3617 argv[vo->index - 1], argv[vo->index]);
3618 status = validate_typedata(q, argv, vo);
3622 if (log_flags & LOG_VALID)
3623 com_err(whoami, 0, "validating rename %s in %s",
3624 argv[vo->index], vo->table);
3625 status = validate_rename(argv, vo);
3629 if (log_flags & LOG_VALID)
3630 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
3631 status = validate_chars(argv[vo->index]);
3639 status = lock_table(vo);
3643 status = convert_wildcards(argv[vo->index]);
3647 status = convert_wildcards_uppercase(argv[vo->index]);
3652 if (status != MR_EXISTS) return(status);
3656 if (ingres_errno) return(mr_errcode);
3661 /* validate_chars: verify that there are no illegal characters in
3662 * the string. Legal characters are printing chars other than
3663 * ", *, ?, \, [ and ].
3665 static int illegalchars[] = {
3666 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
3667 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
3668 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
3669 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
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, 1, 1, 1, 0, 0, /* P - _ */
3672 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
3673 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
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,
3680 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3681 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3688 if (illegalchars[*s++])
3689 return(MR_BAD_CHAR);
3694 validate_id(q, argv, vo)
3697 register struct valobj *vo;
3699 EXEC SQL BEGIN DECLARE SECTION;
3700 char *name, *tbl, *namefield, *idfield;
3702 EXEC SQL END DECLARE SECTION;
3706 name = argv[vo->index];
3708 namefield = vo->namefield;
3709 idfield = vo->idfield;
3711 if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
3712 !strcmp(tbl, "machine") ||
3713 !strcmp(tbl, "filesys") ||
3714 !strcmp(tbl, "list") ||
3715 !strcmp(tbl, "cluster") ||
3716 !strcmp(tbl, "strings")) {
3717 if (!strcmp(tbl, "machine"))
3718 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3719 status = name_to_id(name, tbl, &id);
3721 *(int *)argv[vo->index] = id;
3723 } else if (status == MR_NO_MATCH && !strcmp(tbl, "strings") &&
3724 (q->type == APPEND || q->type == UPDATE)) {
3725 EXEC SQL SELECT value INTO :id FROM numvalues
3726 WHERE name = 'strings_id';
3728 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3729 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3730 cache_entry(name, "STRING", id);
3731 *(int *)argv[vo->index] = id;
3733 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
3739 if (!strcmp(namefield, "uid")) {
3740 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = %s",idfield,tbl,namefield,name);
3742 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",idfield,tbl,namefield,name);
3744 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3746 return(MR_INTERNAL);
3747 EXEC SQL DECLARE csr127 CURSOR FOR stmt;
3748 EXEC SQL OPEN csr127;
3750 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3751 if(sqlca.sqlcode == 0) {
3753 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3754 if(sqlca.sqlcode == 0) rowcount++;
3756 EXEC SQL CLOSE csr127;
3760 if (rowcount != 1) return(vo->error);
3761 bcopy(SQLDA->sqlvar[0].sqldata,argv[vo->index],sizeof(int));
3765 validate_name(argv, vo)
3767 register struct valobj *vo;
3769 EXEC SQL BEGIN DECLARE SECTION;
3770 char *name, *tbl, *namefield;
3772 EXEC SQL END DECLARE SECTION;
3775 name = argv[vo->index];
3777 namefield = vo->namefield;
3778 if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
3779 for (c = name; *c; c++)
3783 sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
3784 tbl,tbl,namefield,name);
3785 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3787 return(MR_INTERNAL);
3788 EXEC SQL DECLARE csr128 CURSOR FOR stmt;
3789 EXEC SQL OPEN csr128;
3790 EXEC SQL FETCH csr128 USING DESCRIPTOR :SQLDA;
3791 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3792 EXEC SQL CLOSE csr128;
3794 if (ingres_errno) return(mr_errcode);
3795 return ((rowcount == 1) ? MR_EXISTS : vo->error);
3798 validate_date(argv, vo)
3802 EXEC SQL BEGIN DECLARE SECTION;
3806 EXEC SQL END DECLARE SECTION;
3808 idate = argv[vo->index];
3809 EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
3811 if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
3816 validate_rename(argv, vo)
3820 EXEC SQL BEGIN DECLARE SECTION;
3821 char *name, *tbl, *namefield, *idfield;
3823 EXEC SQL END DECLARE SECTION;
3827 c = name = argv[vo->index];
3829 if (illegalchars[*c++])
3830 return(MR_BAD_CHAR);
3832 /* minor kludge to upcasify machine names */
3833 if (!strcmp(tbl, "machine"))
3834 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3835 namefield = vo->namefield;
3836 idfield = vo->idfield;
3839 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3841 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = LEFT('%s',SIZE(%s))",
3842 namefield,tbl,namefield,name,namefield);
3843 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3845 return(MR_INTERNAL);
3846 EXEC SQL DECLARE csr129 CURSOR FOR stmt;
3847 EXEC SQL OPEN csr129;
3848 EXEC SQL FETCH csr129 USING DESCRIPTOR :SQLDA;
3849 if(sqlca.sqlcode == 0) id=1; else id=0;
3850 EXEC SQL CLOSE csr129;
3852 if (ingres_errno) return(mr_errcode);
3858 status = name_to_id(name, tbl, &id);
3859 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3866 validate_type(argv, vo)
3868 register struct valobj *vo;
3870 EXEC SQL BEGIN DECLARE SECTION;
3874 EXEC SQL END DECLARE SECTION;
3877 typename = vo->table;
3878 c = val = argv[vo->index];
3880 if (illegalchars[*c++])
3881 return(MR_BAD_CHAR);
3884 /* uppercase type fields */
3885 for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
3887 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
3888 WHERE name = :typename AND type='TYPE' AND trans = :val;
3889 if (ingres_errno) return(mr_errcode);
3890 return (cnt ? MR_EXISTS : vo->error);
3893 /* validate member or type-specific data field */
3895 validate_typedata(q, argv, vo)
3896 register struct query *q;
3897 register char *argv[];
3898 register struct valobj *vo;
3900 EXEC SQL BEGIN DECLARE SECTION;
3903 char data_type[129];
3905 EXEC SQL END DECLARE SECTION;
3910 /* get named object */
3911 name = argv[vo->index];
3913 /* get field type string (known to be at index-1) */
3914 field_type = argv[vo->index-1];
3916 /* get corresponding data type associated with field type name */
3917 EXEC SQL SELECT trans INTO :data_type FROM alias
3918 WHERE name = :field_type AND type='TYPEDATA';
3919 if (ingres_errno) return(mr_errcode);
3920 if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
3922 /* now retrieve the record id corresponding to the named object */
3923 if (index(data_type, ' '))
3924 *index(data_type, ' ') = 0;
3925 if (!strcmp(data_type, "user")) {
3927 if (index(name, '@'))
3929 status = name_to_id(name, data_type, &id);
3930 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3932 if (status) return(status);
3933 } else if (!strcmp(data_type, "list")) {
3935 status = name_to_id(name, data_type, &id);
3936 if (status && status == MR_NOT_UNIQUE)
3938 if (status == MR_NO_MATCH) {
3939 /* if idfield is non-zero, then if argv[0] matches the string
3940 * that we're trying to resolve, we should get the value of
3941 * numvalues.[idfield] for the id.
3943 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3944 set_next_object_id(q->validate->object_id, q->rtable, 0);
3946 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
3948 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
3951 } else if (status) return(status);
3952 } else if (!strcmp(data_type, "machine")) {
3954 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3955 status = name_to_id(name, data_type, &id);
3956 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3958 if (status) return(status);
3959 } else if (!strcmp(data_type, "string")) {
3961 status = name_to_id(name, data_type, &id);
3962 if (status && status == MR_NOT_UNIQUE)
3964 if (status == MR_NO_MATCH) {
3965 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3966 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
3968 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3969 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3970 cache_entry(name, "STRING", id);
3971 } else if (status) return(status);
3972 } else if (!strcmp(data_type, "none")) {
3978 /* now set value in argv */
3979 *(int *)argv[vo->index] = id;
3985 /* Lock the table named by the validation object */
3990 sprintf(stmt_buf,"UPDATE %s SET modtime='now' WHERE %s.%s = 0",
3991 vo->table,vo->table,vo->idfield);
3992 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
3993 if (ingres_errno) return(mr_errcode);
3994 if (sqlca.sqlerrd[2] != 1)
4001 /* Check the database at startup time. For now this just resets the
4002 * inprogress flags that the DCM uses.
4005 sanity_check_database()
4010 /* Dynamic SQL support routines */
4011 MR_SQLDA_T *mr_alloc_SQLDA()
4014 short *null_indicators;
4017 if((it=(MR_SQLDA_T *)malloc(sizeof(MR_SQLDA_T)))==NULL) {
4018 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
4022 if((null_indicators=(short *)calloc(QMAXARGS,sizeof(short)))==NULL) {
4023 com_err(whoami, MR_NO_MEM, "setting up SQLDA null indicators");
4027 for(j=0; j<QMAXARGS; j++) {
4028 if((it->sqlvar[j].sqldata=malloc(sizeof(short)+QMAXARGSIZE))==NULL) {
4029 com_err(whoami, MR_NO_MEM, "setting up SQLDA variables");
4032 it->sqlvar[j].sqllen=QMAXARGSIZE;
4033 it->sqlvar[j].sqlind=null_indicators+j;
4034 null_indicators[j]=0;
4041 /* Use this after FETCH USING DESCRIPTOR one or more
4042 * result columns may contain NULLs. This routine is
4043 * not currently needed, since db/schema creates all
4044 * columns with a NOT NULL WITH DEFAULT clause.
4046 * This is currently dead flesh, since no Moira columns
4047 * allow null values; all use default values.
4049 mr_fix_nulls_in_SQLDA(da)
4052 register IISQLVAR *var;
4056 for(j=0, var=da->sqlvar; j<da->sqld; j++, var++) {
4057 switch(var->sqltype) {
4058 case -IISQ_CHA_TYPE:
4062 case -IISQ_INT_TYPE:
4064 intp=(int *)var->sqldata;
4072 /* prefetch_value():
4073 * This routine fetches an appropriate value from the numvalues table.
4074 * It is a little hack to get around the fact that SQL doesn't let you
4075 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
4077 * It is called from the query table as (*v->pre_rtn)(q,Argv,cl) or
4078 * from within a setup_...() routine with the appropriate arguments.
4080 * Correct functioning of this routine may depend on the assumption
4081 * that this query is an APPEND.
4084 prefetch_value(q,argv,cl)
4089 EXEC SQL BEGIN DECLARE SECTION;
4090 char *name = q->validate->object_id;
4092 EXEC SQL END DECLARE SECTION;
4093 int status, limit, argc;
4095 /* set next object id, limiting it if necessary */
4096 if(!strcmp(name, "uid") || !strcmp(name, "gid"))
4097 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
4100 if((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
4103 /* fetch object id */
4104 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name=:name;
4105 if(ingres_errno) return(mr_errcode);
4106 if(sqlca.sqlerrd[2] != 1) return(MR_INTERNAL);
4108 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
4109 sprintf(argv[argc],"%d",value); /** Could save this step by changing tlist from %s to %d **/
4114 /* prefetch_filesys():
4115 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
4116 * Appends the filsys_id and the phys_id to the argv so they can be
4117 * referenced in an INSERT into a table other than filesys. Also
4118 * see comments at prefetch_value().
4120 * Assumes the existence of a row where filsys_id = argv[0], since a
4121 * filesys label has already been resolved to a filsys_id.
4123 prefetch_filesys(q,argv,cl)
4128 EXEC SQL BEGIN DECLARE SECTION;
4130 EXEC SQL END DECLARE SECTION;
4133 fid = *(int *)argv[0];
4134 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
4135 if(ingres_errno) return(mr_errcode);
4137 argc=q->argc+q->vcnt;
4138 sprintf(argv[argc++],"%d",phid);
4139 sprintf(argv[argc],"%d",fid);
4144 /* Convert normal Unix-style wildcards to SQL voodoo */
4145 convert_wildcards(arg)
4148 static char buffer[QMAXARGSIZE];
4149 register char *s, *d;
4151 for(d=buffer,s=arg;*s;s++) {
4153 case '*': *d++='%'; *d++='%'; break;
4154 case '?': *d++='_'; break;
4157 case ']': *d++='*'; *d++ = *s; break;
4158 case '%': *d++='*'; *d++='%'; *d++='%'; break;
4159 default: *d++ = *s; break;
4164 /* Copy back into argv */
4170 /* This version includes uppercase conversion, for things like gmac.
4171 * This is necessary because "LIKE" doesn't work with "uppercase()".
4172 * Including it in a wildcard routine saves making two passes over
4173 * the argument string.
4175 convert_wildcards_uppercase(arg)
4178 static char buffer[QMAXARGSIZE];
4179 register char *s, *d;
4181 for(d=buffer,s=arg;*s;s++) {
4183 case '*': *d++='%'; *d++='%'; break;
4184 case '?': *d++='_'; break;
4187 case ']': *d++='*'; *d++ = *s; break;
4188 case '%': *d++='*'; *d++='%'; *d++='%'; break;
4189 default: *d++=toupper(*s); break; /* This is the only diff. */
4194 /* Copy back into argv */
4201 /* Looks like it's time to build an abstraction barrier, Yogi */
4203 EXEC SQL BEGIN DECLARE SECTION;
4205 EXEC SQL END DECLARE SECTION;
4209 EXEC SQL PREPARE stmt FROM :stmt;
4210 EXEC SQL DESCRIBE stmt INTO :SQLDA;
4211 if(SQLDA->sqld==0) /* Not a SELECT */
4212 return(MR_INTERNAL);
4213 EXEC SQL DECLARE csr CURSOR FOR stmt;
4215 EXEC SQL FETCH csr USING DESCRIPTOR :SQLDA;
4216 if(sqlca.sqlcode==0)
4218 else if((sqlca.sqlcode<0) && mr_errcode)
4234 fprintf(stderr, "Size: %d\n", strlen(p));
4235 while (strlen(p) >= 8) {
4236 fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x\n",
4237 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
4240 switch (strlen(p)) {
4242 fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x\n",
4243 p[0], p[1], p[2], p[3], p[4], p[5], p[6]);
4246 fprintf(stderr, "%02x %02x %02x %02x %02x %02x\n",
4247 p[0], p[1], p[2], p[3], p[4], p[5]);
4250 fprintf(stderr, "%02x %02x %02x %02x %02x\n",
4251 p[0], p[1], p[2], p[3], p[4]);
4254 fprintf(stderr, "%02x %02x %02x %02x\n",
4255 p[0], p[1], p[2], p[3]);
4258 fprintf(stderr, "%02x %02x %02x\n",
4262 fprintf(stderr, "%02x %02x\n",
4266 fprintf(stderr, "%02x\n",
4274 /* eof:qsupport.dc */