6 * Copyright (C) 1987 by the Massachusetts Institute of Technology
7 * For copying and distribution information, please see the file
13 static char *rcsid_qsupport_dc = "$Header$";
16 #include <mit-copyright.h>
18 #include "mr_server.h"
23 EXEC SQL INCLUDE sqlca;
24 EXEC SQL INCLUDE sqlda;
27 extern char *whoami, *strsave();
28 extern int ingres_errno, mr_errcode;
30 EXEC SQL BEGIN DECLARE SECTION;
31 extern char stmt_buf[];
32 EXEC SQL END DECLARE SECTION;
34 /* Specialized Access Routines */
36 /* access_user - verify that client name equals specified login name
38 * - since field validation routines are called first, a users_id is
39 * now in argv[0] instead of the login name.
42 EXEC SQL WHENEVER SQLERROR CALL ingerr;
44 access_user(q, argv, cl)
49 if (cl->users_id != *(int *)argv[0])
57 /* access_login - verify that client name equals specified login name
59 * argv[0...n] contain search info. q->
62 access_login(q, argv, cl)
67 EXEC SQL BEGIN DECLARE SECTION;
70 EXEC SQL END DECLARE SECTION;
72 build_qual(q->qual, q->argc, argv, qual);
73 if (!strncmp(q->name,"get_user_account",strlen("get_user_account"))) {
74 EXEC SQL SELECT users_id INTO :id FROM users u, strings str WHERE :qual;
76 EXEC SQL SELECT users_id INTO :id FROM users u WHERE :qual;
79 if (sqlca.sqlerrd[2] != 1 || id != cl->users_id)
87 /* access_list - check access for most list operations
89 * Inputs: argv[0] - list_id
91 * argv[2] - member ID (only for queries "amtl" and "dmfl")
92 * argv[7] - group IID (only for query "ulis")
95 * - check that client is a member of the access control list
96 * - OR, if the query is add_member_to_list or delete_member_from_list
97 * and the list is public, allow access if client = member
100 access_list(q, argv, cl)
105 EXEC SQL BEGIN DECLARE SECTION;
106 int list_id, acl_id, flags, gid;
108 EXEC SQL END DECLARE SECTION;
110 int client_id, status;
112 list_id = *(int *)argv[0];
113 EXEC SQL SELECT acl_id, acl_type, gid, publicflg
114 INTO :acl_id, :acl_type, :gid, :flags
116 WHERE list_id = :list_id;
118 if (sqlca.sqlerrd[2] != 1)
121 /* parse client structure */
122 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
125 /* if amtl or dmfl and list is public allow client to add or delete self */
126 if (((!strcmp("amtl", q->shortname) && flags) ||
127 (!strcmp("dmfl", q->shortname))) &&
128 (!strcmp("USER", argv[1]))) {
129 if (*(int *)argv[2] == client_id) return(MR_SUCCESS);
130 /* if update_list, don't allow them to change the GID */
131 } else if (!strcmp("ulis", q->shortname)) {
132 if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
133 (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
137 /* check for client in access control list */
138 status = find_member(acl_type, acl_id, client_type, client_id, 0);
139 if (!status) return(MR_PERM);
145 /* access_visible_list - allow access to list only if it is not hidden,
146 * or if the client is on the ACL
148 * Inputs: argv[0] - list_id
149 * cl - client identifier
152 access_visible_list(q, argv, cl)
157 EXEC SQL BEGIN DECLARE SECTION;
158 int list_id, acl_id, flags ;
160 EXEC SQL END DECLARE SECTION;
162 int client_id, status;
164 list_id = *(int *)argv[0];
165 EXEC SQL SELECT hidden, acl_id, acl_type
166 INTO :flags, :acl_id, :acl_type
168 WHERE list_id = :list_id;
169 if (sqlca.sqlerrd[2] != 1)
174 /* parse client structure */
175 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
178 /* check for client in access control list */
179 status = find_member(acl_type, acl_id, client_type, client_id, 0);
187 /* access_vis_list_by_name - allow access to list only if it is not hidden,
188 * or if the client is on the ACL
190 * Inputs: argv[0] - list name
191 * cl - client identifier
194 access_vis_list_by_name(q, argv, cl)
199 EXEC SQL BEGIN DECLARE SECTION;
200 int acl_id, flags, rowcount;
201 char acl_type[9], *listname;
202 EXEC SQL END DECLARE SECTION;
204 int client_id, status;
207 EXEC SQL SELECT hidden, acl_id, acl_type INTO :flags, :acl_id, :acl_type
208 FROM list WHERE name = :listname;
210 rowcount=sqlca.sqlerrd[2];
218 /* parse client structure */
219 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
222 /* check for client in access control list */
223 status = find_member(acl_type, acl_id, client_type, client_id, 0);
231 /* access_member - allow user to access member of type "USER" and name matches
232 * username, or to access member of type "LIST" and list is one that user is
233 * on the acl of, or the list is visible.
236 access_member(q, argv, cl)
241 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
242 return(access_visible_list(q, &argv[1], cl));
244 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
245 if (cl->users_id == *(int *)argv[1])
249 if (!strcmp(argv[0], "KERBEROS") || !strcmp(argv[0], "RKERBERO")) {
250 if (cl->client_id == *(int *)argv[1])
258 /* access_qgli - special access routine for Qualified_get_lists. Allows
259 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
262 access_qgli(q, argv, cl)
267 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
273 /* access_service - allow access if user is on ACL of service. Don't
274 * allow access if a wildcard is used.
277 access_service(q, argv, cl)
282 EXEC SQL BEGIN DECLARE SECTION;
284 char *name, acl_type[9];
285 EXEC SQL END DECLARE SECTION;
286 int client_id, status;
287 char *client_type, *c;
290 for(c=name;*c;c++) if(islower(*c)) *c = toupper(*c); /* uppercasify */
291 EXEC SQL SELECT acl_id, acl_type INTO :acl_id, :acl_type FROM servers
293 if (sqlca.sqlerrd[2] > 1)
296 /* parse client structure */
297 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
300 /* check for client in access control list */
301 status = find_member(acl_type, acl_id, client_type, client_id, 0);
302 if (!status) return(MR_PERM);
308 /* access_filesys - verify that client is owner or on owners list of filesystem
312 access_filesys(q, argv, cl)
317 EXEC SQL BEGIN DECLARE SECTION;
318 int users_id, list_id;
320 EXEC SQL END DECLARE SECTION;
321 int status, client_id;
325 EXEC SQL SELECT owner, owners INTO :users_id, :list_id FROM filesys
328 if (sqlca.sqlerrd[2] != 1)
330 if (users_id == cl->users_id)
332 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
334 status = find_member("LIST", list_id, client_type, client_id, 0);
345 /* Setup routine for add_user
347 * Inputs: argv[0] - login
352 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
353 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
356 setup_ausr(q, argv, cl)
358 register char *argv[];
362 EXEC SQL BEGIN DECLARE SECTION;
364 EXEC SQL END DECLARE SECTION;
366 if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
370 if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1) {
371 if (set_next_object_id("uid", "users", 1))
372 return(MR_INGRES_ERR);
373 EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'uid';
374 if (sqlca.sqlerrd[2] != 1)
376 sprintf(argv[row], "%d", nuid);
379 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1) {
380 sprintf(argv[0], "#%s", argv[row]);
383 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
390 /* setup_dusr - verify that the user is no longer being referenced
391 * and may safely be deleted.
394 int setup_dusr(q, argv)
398 EXEC SQL BEGIN DECLARE SECTION;
400 EXEC SQL END DECLARE SECTION;
402 id = *(int *)argv[0];
404 /* For now, only allow users to be deleted if their status is 0 */
405 EXEC SQL REPEATED SELECT status INTO :flag FROM users
406 WHERE users_id = :id;
407 if (flag != 0 && flag != 4)
410 EXEC SQL REPEATED DELETE FROM quota WHERE entity_id = :id AND type='USER';
411 EXEC SQL REPEATED DELETE FROM krbmap WHERE users_id = :id;
412 EXEC SQL REPEATED SELECT COUNT(member_id) INTO :cnt FROM imembers
413 WHERE member_id = :id AND member_type = 'USER';
416 EXEC SQL REPEATED SELECT COUNT(label) INTO :cnt FROM filesys
420 EXEC SQL REPEATED SELECT COUNT(name) INTO :cnt FROM list
421 WHERE acl_id = :id AND acl_type = 'USER';
424 EXEC SQL REPEATED SELECT COUNT(name) INTO :cnt FROM servers
425 WHERE acl_id = :id AND acl_type = 'USER';
428 EXEC SQL REPEATED SELECT COUNT(acl_id) INTO :cnt FROM hostaccess
429 WHERE acl_id = :id AND acl_type = 'USER';
438 /* setup_spop: verify that there is already a valid POP machine_id in the
439 * pop_id field. Also take care of keeping track of the post office usage.
441 int setup_spop(q, argv)
445 EXEC SQL BEGIN DECLARE SECTION;
448 EXEC SQL END DECLARE SECTION;
450 id = *(int *)argv[0];
451 EXEC SQL REPEATED SELECT potype, pop_id INTO :type, :mid FROM users
452 WHERE users_id = :id;
453 if(sqlca.sqlerrd[2] = 0)
455 EXEC SQL REPEATED SELECT mach_id INTO :mid FROM machine
456 WHERE mach_id = :mid;
457 if (sqlca.sqlerrd[2] = 0)
459 if (strcmp(strtrim(type), "POP"))
460 set_pop_usage(mid, 1);
465 /* setup_dpob: Take care of keeping track of the post office usage.
467 int setup_dpob(q, argv)
471 EXEC SQL BEGIN DECLARE SECTION;
474 EXEC SQL END DECLARE SECTION;
476 user = *(int *)argv[0];
477 EXEC SQL REPEATED SELECT potype, pop_id INTO :type, :id FROM users
478 WHERE users_id = :user;
479 if (ingres_errno) return(mr_errcode);
481 if (!strcmp(strtrim(type), "POP"))
482 set_pop_usage(id, -1);
487 /* setup_dmac - verify that the machine is no longer being referenced
488 * and may safely be deleted.
491 int setup_dmac(q, argv)
495 EXEC SQL BEGIN DECLARE SECTION;
497 EXEC SQL END DECLARE SECTION;
499 id = *(int *)argv[0];
500 EXEC SQL REPEATED SELECT COUNT(login) INTO :cnt FROM users
501 WHERE potype='POP' AND pop_id = :id;
504 EXEC SQL REPEATED SELECT COUNT(mach_id) INTO :cnt FROM serverhosts
508 EXEC SQL REPEATED SELECT COUNT(mach_id) INTO :cnt FROM nfsphys
512 EXEC SQL REPEATED SELECT COUNT(mach_id) INTO :cnt FROM hostaccess
516 EXEC SQL REPEATED SELECT COUNT(mach_id) INTO :cnt FROM printcap
520 EXEC SQL REPEATED SELECT COUNT(quotaserver) INTO :cnt FROM printcap
521 WHERE quotaserver = :id;
524 EXEC SQL REPEATED SELECT COUNT(mach_id) INTO :cnt FROM palladium
529 EXEC SQL REPEATED DELETE FROM mcmap WHERE mach_id = :id;
530 if (ingres_errno) return(mr_errcode);
535 /* setup_dclu - verify that the cluster is no longer being referenced
536 * and may safely be deleted.
539 int setup_dclu(q, argv)
543 EXEC SQL BEGIN DECLARE SECTION;
545 EXEC SQL END DECLARE SECTION;
547 id = *(int *)argv[0];
548 EXEC SQL REPEATED SELECT COUNT(mach_id) INTO :cnt FROM mcmap
552 EXEC SQL REPEATED SELECT COUNT(clu_id) INTO :cnt FROM svc
562 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
563 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
564 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
565 * a -1 there. Remember that this is also used for ulis, with the indexes
566 * at 6 & 7. Also check that the list name does not contain uppercase
567 * characters, control characters, @, or :.
570 static int badlistchars[] = {
571 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
572 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
573 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
574 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, /* 0 - ? */
575 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* @ - O */
576 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, /* P - _ */
577 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
578 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
579 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
580 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
581 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
582 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
583 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
584 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
585 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
586 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
589 int setup_alis(q, argv, cl)
594 EXEC SQL BEGIN DECLARE SECTION;
596 EXEC SQL END DECLARE SECTION;
601 if (!strcmp(q->shortname, "alis"))
603 else if (!strcmp(q->shortname, "ulis"))
606 for (p = (unsigned char *) argv[idx]; *p; p++)
607 if (badlistchars[*p])
610 if (!strcmp(argv[6 + idx], UNIQUE_GID) || atoi(argv[6 + idx]) == -1) {
611 if (atoi(argv[5 + idx])) {
612 if (set_next_object_id("gid", "list", 1))
613 return(MR_INGRES_ERR);
614 EXEC SQL REPEATED SELECT value INTO :ngid FROM numvalues
616 if (ingres_errno) return(mr_errcode);
617 sprintf(argv[6 + idx], "%d", ngid);
619 strcpy(argv[6 + idx], "-1");
623 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
630 /* setup_dlis - verify that the list is no longer being referenced
631 * and may safely be deleted.
634 int setup_dlis(q, argv)
640 id = *(int *)argv[0];
641 sprintf(stmt_buf,"SELECT member_id FROM imembers WHERE member_id = %d AND member_type='LIST'",id);
642 if(ec=mr_select_any(stmt_buf)) {
643 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
646 sprintf(stmt_buf,"SELECT member_id FROM imembers WHERE list_id = %d",id);
647 if(ec=mr_select_any(stmt_buf)) {
648 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
651 sprintf(stmt_buf,"SELECT label FROM filesys WHERE owners = %d",id);
652 if(ec=mr_select_any(stmt_buf)) {
653 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
656 sprintf(stmt_buf,"SELECT tag FROM capacls WHERE list_id = %d",id);
657 if(ec=mr_select_any(stmt_buf)) {
658 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
661 sprintf(stmt_buf,"SELECT name FROM list WHERE acl_id = %d AND acl_type='LIST' AND list_id != %d",id,id);
662 if(ec=mr_select_any(stmt_buf)) {
663 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
666 sprintf(stmt_buf,"SELECT name FROM servers WHERE acl_id = %d AND acl_type='LIST'",id);
667 if(ec=mr_select_any(stmt_buf)) {
668 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
671 sprintf(stmt_buf,"SELECT entity_id FROM quota WHERE entity_id = %d AND type='GROUP'",id);
672 if(ec=mr_select_any(stmt_buf)) {
673 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
676 sprintf(stmt_buf,"SELECT acl_id FROM hostaccess WHERE acl_id = %d AND acl_type='LIST'",id);
677 if(ec=mr_select_any(stmt_buf)) {
678 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
681 sprintf(stmt_buf,"SELECT class FROM zephyr z \
682 WHERE z.xmt_type = 'LIST' AND z.xmt_id = %d \
683 OR z.sub_type = 'LIST' AND z.sub_id = %d \
684 OR z.iws_type = 'LIST' AND z.iws_id = %d \
685 OR z.iui_type = 'LIST' AND z.iui_id = %d",id,id,id,id);
686 if(ec=mr_select_any(stmt_buf)) {
687 if(ec==MR_EXISTS) return(MR_IN_USE); else return(ec);
694 /* setup_dsin - verify that the service is no longer being referenced
695 * and may safely be deleted.
698 int setup_dsin(q, argv)
702 EXEC SQL BEGIN DECLARE SECTION;
705 EXEC SQL END DECLARE SECTION;
707 sprintf(stmt_buf,"SELECT service FROM serverhosts WHERE service = UPPERCASE('%s')",argv[0]);
708 if(ec=mr_select_any(stmt_buf)) {
716 EXEC SQL SELECT inprogress INTO :ec FROM servers
717 WHERE name=UPPERCASE(:svrname);
727 /* setup_dshi - verify that the service-host is no longer being referenced
728 * and may safely be deleted.
731 int setup_dshi(q, argv)
735 EXEC SQL BEGIN DECLARE SECTION;
738 EXEC SQL END DECLARE SECTION;
741 id = *(int *)argv[1];
743 EXEC SQL SELECT inprogress INTO :ec FROM serverhosts
744 WHERE service=UPPERCASE(:svrname) AND mach_id = :id;
756 ** setup_add_filesys - verify existance of referenced file systems
768 ** * extract directory prefix from name
769 ** * verify mach_id/dir in nfsphys
770 ** * verify access in {r, w, R, W}
772 ** Side effect: sets variable var_phys_id to the ID of the physical
773 ** filesystem (nfsphys_id for NFS, 0 for RVD)
776 ** MR_NFS - specified directory not exported
777 ** MR_FILESYS_ACCESS - invalid filesys access
781 EXEC SQL BEGIN DECLARE SECTION;
782 static int var_phys_id;
783 EXEC SQL END DECLARE SECTION;
785 setup_afil(q, argv, cl)
792 EXEC SQL BEGIN DECLARE SECTION;
794 char ftype[32], *access;
795 EXEC SQL END DECLARE SECTION;
798 mach_id = *(int *)argv[2];
803 sprintf(ftype, "fs_access_%s", type);
804 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
805 WHERE name = :ftype AND type = 'TYPE' and trans = :access;
806 if (ingres_errno) return(mr_errcode);
807 if (ok == 0) return(MR_FILESYS_ACCESS);
809 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
812 if (!strcmp(type, "NFS"))
813 return (check_nfs(mach_id, name, access));
819 /* Verify the arguments, depending on the FStype. Also, if this is an
820 * NFS filesystem, then update any quotas for that filesystem to reflect
824 setup_ufil(q, argv, cl)
831 EXEC SQL BEGIN DECLARE SECTION;
832 int fid, total, who, ok;
833 char *entity, ftype[32], *access;
835 short int total_null;
836 EXEC SQL END DECLARE SECTION;
839 mach_id = *(int *)argv[3];
842 fid = *(int *)argv[0];
846 sprintf(ftype, "fs_access_%s", type);
847 EXEC SQL SELECT COUNT(trans) INTO :ok FROM alias
848 WHERE name = :ftype AND type='TYPE' AND trans = :access;
849 if (ingres_errno) return(mr_errcode);
850 if (ok == 0) return(MR_FILESYS_ACCESS);
852 EXEC SQL SELECT type INTO :ftype FROM filesys
853 WHERE filsys_id = :fid;
855 if (ingres_errno) return(mr_errcode);
857 if (!strcmp(type, "NFS")) {
858 status = check_nfs(mach_id, name, access);
859 EXEC SQL UPDATE quota SET phys_id = :var_phys_id
860 WHERE filsys_id = :fid;
861 if (ingres_errno) return(mr_errcode);
863 } else if (!strcmp(type, "AFS") && strcmp(ftype, "AFS")) {
865 EXEC SQL REPEATED DELETE FROM quota
866 WHERE type = 'ANY' AND filsys_id = :fid;
867 EXEC SQL SELECT SUM (quota) INTO :total:total_null FROM quota
868 WHERE filsys_id = :fid AND phys_id != 0;
869 if (ingres_errno) return(mr_errcode);
870 if (!total_null && (total != 0)) {
872 * append quota (quota = total, filsys_id = fid,
873 * phys_id = 0, entity_id = 0, type = "ANY",
874 * modtime = "now", modby = who, modwith = entity)
876 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
877 type, modtime, modby, modwith)
878 VALUES (:total, :fid, 0, 0,
879 'ANY', 'now', :who, :entity) ;
880 if (ingres_errno) return(mr_errcode);
883 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
884 if (ingres_errno) return(mr_errcode);
890 /* Find the NFS physical partition that the named directory is on.
891 * This is done by comparing the dir against the mount point of the
892 * partition. To make sure we get the correct match when there is
893 * more than one, we sort the query in reverse order by dir name.
896 check_nfs(mach_id, name, access)
897 EXEC SQL BEGIN DECLARE SECTION;
899 EXEC SQL END DECLARE SECTION;
903 EXEC SQL BEGIN DECLARE SECTION;
905 EXEC SQL END DECLARE SECTION;
912 EXEC SQL DECLARE csr101 CURSOR FOR
913 SELECT nfsphys_id, TRIM (dir) FROM nfsphys
914 WHERE mach_id = :mach_id
916 EXEC SQL OPEN csr101;
918 EXEC SQL FETCH csr101 INTO :var_phys_id, :dir;
919 if(sqlca.sqlcode != 0) break;
923 if (*cp1++ != *cp2) break;
931 EXEC SQL CLOSE csr101;
938 /* setup_dfil: free any quota records and fsgroup info associated with
939 * a filesystem when it is deleted. Also adjust the allocation numbers.
942 setup_dfil(q, argv, cl)
947 EXEC SQL BEGIN DECLARE SECTION;
948 int id, total, phys_id;
950 EXEC SQL END DECLARE SECTION;
952 id = *(int *)argv[0];
953 EXEC SQL REPEATED SELECT SUM (quota) INTO :total:none FROM quota
954 WHERE filsys_id = :id;
958 /** What if there are multiple phys_id's per f/s? (bad data) **/
959 EXEC SQL REPEATED SELECT phys_id INTO :phys_id FROM filesys
960 WHERE filsys_id = :id;
961 EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated - :total
962 WHERE nfsphys_id = :phys_id;
965 EXEC SQL REPEATED DELETE FROM quota WHERE filsys_id = :id;
967 EXEC SQL REPEATED DELETE FROM fsgroup WHERE filsys_id = :id;
968 EXEC SQL REPEATED DELETE FROM fsgroup WHERE group_id = :id;
969 if (ingres_errno) return(mr_errcode);
974 /* setup_dnfp: check to see that the nfs physical partition does not have
975 * any filesystems assigned to it before allowing it to be deleted.
978 setup_dnfp(q, argv, cl)
983 EXEC SQL BEGIN DECLARE SECTION;
986 EXEC SQL END DECLARE SECTION;
988 id = *(int *)argv[0];
990 EXEC SQL REPEATED SELECT label INTO :cnt FROM filesys fs, nfsphys np
991 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
992 AND np.mach_id = :id AND np.dir = :dir;
1001 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
1002 * argv[0] = filsys_id
1003 * argv[1] = type if "update_quota" or "delete_quota"
1004 * argv[2 or 1] = users_id or list_id
1007 setup_dqot(q, argv, cl)
1012 EXEC SQL BEGIN DECLARE SECTION;
1013 int quota, fs, id, physid;
1015 EXEC SQL END DECLARE SECTION;
1017 fs = *(int *)argv[0];
1018 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
1020 id = *(int *)argv[2];
1023 id = *(int *)argv[1];
1026 EXEC SQL REPEATED SELECT quota INTO :quota FROM quota
1027 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
1028 EXEC SQL REPEATED SELECT phys_id INTO :physid FROM filesys
1029 WHERE filsys_id = :fs;
1030 EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated - :quota
1031 WHERE nfsphys_id = :physid;
1033 if (ingres_errno) return(mr_errcode);
1038 /* setup_sshi: don't exclusive lock the machine table during
1039 * set_server_host_internal.
1041 /** Not allowed under (INGRES) SQL **/
1042 setup_sshi(q, argv, cl)
1049 EXEC SQL set lockmode session where readlock = system;
1056 /* setup add_kerberos_user_mapping: add the string to the string
1057 * table if necessary.
1060 setup_akum(q, argv, cl)
1065 EXEC SQL BEGIN DECLARE SECTION;
1068 EXEC SQL END DECLARE SECTION;
1071 if (name_to_id(name, "STRING", &id) != MR_SUCCESS) {
1072 if (q->type != APPEND) return(MR_STRING);
1073 EXEC SQL SELECT value INTO :id FROM numvalues
1074 WHERE name = 'strings_id';
1076 EXEC SQL UPDATE numvalues SET value = :id
1077 WHERE name = 'strings_id';
1078 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
1079 cache_entry(name, "STRING", id);
1081 if (ingres_errno) return(mr_errcode);
1082 *(int *)argv[1] = id;
1088 /* FOLLOWUP ROUTINES */
1090 /* generic set_modtime routine. This takes the table name from the query,
1091 * and will update the modtime, modby, and modwho fields in the entry in
1092 * the table whose name field matches argv[0].
1095 set_modtime(q, argv, cl)
1100 char *name, *entity, *table;
1103 entity = cl->entity;
1104 who = cl->client_id;
1108 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, modwith = '%s' WHERE %s.name = LEFT('%s',SIZE(%s.name))",table,who,entity,table,name,table);
1109 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1114 /* generic set_modtime_by_id routine. This takes the table name from
1115 * the query, and the id name from the validate record,
1116 * and will update the modtime, modby, and modwho fields in the entry in
1117 * the table whose id matches argv[0].
1120 set_modtime_by_id(q, argv, cl)
1125 char *entity, *table, *id_name;
1128 entity = cl->entity;
1129 who = cl->client_id;
1131 id_name = q->validate->object_id;
1133 id = *(int *)argv[0];
1134 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, \
1135 modwith = '%s' WHERE %s.%s = %d",table,who,entity,table,id_name,id);
1136 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1141 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
1144 set_finger_modtime(q, argv, cl)
1149 EXEC SQL BEGIN DECLARE SECTION;
1152 EXEC SQL END DECLARE SECTION;
1154 entity = cl->entity;
1155 who = cl->client_id;
1156 users_id = *(int *)argv[0];
1158 EXEC SQL UPDATE users SET fmodtime='now', fmodby = :who, fmodwith = :entity
1159 WHERE users.users_id = :users_id;
1165 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
1168 set_pobox_modtime(q, argv, cl)
1173 EXEC SQL BEGIN DECLARE SECTION;
1176 EXEC SQL END DECLARE SECTION;
1178 entity = cl->entity;
1179 who = cl->client_id;
1180 users_id = *(int *)argv[0];
1182 EXEC SQL UPDATE users SET pmodtime='now', pmodby = :who, pmodwith = :entity
1183 WHERE users.users_id = :users_id;
1189 /* Like set_modtime, but uppercases the name first.
1192 set_uppercase_modtime(q, argv, cl)
1197 char *name, *entity, *table;
1200 entity = cl->entity;
1201 who = cl->client_id;
1205 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, modwith = '%s' WHERE %s.name = UPPERCASE(LEFT('%s',SIZE(%s.name)))",table,who,entity,table,name,table);
1206 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1212 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
1213 * is necessary for add_machine_to_cluster becuase the table that query
1214 * operates on is "mcm", not "machine".
1217 set_mach_modtime_by_id(q, argv, cl)
1222 EXEC SQL BEGIN DECLARE SECTION;
1225 EXEC SQL END DECLARE SECTION;
1227 entity = cl->entity;
1228 who = cl->client_id;
1229 id = *(int *)argv[0];
1230 EXEC SQL UPDATE machine SET modtime='now', modby = :who, modwith = :entity
1231 WHERE machine.mach_id = :id;
1237 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
1238 * is necessary for add_cluster_data and delete_cluster_data becuase the
1239 * table that query operates on is "svc", not "cluster".
1242 set_cluster_modtime_by_id(q, argv, cl)
1247 EXEC SQL BEGIN DECLARE SECTION;
1250 EXEC SQL END DECLARE SECTION;
1252 entity = cl->entity;
1253 who = cl->client_id;
1255 id = *(int *)argv[0];
1256 EXEC SQL UPDATE cluster SET modtime='now', modby = :who, modwith = :entity
1257 WHERE cluster.clu_id = :id;
1262 /* sets the modtime on the serverhost where the service name is in argv[0]
1263 * and the mach_id is in argv[1].
1266 set_serverhost_modtime(q, argv, cl)
1271 EXEC SQL BEGIN DECLARE SECTION;
1272 char *entity, *serv;
1274 EXEC SQL END DECLARE SECTION;
1276 entity = cl->entity;
1277 who = cl->client_id;
1280 id = *(int *)argv[1];
1281 EXEC SQL UPDATE serverhosts
1282 SET modtime = 'now', modby = :who, modwith = :entity
1283 WHERE service = :serv AND mach_id = :id;
1288 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1289 * directory name is in argv[1].
1292 set_nfsphys_modtime(q, argv, cl)
1297 EXEC SQL BEGIN DECLARE SECTION;
1300 EXEC SQL END DECLARE SECTION;
1302 entity = cl->entity;
1303 who = cl->client_id;
1305 id = *(int *)argv[0];
1307 EXEC SQL UPDATE nfsphys SET modtime = 'now', modby = :who, modwith = :entity
1308 WHERE dir = :dir AND mach_id = :id;
1313 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1317 set_filesys_modtime(q, argv, cl)
1322 EXEC SQL BEGIN DECLARE SECTION;
1323 char *label, *entity;
1325 EXEC SQL END DECLARE SECTION;
1327 entity = cl->entity;
1328 who = cl->client_id;
1331 if (!strcmp(q->shortname, "ufil"))
1334 EXEC SQL UPDATE filesys SET modtime = 'now', modby = :who,
1335 modwith = :entity, phys_id = :var_phys_id
1336 WHERE label = LEFT(:label,SIZE(label));
1341 /* sets the modtime on a zephyr class, where argv[0] contains the class
1345 set_zephyr_modtime(q, argv, cl)
1350 EXEC SQL BEGIN DECLARE SECTION;
1351 char *class, *entity;
1353 EXEC SQL END DECLARE SECTION;
1355 entity = cl->entity;
1356 who = cl->client_id;
1360 EXEC SQL UPDATE zephyr SET modtime = 'now', modby = :who, modwith = :entity
1361 WHERE class = LEFT(:class,SIZE(class));
1367 /* fixes the modby field. This will be the second to last thing in the
1368 * argv, the argv length is determined from the query structure. It is
1369 * passed as a pointer to an integer. This will either turn it into a
1370 * username, or # + the users_id.
1372 followup_fix_modby(q, sq, v, action, actarg, cl)
1374 register struct save_queue *sq;
1376 register int (*action)();
1377 register int actarg;
1381 char **argv, *malloc();
1385 while (sq_get_data(sq, &argv)) {
1388 status = id_to_name(id, "USER", &argv[i]);
1390 status = id_to_name(-id, "STRING", &argv[i]);
1391 if (status && status != MR_NO_MATCH)
1393 (*action)(q->vcnt, argv, actarg);
1394 for (j = 0; j < q->vcnt; j++)
1403 /* After retrieving a user account, fix the modby field and signature.
1404 * The modby field is the second to last thing in the
1405 * argv, the argv length is determined from the query structure. It is
1406 * passed as a pointer to an integer. This will either turn it into a
1407 * username, or # + the users_id. Only "gua*" queries have a signature,
1408 * these are ones with U_END return values. "gub*" queries also use this
1409 * routine but don't have a signature.
1411 followup_guax(q, sq, v, action, actarg, cl)
1413 register struct save_queue *sq;
1415 register int (*action)();
1416 register int actarg;
1420 char **argv, *malloc();
1422 unsigned char sigbuf[256];
1425 EXEC SQL BEGIN DECLARE SECTION;
1428 varchar struct { short data_size; char data_buf[257];} rsig;
1429 EXEC SQL END DECLARE SECTION;
1434 while (sq_get_data(sq, &argv)) {
1436 com_err(whoami, 0, "argv[SIGNATURE] = \"%s\"", argv[U_SIGNATURE]);
1440 status = id_to_name(id, "USER", &argv[i]);
1442 status = id_to_name(-id, "STRING", &argv[i]);
1443 if (status && status != MR_NO_MATCH)
1446 if (q->vcnt == U_END && strlen(argv[U_SIGNATURE])) {
1447 login = argv[U_NAME];
1448 EXEC SQL REPEATED SELECT signature, sigdate, sigwho
1449 INTO :rsig, :timestamp, :who FROM users
1450 WHERE login = :login;
1451 /** What about (INGRES) error handling? **/
1453 status = id_to_name(who, "STRING", &kname);
1454 si.timestamp = timestamp;
1455 si.SigInfoVersion = 0; /* XXXXX this isn't used */
1456 kname_parse(si.pname, si.pinst, si.prealm, kname);
1458 rsig.data_buf[rsig.data_size] = 0;
1459 si.rawsig = (unsigned char *)strsave(rsig.data_buf);
1461 com_err(whoami, 0, "rawsig length = %d, sig=\"%s\"", strlen(si.rawsig), si.rawsig);
1463 GDSS_Recompose(&si, sigbuf);
1465 free(argv[U_SIGNATURE]);
1466 argv[U_SIGNATURE] = strsave(sigbuf);
1468 com_err(whoami, 0, "generated signature length %d", strlen(sigbuf));
1472 (*action)(q->vcnt, argv, actarg);
1473 for (j = 0; j < q->vcnt; j++)
1483 ** followup_ausr - add finger and pobox entries, set_user_modtime
1486 ** argv[0] - login (add_user)
1487 ** argv[3] - last name
1488 ** argv[4] - first name
1489 ** argv[5] - middle name
1493 followup_ausr(q, argv, cl)
1498 EXEC SQL BEGIN DECLARE SECTION;
1499 int who, status, id;
1500 char *login, *entity, *src, *dst, *name;
1502 EXEC SQL END DECLARE SECTION;
1504 char databuf[32], *kname_unparse();
1505 EXEC SQL BEGIN DECLARE SECTION;
1507 int sigwho, timestamp;
1508 EXEC SQL END DECLARE SECTION;
1512 /* build fullname */
1513 if (strlen(argv[4]) && strlen(argv[5]))
1514 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1515 else if (strlen(argv[4]))
1516 sprintf(fullname, "%s %s", argv[4], argv[3]);
1518 sprintf(fullname, "%s", argv[3]);
1521 if (q->vcnt == U_END && *argv[U_SIGNATURE]) {
1522 sprintf(databuf, "%s:%s", argv[U_NAME], argv[U_MITID]);
1523 /* skip bytes for timestamp & kname */
1524 si.rawsig = (unsigned char *) rawsig;
1525 status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE], &si);
1526 if (strlen(rawsig) > mr_sig_length) {
1527 com_err(whoami, 0, "GDSS signature would be truncated."); /** untested **/
1528 return(MR_INTERNAL);
1531 name = kname_unparse(si.pname, si.pinst, si.prealm);
1532 status = name_to_id(name, "STRING", &sigwho);
1533 if (status == MR_NO_MATCH) {
1534 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1535 WHERE name='strings_id';
1537 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1538 WHERE name='strings_id';
1539 EXEC SQL INSERT INTO strings (string_id, string)
1540 VALUES (:sigwho, :name);
1542 return(gdss2et(status));
1543 timestamp = si.timestamp;
1545 return(gdss2et(status));
1554 who = cl->client_id;
1555 entity = cl->entity;
1557 /* create finger entry, pobox & set modtime on user */
1559 EXEC SQL REPEATED UPDATE users
1560 SET modtime='now', modby=:who, modwith = :entity,
1561 fullname = :fullname, affiliation = type,
1562 signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho,
1563 fmodtime='now', fmodby = :who, fmodwith = :entity,
1564 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1565 WHERE login = :login;
1567 EXEC SQL REPEATED UPDATE users
1568 SET modtime='now', modby=:who, modwith = :entity,
1569 fullname = :fullname, affiliation = type,
1570 fmodtime='now', fmodby = :who, fmodwith = :entity,
1571 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1572 WHERE login = :login;
1580 ** followup_uusr - do signature, set_user_modtime
1583 ** argv[0] - login (add_user)
1584 ** argv[U_SIGNATURE] - sig
1588 followup_uuac(q, argv, cl)
1593 EXEC SQL BEGIN DECLARE SECTION;
1594 int who, status, id;
1595 char *entity, *name;
1596 EXEC SQL END DECLARE SECTION;
1598 char databuf[32], *kname_unparse();
1599 EXEC SQL BEGIN DECLARE SECTION;
1602 int sigwho, timestamp;
1603 EXEC SQL END DECLARE SECTION;
1607 id = *(int *)argv[0];
1608 who = cl->client_id;
1609 entity = cl->entity;
1612 if (q->vcnt == U_MODTIME && *argv[U_SIGNATURE + 1]) {
1614 status = id_to_name(id, "USER", &login);
1615 sprintf(databuf, "%s:%s", login, argv[U_MITID+1]);
1617 /* skip bytes for timestamp & kname */
1618 si.rawsig = (unsigned char *) rawsig;
1620 com_err(whoami, 0, "verifying sig");
1622 status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE+1], &si);
1624 com_err(whoami, 0, "verified");
1626 if (strlen(rawsig) > mr_sig_length) {
1627 com_err(whoami, 0, "GDSS signature would be truncated."); /** untested **/
1628 return(MR_INTERNAL);
1631 name = kname_unparse(si.pname, si.pinst, si.prealm);
1632 status = name_to_id(name, "STRING", &sigwho);
1633 if (status == MR_NO_MATCH) {
1634 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1635 WHERE name='strings_id';
1637 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1638 WHERE name='strings_id';
1639 EXEC SQL INSERT INTO strings (string_id, string)
1640 VALUES (:sigwho, :name);
1642 return(gdss2et(status));
1643 timestamp = si.timestamp;
1645 return(gdss2et(status));
1653 /* create finger entry, pobox & set modtime on user */
1656 EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity,
1657 signature = :rawsig, sigdate = :timestamp, sigwho = :sigwho
1658 WHERE users_id = :id;
1660 EXEC SQL REPEATED UPDATE users SET modtime='now', modby = :who, modwith = :entity
1661 WHERE users_id = :id;
1667 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1668 * type in argv[1]. Then completes the upcall to the user.
1670 * argv[2] is of the form "123:234" where the first integer is the machine
1671 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1672 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1676 followup_gpob(q, sq, v, action, actarg, cl)
1677 register struct query *q;
1678 register struct save_queue *sq;
1679 register struct validate *v;
1680 register int (*action)();
1684 char **argv, *index();
1686 int mid, sid, status, i;
1689 while (sq_get_data(sq, &argv)) {
1690 mr_trim_args(2, argv);
1692 p = index(argv[2], ':');
1694 mid = atoi(argv[2]);
1697 if (!strcmp(ptype, "POP")) {
1698 status = id_to_name(mid, "MACHINE", &argv[2]);
1699 if (status == MR_NO_MATCH)
1701 } else if (!strcmp(ptype, "SMTP")) {
1702 status = id_to_name(sid, "STRING", &argv[2]);
1703 if (status == MR_NO_MATCH)
1705 } else /* ptype == "NONE" */ {
1708 if (status) return(status);
1710 if (!strcmp(q->shortname, "gpob")) {
1711 sid = atoi(argv[4]);
1713 status = id_to_name(sid, "USER", &argv[4]);
1715 status = id_to_name(-sid, "STRING", &argv[4]);
1717 if (status && status != MR_NO_MATCH) return(status);
1719 (*action)(q->vcnt, argv, actarg);
1721 /* free saved data */
1722 for (i = 0; i < q->vcnt; i++)
1728 return (MR_SUCCESS);
1732 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1733 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1734 * proper name based on the type, and repace that string in the argv.
1735 * Also fixes the modby field by called followup_fix_modby.
1738 followup_glin(q, sq, v, action, actarg, cl)
1739 register struct query *q;
1740 register struct save_queue *sq;
1741 register struct validate *v;
1742 register int (*action)();
1746 char **argv, *malloc(), *realloc(), *type;
1747 int id, i, idx, status;
1750 if (!strcmp(q->shortname, "gsin"))
1753 while (sq_get_data(sq, &argv)) {
1754 mr_trim_args(q->vcnt, argv);
1756 id = atoi(argv[i = q->vcnt - 2]);
1758 status = id_to_name(id, "USER", &argv[i]);
1760 status = id_to_name(-id, "STRING", &argv[i]);
1761 if (status && status != MR_NO_MATCH)
1764 id = atoi(argv[idx]);
1765 type = argv[idx - 1];
1767 if (!strcmp(type, "LIST")) {
1768 status = id_to_name(id, "LIST", &argv[idx]);
1769 } else if (!strcmp(type, "USER")) {
1770 status = id_to_name(id, "USER", &argv[idx]);
1771 } else if (!strcmp(type, "KERBEROS")) {
1772 status = id_to_name(id, "STRING", &argv[idx]);
1773 } else if (!strcmp(type, "NONE")) {
1776 argv[idx] = strsave("NONE");
1780 argv[idx] = strsave("???");
1782 if (status && status != MR_NO_MATCH)
1785 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1786 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1787 strcpy(argv[6], UNIQUE_GID);
1791 (*action)(q->vcnt, argv, actarg);
1793 /* free saved data */
1794 for (i = 0; i < q->vcnt; i++)
1800 return (MR_SUCCESS);
1804 /* followup_gqot: Fix the entity name, directory name & modby fields
1805 * argv[0] = filsys_id
1807 * argv[2] = entity_id
1808 * argv[3] = ascii(quota)
1811 followup_gqot(q, sq, v, action, actarg, cl)
1813 register struct save_queue *sq;
1815 register int (*action)();
1816 register int actarg;
1820 char **argv, *malloc();
1821 EXEC SQL BEGIN DECLARE SECTION;
1824 EXEC SQL END DECLARE SECTION;
1827 if (!strcmp(q->name, "get_quota") ||
1828 !strcmp(q->name, "get_quota_by_filesys"))
1832 while (sq_get_data(sq, &argv)) {
1834 switch (argv[1][0]) {
1836 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1840 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1844 argv[2] = strsave("system:anyuser");
1848 argv[2] = malloc(8);
1849 sprintf(argv[2], "%d", id);
1852 id = atoi(argv[idx]);
1854 argv[idx] = malloc(256);
1858 EXEC SQL REPEATED SELECT name INTO :name FROM filesys
1859 WHERE label = :label;
1861 EXEC SQL REPEATED SELECT dir INTO :name FROM nfsphys
1862 WHERE nfsphys_id = :id;
1864 if (sqlca.sqlerrd[2] != 1) {
1865 sprintf(argv[idx], "#%d", id);
1868 id = atoi(argv[idx+3]);
1870 status = id_to_name(id, "USER", &argv[idx+3]);
1872 status = id_to_name(-id, "STRING", &argv[idx+3]);
1873 if (status && status != MR_NO_MATCH)
1875 (*action)(q->vcnt, argv, actarg);
1876 for (j = 0; j < q->vcnt; j++)
1885 /* followup_aqot: Add allocation to nfsphys after creating quota.
1886 * argv[0] = filsys_id
1887 * argv[1] = type if "add_quota" or "update_quota"
1889 * argv[3 or 2] = ascii(quota)
1892 followup_aqot(q, argv, cl)
1897 EXEC SQL BEGIN DECLARE SECTION;
1898 int quota, id, fs, who, physid;
1899 char *entity, *qtype, *table_name;
1900 EXEC SQL END DECLARE SECTION;
1905 table_name=q->rtable;
1906 fs = *(int *)argv[0];
1907 EXEC SQL REPEATED SELECT phys_id INTO :physid FROM filesys
1908 WHERE filsys_id = :fs;
1912 if (!strcmp(q->shortname, "aqot") || !strcmp(q->shortname, "uqot")) {
1914 id = *(int *)argv[2];
1915 quota = atoi(argv[3]);
1916 sprintf(incr_qual,"q.filsys_id = %d",fs);
1919 id = *(int *)argv[1];
1920 quota = atoi(argv[2]);
1921 sprintf(incr_qual,"q.filsys_id=%d AND q.type='%s' AND q.entity_id=%d",
1925 /* quota case of incremental_{before|after} only looks at slot 1 */
1928 /* Follows one of many possible gross hacks to fix these particular
1929 * conflicts between what is possible in the query table and what
1930 * is possible in SQL.
1932 if(q->type==APPEND) {
1933 incremental_clear_before();
1934 EXEC SQL INSERT INTO quota
1935 (filsys_id, type, entity_id, quota, phys_id)
1936 VALUES (:fs, :qtype, :id, :quota, :physid);
1937 incremental_after(table_name, incr_qual, incr_argv);
1939 incremental_before(table_name, incr_qual, incr_argv);
1940 EXEC SQL UPDATE quota SET quota = :quota
1941 WHERE filsys_id = :fs AND type = :qtype AND entity_id = :id;
1942 status = mr_errcode;
1943 incremental_after(table_name, incr_qual, incr_argv);
1948 flush_name(argv[0], q->rtable);
1949 if(q->type==APPEND) {
1950 EXEC SQL UPDATE tblstats SET appends = appends + 1, modtime = 'now'
1951 WHERE table_name = :table_name;
1953 EXEC SQL UPDATE tblstats SET updates = updates + 1, modtime = 'now'
1954 WHERE table_name = :table_name;
1957 /* Proceed with original followup */
1958 who = cl->client_id;
1959 entity = cl->entity;
1961 EXEC SQL REPEATED UPDATE quota
1962 SET modtime = 'now', modby = :who, modwith = :entity
1963 WHERE filsys_id = :fs and type = :qtype and entity_id = :id;
1964 EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated + :quota
1965 WHERE nfsphys_id = :physid;
1966 if (ingres_errno) return(mr_errcode);
1971 /* Necessitated by the requirement of a correlation name by the incremental
1972 * routines, since query table deletes don't provide one.
1974 followup_dqot(q,argv,cl)
1982 EXEC SQL BEGIN DECLARE SECTION;
1985 EXEC SQL END DECLARE SECTION;
1987 fs = *(int *)argv[0];
1988 if (!strcmp(q->shortname, "dqot")) {
1990 id = *(int *)argv[2];
1993 id = *(int *)argv[1];
1995 sprintf(incr_qual,"q.filsys_id=%d AND q.type='%s' AND q.entity_id=%d",
1998 /* quota case of incremental_{before|after} only looks at slot 1 */
2001 incremental_before(q->rtable, incr_qual, incr_argv);
2002 EXEC SQL DELETE FROM quota q WHERE :incr_qual;
2003 incremental_clear_after();
2007 flush_name(argv[0], q->rtable);
2009 tblname = q->rtable;
2010 EXEC SQL UPDATE tblstats SET deletes = deletes + 1, modtime = 'now'
2011 WHERE table_name = :tblname;
2016 followup_gpce(q, sq, v, action, actarg, cl)
2018 register struct save_queue *sq;
2020 register int (*action)();
2021 register int actarg;
2025 char **argv, *malloc();
2029 while (sq_get_data(sq, &argv)) {
2030 id = atoi(argv[PCAP_QSERVER]);
2031 status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
2032 if (status) return (status);
2035 status = id_to_name(id, "USER", &argv[i]);
2037 status = id_to_name(-id, "STRING", &argv[i]);
2038 if (status && status != MR_NO_MATCH)
2040 (*action)(q->vcnt, argv, actarg);
2041 for (j = 0; j < q->vcnt; j++)
2053 followup_gzcl(q, sq, v, action, actarg, cl)
2054 register struct query *q;
2055 register struct save_queue *sq;
2056 register struct validate *v;
2057 register int (*action)();
2064 while (sq_get_data(sq, &argv)) {
2065 mr_trim_args(q->vcnt, argv);
2067 id = atoi(argv[i = q->vcnt - 2]);
2069 status = id_to_name(id, "USER", &argv[i]);
2071 status = id_to_name(-id, "STRING", &argv[i]);
2072 if (status && status != MR_NO_MATCH)
2075 for (i = 1; i < 8; i+=2) {
2076 id = atoi(argv[i+1]);
2077 if (!strcmp(argv[i], "LIST")) {
2078 status = id_to_name(id, "LIST", &argv[i+1]);
2079 } else if (!strcmp(argv[i], "USER")) {
2080 status = id_to_name(id, "USER", &argv[i+1]);
2081 } else if (!strcmp(argv[i], "KERBEROS")) {
2082 status = id_to_name(id, "STRING", &argv[i+1]);
2083 } else if (!strcmp(argv[i], "NONE")) {
2086 argv[i+1] = strsave("NONE");
2090 argv[i+1] = strsave("???");
2092 if (status && status != MR_NO_MATCH)
2097 (*action)(q->vcnt, argv, actarg);
2099 /* free saved data */
2100 for (i = 0; i < q->vcnt; i++)
2112 followup_gsha(q, sq, v, action, actarg, cl)
2113 register struct query *q;
2114 register struct save_queue *sq;
2115 register struct validate *v;
2116 register int (*action)();
2123 while (sq_get_data(sq, &argv)) {
2124 mr_trim_args(q->vcnt, argv);
2128 status = id_to_name(id, "USER", &argv[4]);
2130 status = id_to_name(-id, "STRING", &argv[4]);
2131 if (status && status != MR_NO_MATCH)
2135 if (!strcmp(argv[1], "LIST")) {
2136 status = id_to_name(id, "LIST", &argv[2]);
2137 } else if (!strcmp(argv[1], "USER")) {
2138 status = id_to_name(id, "USER", &argv[2]);
2139 } else if (!strcmp(argv[1], "KERBEROS")) {
2140 status = id_to_name(id, "STRING", &argv[2]);
2141 } else if (!strcmp(argv[1], "NONE")) {
2144 argv[2] = strsave("NONE");
2148 argv[2] = strsave("???");
2150 if (status && status != MR_NO_MATCH)
2154 (*action)(q->vcnt, argv, actarg);
2156 /* free saved data */
2157 for (i = 0; i < q->vcnt; i++)
2167 /* Special query routines */
2169 /* set_pobox - this does all of the real work.
2170 * argv = user_id, type, box
2171 * if type is POP, then box should be a machine, and its ID should be put in
2172 * pop_id. If type is SMTP, then box should be a string and its ID should
2173 * be put in box_id. If type is NONE, then box doesn't matter.
2176 int set_pobox(q, argv, cl)
2181 EXEC SQL BEGIN DECLARE SECTION;
2183 char *box, potype[9];
2184 EXEC SQL END DECLARE SECTION;
2188 user = *(int *)argv[0];
2190 EXEC SQL REPEATED SELECT pop_id, potype INTO :id, :potype FROM users
2191 WHERE users_id = :user;
2192 if (ingres_errno) return(mr_errcode);
2193 if (!strcmp(strtrim(potype), "POP"))
2194 set_pop_usage(id, -1);
2196 if (!strcmp(argv[1], "POP")) {
2197 status = name_to_id(box, "MACHINE", &id);
2198 if (status == MR_NO_MATCH)
2202 EXEC SQL REPEATED UPDATE users SET potype = 'POP', pop_id = :id
2203 WHERE users_id = :user;
2204 set_pop_usage(id, 1);
2205 } else if (!strcmp(argv[1], "SMTP")) {
2206 if (index(box, '/') || index(box, '|'))
2207 return(MR_BAD_CHAR);
2208 status = name_to_id(box, "STRING", &id);
2209 if (status == MR_NO_MATCH) {
2210 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
2211 WHERE name='strings_id';
2213 EXEC SQL REPEATED UPDATE numvalues SET value = :id
2214 WHERE name='strings_id';
2215 EXEC SQL INSERT INTO strings (string_id, string)
2219 EXEC SQL REPEATED UPDATE users SET potype='SMTP', box_id = :id
2220 WHERE users_id = :user;
2221 } else /* argv[1] == "NONE" */ {
2222 EXEC SQL REPEATED UPDATE users SET potype='NONE'
2223 WHERE users_id = :user;
2226 set_pobox_modtime(q, argv, cl);
2227 EXEC SQL REPEATED UPDATE tblstats SET updates = updates+1, modtime='now'
2228 WHERE table_name='users';
2229 if (ingres_errno) return(mr_errcode);
2234 /* get_list_info: passed a wildcard list name, returns lots of stuff about
2235 * each list. This is tricky: first build a queue of all requested
2236 * data. Rest of processing consists of fixing gid, ace_name, and modby.
2239 get_list_info(q, aargv, cl, action, actarg)
2240 register struct query *q;
2243 register int (*action)();
2246 char *argv[13], *malloc(), *realloc();
2247 EXEC SQL BEGIN DECLARE SECTION;
2248 char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
2249 char maillist[5], grouplist[5], gid_str[6], acl_name[256], desc[256];
2250 char modtime[27], modby[256], modwith[9];
2251 int id, rowcount, acl_id, hid, modby_id;
2253 EXEC SQL END DECLARE SECTION;
2254 int returned, status;
2255 struct save_queue *sq, *sq_create();
2257 returned = rowcount = 0;
2259 convert_wildcards(name);
2262 sprintf(qual,"name LIKE '%s' ESCAPE '*'",name);
2263 optimize_sql_stmt(qual);
2264 EXEC SQL DECLARE csr102 CURSOR FOR SELECT list_id FROM list
2266 EXEC SQL OPEN csr102;
2269 EXEC SQL FETCH csr102 INTO :id;
2270 if(sqlca.sqlcode!=0) break;
2271 sq_save_data(sq, id);
2274 EXEC SQL CLOSE csr102;
2276 if (ingres_errno) return(mr_errcode);
2278 return(MR_NO_MATCH);
2280 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
2281 argv[4] = maillist; argv[5] = grouplist; argv[6] = gid_str;
2282 argv[7] = acl_type; argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
2284 while (sq_get_data(sq, &id)) {
2288 EXEC SQL REPEATED SELECT name, CHAR(active), CHAR(publicflg),
2289 CHAR(hidden), hidden, CHAR(maillist), CHAR(grouplist), CHAR(gid),
2290 TRIM(acl_type), acl_id, description, CHAR(modtime), modby, modwith
2291 INTO :listname, :active, :public, :hidden, :hid, :maillist,
2292 :grouplist, :gid_str, :acl_type, :acl_id, :desc,
2293 :modtime, :modby_id, :modwith
2294 FROM list WHERE list_id = :id;
2296 if (ingres_errno) return(mr_errcode);
2298 if (atoi(gid_str) == -1)
2299 argv[6] = UNIQUE_GID;
2301 argv[8] = malloc(0);
2302 if (!strcmp(acl_type, "LIST")) {
2303 status = id_to_name(acl_id, "LIST", &argv[8]);
2304 } else if (!strcmp(acl_type, "USER")) {
2305 status = id_to_name(acl_id, "USER", &argv[8]);
2306 } else if (!strcmp(acl_type, "KERBEROS")) {
2307 status = id_to_name(acl_id, "STRING", &argv[8]);
2308 } else if (!strcmp(acl_type, "NONE")) {
2311 argv[8] = strsave("NONE");
2315 argv[8] = strsave("???");
2317 if (status && status != MR_NO_MATCH) return(status);
2319 argv[11] = malloc(0);
2321 status = id_to_name(modby_id, "USER", &argv[11]);
2323 status = id_to_name(-modby_id, "STRING", &argv[11]);
2324 if (status && status != MR_NO_MATCH) return(status);
2326 mr_trim_args(q->vcnt, argv);
2328 (*action)(q->vcnt, argv, actarg);
2334 if (ingres_errno) return(mr_errcode);
2335 return (MR_SUCCESS);
2339 /* Add_member_to_list: do list flattening as we go! MAXLISTDEPTH is
2340 * how many different ancestors a member is allowed to have.
2343 #define MAXLISTDEPTH 1024
2345 int add_member_to_list(q, argv, cl)
2350 EXEC SQL BEGIN DECLARE SECTION;
2351 int id, lid, mid, error, who, ref, rowcnt;
2352 char *mtype, dtype[9], *entity;
2353 EXEC SQL END DECLARE SECTION;
2354 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2355 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2357 char *dtypes[MAXLISTDEPTH];
2358 char *iargv[3], *buf;
2360 lid = *(int *)argv[0];
2362 mid = *(int *)argv[2];
2363 /* if the member is already a direct member of the list, punt */
2364 EXEC SQL REPEATED SELECT COUNT(list_id) INTO :rowcnt FROM imembers
2365 WHERE list_id = :lid AND member_id = :mid
2366 AND member_type = :mtype AND direct = 1;
2369 if (!strcasecmp(mtype, "STRING")) {
2371 status = id_to_name(mid, "STRING", &buf);
2372 if (status) return(status);
2373 if (index(buf, '/') || index(buf, '|')) {
2375 return(MR_BAD_CHAR);
2383 EXEC SQL DECLARE csr103 CURSOR FOR
2384 SELECT list_id, ref_count FROM imembers
2385 WHERE member_id = :lid AND member_type='LIST';
2386 EXEC SQL OPEN csr103;
2388 EXEC SQL FETCH csr103 INTO :id, :ref;
2389 if(sqlca.sqlcode != 0) break;
2391 ancestors[acount++] = id;
2392 if (acount >= MAXLISTDEPTH) break;
2394 EXEC SQL CLOSE csr103;
2395 if (ingres_errno) return(mr_errcode);
2396 if (acount >= MAXLISTDEPTH) {
2397 return(MR_INTERNAL);
2399 descendants[0] = mid;
2404 if (!strcmp(mtype, "LIST")) {
2405 EXEC SQL DECLARE csr104 CURSOR FOR
2406 SELECT member_id, member_type, ref_count
2408 WHERE list_id = :mid;
2409 EXEC SQL OPEN csr104;
2411 EXEC SQL FETCH csr104 INTO :id, :dtype, :ref;
2412 if(sqlca.sqlcode != 0) break;
2415 dtypes[dcount] = "LIST";
2418 dtypes[dcount] = "USER";
2421 dtypes[dcount] = "STRING";
2424 dtypes[dcount] = "KERBEROS";
2431 descendants[dcount++] = id;
2432 if (dcount >= MAXLISTDEPTH) {
2437 EXEC SQL CLOSE csr104;
2438 if (ingres_errno) return(mr_errcode);
2440 return(MR_INTERNAL);
2442 for (a = 0; a < acount; a++) {
2444 for (d = 0; d < dcount; d++) {
2445 mid = descendants[d];
2447 if (mid == lid && !strcmp(mtype, "LIST")) {
2448 return(MR_LISTLOOP);
2450 EXEC SQL REPEATED SELECT COUNT(ref_count) INTO :rowcnt
2452 WHERE list_id = :lid AND member_id = :mid
2453 AND member_type = :mtype;
2454 ref = aref[a] * dref[d];
2456 if (a == 0 && d == 0) {
2457 EXEC SQL UPDATE imembers
2458 SET ref_count = ref_count+:ref, direct=1
2459 WHERE list_id = :lid AND member_id = :mid
2460 AND member_type = :mtype;
2462 EXEC SQL UPDATE imembers
2463 SET ref_count = ref_count+:ref
2464 WHERE list_id = :lid AND member_id = :mid
2465 AND member_type = :mtype;
2468 incremental_clear_before();
2469 if (a == 0 && d == 0) {
2470 EXEC SQL INSERT INTO imembers
2471 (list_id, member_id, direct, member_type, ref_count)
2472 VALUES (:lid, :mid, 1, :mtype, 1);
2474 EXEC SQL INSERT INTO imembers
2475 (list_id, member_id, member_type, ref_count)
2476 VALUES (:lid, :mid, :mtype, 1);
2478 iargv[0] = (char *)lid;
2480 iargv[2] = (char *)mid;
2481 incremental_after("members", 0, iargv);
2485 lid = *(int *)argv[0];
2486 entity = cl->entity;
2487 who = cl->client_id;
2488 EXEC SQL REPEATED UPDATE list
2489 SET modtime='now', modby = :who, modwith = :entity
2490 WHERE list_id = :lid;
2491 if (ingres_errno) return(mr_errcode);
2496 /* Delete_member_from_list: do list flattening as we go!
2499 int delete_member_from_list(q, argv, cl)
2504 EXEC SQL BEGIN DECLARE SECTION;
2505 int id, lid, mid, cnt, error, who, ref;
2506 char *mtype, dtype[9], *entity;
2507 EXEC SQL END DECLARE SECTION;
2508 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2509 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2510 char *dtypes[MAXLISTDEPTH];
2513 lid = *(int *)argv[0];
2515 mid = *(int *)argv[2];
2516 /* if the member is not a direct member of the list, punt */
2517 EXEC SQL REPEATED SELECT COUNT(list_id) INTO :cnt FROM imembers
2518 WHERE list_id = :lid AND member_id = :mid
2519 AND member_type = :mtype AND direct = 1;
2520 if (ingres_errno) return(mr_errcode);
2522 return(MR_NO_MATCH);
2526 EXEC SQL DECLARE csr105 CURSOR FOR
2527 SELECT list_id, ref_count FROM imembers
2528 WHERE member_id = :lid AND member_type = 'LIST';
2529 EXEC SQL OPEN csr105;
2531 EXEC SQL FETCH csr105 INTO :id, :ref;
2532 if(sqlca.sqlcode!=0) break;
2534 ancestors[acount++] = id;
2535 if (acount >= MAXLISTDEPTH) break;
2537 EXEC SQL CLOSE csr105;
2540 if (acount >= MAXLISTDEPTH)
2541 return(MR_INTERNAL);
2542 descendants[0] = mid;
2547 if (!strcmp(mtype, "LIST")) {
2548 EXEC SQL DECLARE csr106 CURSOR FOR
2549 SELECT member_id, member_type, ref_count FROM imembers
2550 WHERE list_id = :mid;
2551 EXEC SQL OPEN csr106;
2553 EXEC SQL FETCH csr106 INTO :id, :dtype, :ref;
2554 if(sqlca.sqlcode!=0) break;
2557 dtypes[dcount] = "LIST";
2560 dtypes[dcount] = "USER";
2563 dtypes[dcount] = "STRING";
2566 dtypes[dcount] = "KERBEROS";
2573 descendants[dcount++] = id;
2574 if (dcount >= MAXLISTDEPTH) break;
2576 EXEC SQL CLOSE csr106;
2580 return(MR_INTERNAL);
2582 for (a = 0; a < acount; a++) {
2584 for (d = 0; d < dcount; d++) {
2585 mid = descendants[d];
2587 if (mid == lid && !strcmp(mtype, "LIST")) {
2588 return(MR_LISTLOOP);
2590 EXEC SQL REPEATED SELECT ref_count INTO :cnt FROM imembers
2591 WHERE list_id = :lid AND member_id = :mid AND member_type = :mtype;
2592 ref = aref[a] * dref[d];
2594 iargv[0] = (char *)lid;
2596 iargv[2] = (char *)mid;
2597 incremental_before("members", 0, iargv);
2598 EXEC SQL DELETE FROM imembers
2599 WHERE list_id = :lid AND member_id = :mid
2600 AND member_type= :mtype;
2601 incremental_clear_after();
2602 } else if (a == 0 && d == 0) {
2603 EXEC SQL UPDATE imembers
2604 SET ref_count = ref_count - :ref, direct = 0
2605 WHERE list_id = :lid AND member_id = :mid
2606 AND member_type = :mtype;
2608 EXEC SQL UPDATE imembers
2609 SET ref_count = ref_count - :ref
2610 WHERE list_id = :lid AND member_id = :mid
2611 AND member_type = :mtype;
2615 lid = *(int *)argv[0];
2616 entity = cl->entity;
2617 who = cl->client_id;
2618 EXEC SQL UPDATE list SET modtime = 'now', modby = :who, modwith = :entity
2619 WHERE list_id = :lid;
2620 if (ingres_errno) return(mr_errcode);
2625 /* get_ace_use - given a type and a name, return a type and a name.
2626 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2627 * and argv[1] will contain the ID of the entity in question. The R*
2628 * types mean to recursively look at every containing list, not just
2629 * when the object in question is a direct member. On return, the
2630 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2633 int get_ace_use(q, argv, cl, action, actarg)
2641 EXEC SQL BEGIN DECLARE SECTION;
2643 int aid, listid, id;
2644 EXEC SQL END DECLARE SECTION;
2645 struct save_queue *sq, *sq_create();
2648 aid = *(int *)argv[1];
2649 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2650 !strcmp(atype, "KERBEROS")) {
2651 return(get_ace_internal(atype, aid, action, actarg));
2655 if (!strcmp(atype, "RLIST")) {
2656 sq_save_data(sq, aid);
2657 /* get all the list_id's of containing lists */
2658 EXEC SQL DECLARE csr107 CURSOR FOR
2659 SELECT list_id FROM imembers
2660 WHERE member_type='LIST' AND member_id = :aid;
2661 EXEC SQL OPEN csr107;
2663 EXEC SQL FETCH csr107 INTO :listid;
2664 if(sqlca.sqlcode != 0) break;
2665 sq_save_unique_data(sq, listid);
2667 EXEC SQL CLOSE csr107;
2668 /* now process each one */
2669 while (sq_get_data(sq, &id)) {
2670 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2675 if (!strcmp(atype, "RUSER")) {
2676 EXEC SQL DECLARE csr108 CURSOR FOR
2677 SELECT list_id FROM imembers
2678 WHERE member_type='USER' AND member_id = :aid;
2679 EXEC SQL OPEN csr108;
2681 EXEC SQL FETCH csr108 INTO :listid;
2682 if(sqlca.sqlcode != 0) break;
2683 sq_save_data(sq, listid);
2685 EXEC SQL CLOSE csr108;
2686 /* now process each one */
2687 while (sq_get_data(sq, &id)) {
2688 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2691 if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2695 if (!strcmp(atype, "RKERBERO")) {
2696 EXEC SQL DECLARE csr109 CURSOR FOR
2697 SELECT list_id FROM imembers
2698 WHERE member_type='KERBEROS' AND member_id = :aid;
2699 EXEC SQL OPEN csr109;
2701 EXEC SQL FETCH csr109 INTO :listid;
2702 if(sqlca.sqlcode != 0) break;
2703 sq_save_data(sq, listid);
2705 EXEC SQL CLOSE csr109;
2706 /* now process each one */
2707 while (sq_get_data(sq, &id)) {
2708 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2711 if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2716 if (ingres_errno) return(mr_errcode);
2717 if (!found) return(MR_NO_MATCH);
2722 /* This looks up a single list or user for ace use. atype must be "USER"
2723 * or "LIST", and aid is the ID of the corresponding object. This is used
2724 * by get_ace_use above.
2727 get_ace_internal(atype, aid, action, actarg)
2728 EXEC SQL BEGIN DECLARE SECTION;
2731 EXEC SQL END DECLARE SECTION;
2737 EXEC SQL BEGIN DECLARE SECTION;
2739 EXEC SQL END DECLARE SECTION;
2742 if (!strcmp(atype, "LIST")) {
2743 rargv[0] = "FILESYS";
2744 EXEC SQL DECLARE csr110 CURSOR FOR
2745 SELECT label FROM filesys
2746 WHERE owners = :aid;
2747 EXEC SQL OPEN csr110;
2749 EXEC SQL FETCH csr110 INTO :name;
2750 if(sqlca.sqlcode != 0) break;
2751 (*action)(2, rargv, actarg);
2754 EXEC SQL CLOSE csr110;
2757 EXEC SQL DECLARE csr111 CURSOR FOR
2758 SELECT capability FROM capacls
2759 WHERE list_id = :aid ;
2760 EXEC SQL OPEN csr111;
2762 EXEC SQL FETCH csr111 INTO :name ;
2763 if(sqlca.sqlcode != 0) break;
2764 (*action)(2, rargv, actarg);
2767 EXEC SQL CLOSE csr111;
2768 } else if (!strcmp(atype, "USER")) {
2769 rargv[0] = "FILESYS";
2770 EXEC SQL DECLARE csr112 CURSOR FOR
2771 SELECT label FROM filesys
2773 EXEC SQL OPEN csr112;
2775 EXEC SQL FETCH csr112 INTO :name ;
2776 if(sqlca.sqlcode != 0) break;
2777 (*action)(2, rargv, actarg);
2780 EXEC SQL CLOSE csr112;
2784 EXEC SQL DECLARE csr113 CURSOR FOR
2785 SELECT name FROM list
2786 WHERE acl_type = :atype AND acl_id = :aid;
2787 EXEC SQL OPEN csr113;
2789 EXEC SQL FETCH csr113 INTO :name;
2790 if(sqlca.sqlcode != 0) break;
2791 (*action)(2, rargv, actarg);
2794 EXEC SQL CLOSE csr113;
2796 rargv[0] = "SERVICE";
2797 EXEC SQL DECLARE csr114 CURSOR FOR
2798 SELECT name FROM servers
2799 WHERE acl_type = :atype AND acl_id = :aid;
2800 EXEC SQL OPEN csr114;
2802 EXEC SQL FETCH csr114 INTO :name;
2803 if(sqlca.sqlcode != 0) break;
2804 (*action)(2, rargv, actarg);
2807 EXEC SQL CLOSE csr114;
2809 rargv[0] = "HOSTACCESS";
2810 EXEC SQL DECLARE csr115 CURSOR FOR
2811 SELECT name FROM machine m, hostaccess ha
2812 WHERE m.mach_id = ha.mach_id AND ha.acl_type = :atype
2813 AND ha.acl_id = :aid;
2814 EXEC SQL OPEN csr115;
2816 EXEC SQL FETCH csr115 INTO :name;
2817 if(sqlca.sqlcode != 0) break;
2818 (*action)(2, rargv, actarg);
2821 EXEC SQL CLOSE csr115;
2823 rargv[0] = "ZEPHYR";
2824 EXEC SQL DECLARE csr116 CURSOR FOR
2825 SELECT class FROM zephyr z
2826 WHERE z.xmt_type = :atype AND z.xmt_id = :aid
2827 OR z.sub_type = :atype AND z.sub_id = :aid
2828 OR z.iws_type = :atype AND z.iws_id = :aid
2829 OR z.iui_type = :atype AND z.iui_id = :aid;
2830 EXEC SQL OPEN csr116;
2832 EXEC SQL FETCH csr116 INTO :name;
2833 if(sqlca.sqlcode != 0) break;
2834 (*action)(2, rargv, actarg);
2837 EXEC SQL CLOSE csr116;
2839 if (!found) return(MR_NO_MATCH);
2844 /* get_lists_of_member - given a type and a name, return the name and flags
2845 * of all of the lists of the given member. The member_type is one of
2846 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2847 * and argv[1] will contain the ID of the entity in question. The R*
2848 * types mean to recursively look at every containing list, not just
2849 * when the object in question is a direct member.
2852 int get_lists_of_member(q, argv, cl, action, actarg)
2859 int found = 0, direct = 1;
2861 EXEC SQL BEGIN DECLARE SECTION;
2863 int aid, listid, id;
2864 char name[33], active[5], public[5], hidden[5], maillist[5], grouplist[5];
2865 EXEC SQL END DECLARE SECTION;
2868 aid = *(int *)argv[1];
2869 if (!strcmp(atype, "RLIST")) {
2873 if (!strcmp(atype, "RUSER")) {
2877 if (!strcmp(atype, "RSTRING")) {
2881 if (!strcmp(atype, "RKERBEROS")) {
2890 rargv[4] = maillist;
2891 rargv[5] = grouplist;
2893 EXEC SQL DECLARE csr117a CURSOR FOR
2894 SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2895 CHAR(l.maillist), CHAR(l.grouplist)
2896 FROM list l, imembers im
2897 WHERE l.list_id = im.list_id AND im.direct = 1
2898 AND im.member_type = :atype AND im.member_id = :aid;
2899 EXEC SQL OPEN csr117a;
2901 EXEC SQL FETCH csr117a
2902 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2903 if(sqlca.sqlcode != 0) break;
2904 (*action)(6, rargv, actarg);
2907 EXEC SQL CLOSE csr117a;
2909 EXEC SQL DECLARE csr117b CURSOR FOR
2910 SELECT l.name, CHAR(l.active), CHAR(l.publicflg), CHAR(l.hidden),
2911 CHAR(l.maillist), CHAR(l.grouplist)
2912 FROM list l, imembers im
2913 WHERE l.list_id = im.list_id
2914 AND im.member_type = :atype AND im.member_id = :aid;
2915 EXEC SQL OPEN csr117b;
2917 EXEC SQL FETCH csr117b
2918 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2919 if(sqlca.sqlcode != 0) break;
2920 (*action)(6, rargv, actarg);
2923 EXEC SQL CLOSE csr117b;
2926 if (ingres_errno) return(mr_errcode);
2927 if (!found) return(MR_NO_MATCH);
2932 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2933 * the five flags associated with each list. It will return the name of
2934 * each list that meets the quailifications. It does this by building a
2935 * where clause based on the arguments, then doing a retrieve.
2938 static char *lflags[5] = { "active", "publicflg", "hidden", "maillist", "grouplist" };
2940 int qualified_get_lists(q, argv, cl, action, actarg)
2947 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2948 "l", "name", lflags));
2952 /* get_members_of_list - this gets only direct members */
2954 get_members_of_list(q, argv, cl, action, actarg)
2961 return(gmol_internal(q, argv, cl, action, actarg, 1));
2964 /* get_end_members_of_list - this gets direct or indirect members */
2966 get_end_members_of_list(q, argv, cl, action, actarg)
2973 return(gmol_internal(q, argv, cl, action, actarg, 0));
2976 /** gmol_internal - optimized query for retrieval of list members
2977 ** used by both get_members_of_list and get_end_members_of_list
2980 ** argv[0] - list_id
2983 ** - retrieve USER members, then LIST members, then STRING members
2986 gmol_internal(q, argv, cl, action, actarg, flag)
2994 EXEC SQL BEGIN DECLARE SECTION;
2995 int list_id, member_id, direct;
2996 char member_name[129], member_type[9];
2997 EXEC SQL END DECLARE SECTION;
3000 struct save_queue *sq;
3002 /* true/false flag indicates whether to display only direct members. */
3008 list_id = *(int *)argv[0];
3012 EXEC SQL DECLARE csr118 CURSOR FOR
3013 SELECT member_type, member_id FROM imembers
3014 WHERE list_id = :list_id AND direct > :direct;
3015 EXEC SQL OPEN csr118;
3017 EXEC SQL FETCH csr118 INTO :member_type, :member_id;
3018 if (sqlca.sqlcode != 0) break;
3021 sq_save_data(sq, ((int)member_type[0] << 24) | (member_id & 0xffffff));
3023 EXEC SQL CLOSE csr118;
3025 if (members <= 49) {
3026 targv[1] = malloc(0);
3027 while (sq_remove_data(sq, &member_id)) {
3028 switch (member_id >> 24) {
3031 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
3032 (*action)(2, targv, actarg);
3036 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
3037 (*action)(2, targv, actarg);
3040 targv[0] = "STRING";
3041 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
3042 (*action)(2, targv, actarg);
3045 targv[0] = "KERBEROS";
3046 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
3047 (*action)(2, targv, actarg);
3051 return(MR_INTERNAL);
3060 targv[1] = member_name;
3062 EXEC SQL DECLARE csr119 CURSOR FOR
3063 SELECT u.login FROM users u, imembers im
3064 WHERE im.list_id = :list_id AND im.member_type = 'USER'
3065 AND im.member_id = u.users_id AND im.direct > :direct
3067 EXEC SQL OPEN csr119;
3069 EXEC SQL FETCH csr119 INTO :member_name;
3070 if(sqlca.sqlcode != 0) break;
3071 (*action)(2, targv, actarg);
3073 EXEC SQL CLOSE csr119;
3074 if (ingres_errno) return(mr_errcode);
3077 EXEC SQL DECLARE csr120 CURSOR FOR
3078 SELECT l.name FROM list l, imembers im
3079 WHERE im.list_id = :list_id AND im.member_type='LIST'
3080 AND im.member_id = l.list_id AND im.direct > :direct
3082 EXEC SQL OPEN csr120;
3084 EXEC SQL FETCH csr120 INTO :member_name;
3085 if(sqlca.sqlcode != 0) break;
3086 (*action)(2, targv, actarg);
3088 EXEC SQL CLOSE csr120;
3089 if (ingres_errno) return(mr_errcode);
3091 targv[0] = "STRING";
3092 EXEC SQL DECLARE csr121 CURSOR FOR
3093 SELECT CHAR(str.string) FROM strings str, imembers im
3094 WHERE im.list_id = :list_id AND im.member_type='STRING'
3095 AND im.member_id = str.string_id AND im.direct > :direct
3097 EXEC SQL OPEN csr121;
3099 EXEC SQL FETCH csr121 INTO :member_name;
3100 if(sqlca.sqlcode != 0) break;
3101 (*action)(2, targv, actarg);
3103 EXEC SQL CLOSE csr121;
3104 if (ingres_errno) return(mr_errcode);
3106 targv[0] = "KERBEROS";
3107 EXEC SQL DECLARE csr122 CURSOR FOR
3108 SELECT CHAR(str.string) FROM strings str, imembers im
3109 WHERE im.list_id = :list_id AND im.member_type='KERBEROS'
3110 AND im.member_id = str.string_id
3111 AND im.direct > :direct
3113 EXEC SQL OPEN csr122;
3115 EXEC SQL FETCH csr122 INTO :member_name;
3116 if(sqlca.sqlcode != 0) break;
3117 (*action)(2, targv, actarg);
3119 EXEC SQL CLOSE csr122;
3120 if (ingres_errno) return(mr_errcode);
3126 /* count_members_of_list: this is a simple query, but it cannot be done
3127 * through the dispatch table.
3130 int count_members_of_list(q, argv, cl, action, actarg)
3137 EXEC SQL BEGIN DECLARE SECTION;
3139 EXEC SQL END DECLARE SECTION;
3140 char *rargv[1], countbuf[5];
3142 list = *(int *)argv[0];
3143 rargv[0] = countbuf;
3144 EXEC SQL REPEATED SELECT count (*) INTO :ct FROM imembers
3145 WHERE list_id = :list AND direct=1;
3146 if (ingres_errno) return(mr_errcode);
3147 sprintf(countbuf, "%d", ct);
3148 (*action)(1, rargv, actarg);
3153 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
3154 * the three flags associated with each service. It will return the name of
3155 * each service that meets the quailifications. It does this by building a
3156 * where clause based on the arguments, then doing a retrieve.
3159 static char *sflags[3] = { "enable", "inprogress", "harderror" };
3161 int qualified_get_server(q, argv, cl, action, actarg)
3168 return(qualified_get(q, argv, action, actarg, "s.name != ''",
3169 "s", "name", sflags));
3173 /* generic qualified get routine, used by qualified_get_lists,
3174 * qualified_get_server, and qualified_get_serverhost.
3176 * start - a simple where clause, must not be empty
3177 * range - the name of the range variable
3178 * field - the field to return
3179 * flags - an array of strings, names of the flag variables
3182 int qualified_get(q, argv, action, actarg, start, range, field, flags)
3192 char name[33], qual[256];
3194 char *rargv[1], buf[32];
3196 strcpy(qual, start);
3197 for (i = 0; i < q->argc; i++) {
3198 if (!strcmp(argv[i], "TRUE")) {
3199 sprintf(buf, " AND %s.%s != 0", range, flags[i]);
3200 (void) strcat(qual, buf);
3201 } else if (!strcmp(argv[i], "FALSE")) {
3202 sprintf(buf, " AND %s.%s = 0", range, flags[i]);
3203 (void) strcat(qual, buf);
3207 rargv[0] = SQLDA->sqlvar[0].sqldata;
3208 sprintf(stmt_buf,"SELECT CHAR(%s.%s) FROM %s %s WHERE %s",range,field,q->rtable,range,qual);
3209 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3211 return(MR_INTERNAL);
3212 EXEC SQL DECLARE csr123 CURSOR FOR stmt;
3213 EXEC SQL OPEN csr123;
3215 EXEC SQL FETCH csr123 USING DESCRIPTOR :SQLDA;
3216 if(sqlca.sqlcode != 0) break;
3218 (*action)(1, rargv, actarg);
3220 EXEC SQL CLOSE csr123;
3221 if (ingres_errno) return(mr_errcode);
3223 return(MR_NO_MATCH);
3228 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
3229 * the five flags associated with each serverhost. It will return the name of
3230 * each service and host that meets the quailifications. It does this by
3231 * building a where clause based on the arguments, then doing a retrieve.
3234 static char *shflags[6] = { "service", "enable", "override", "success",
3235 "inprogress", "hosterror" };
3237 int qualified_get_serverhost(q, argv, cl, action, actarg)
3244 EXEC SQL BEGIN DECLARE SECTION;
3245 char sname[33], mname[33], qual[256];
3246 EXEC SQL END DECLARE SECTION;
3247 char *rargv[2], buf[32];
3250 sprintf(qual, "m.mach_id = sh.mach_id AND sh.service = uppercase('%s')",
3252 for (i = 1; i < q->argc; i++) {
3253 if (!strcmp(argv[i], "TRUE")) {
3254 sprintf(buf, " AND sh.%s != 0", shflags[i]);
3256 } else if (!strcmp(argv[i], "FALSE")) {
3257 sprintf(buf, " AND sh.%s = 0", shflags[i]);
3264 EXEC SQL DECLARE csr124 CURSOR FOR
3265 SELECT sh.service, m.name FROM serverhosts sh, machine m
3267 EXEC SQL OPEN csr124;
3269 EXEC SQL FETCH csr124 INTO :sname, :mname;
3270 if(sqlca.sqlcode != 0) break;
3272 (*action)(2, rargv, actarg);
3274 EXEC SQL CLOSE csr124;
3276 if (ingres_errno) return(mr_errcode);
3278 return(MR_NO_MATCH);
3283 /* register_user - change user's login name and allocate a pobox, group,
3284 * filesystem, and quota for them. The user's status must start out as 0,
3285 * and is left as 2. Arguments are: user's UID, new login name, and user's
3286 * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY,
3287 * MR_FS_STAFF, MR_FS_MISC).
3290 register_user(q, argv, cl)
3295 EXEC SQL BEGIN DECLARE SECTION;
3296 char *login, dir[65], *entity, directory[129], machname[33];
3297 int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
3298 int size, alloc, pid, ostatus, nstatus, gidval, fsidval, npidval;
3299 static int m_id = 0, def_quota = 0;
3300 EXEC SQL END DECLARE SECTION;
3301 char buffer[256], *aargv[3];
3303 entity = cl->entity;
3304 who = cl->client_id;
3306 uid = atoi(argv[0]);
3308 utype = atoi(argv[2]);
3311 EXEC SQL REPEATED SELECT users_id, status INTO :users_id, :ostatus
3313 WHERE uid = :uid AND (status=0 OR status=5 OR status=6);
3315 if (sqlca.sqlerrd[2] == 0)
3316 return(MR_NO_MATCH);
3317 if (sqlca.sqlerrd[2] > 1)
3318 return(MR_NOT_UNIQUE);
3320 /* check new login name */
3321 EXEC SQL REPEATED SELECT COUNT(login) INTO :rowcount FROM users
3322 WHERE login = LEFT(:login,SIZE(login)) AND users_id != :users_id;
3323 if (ingres_errno) return(mr_errcode);
3324 if (rowcount > 0) return(MR_IN_USE);
3325 EXEC SQL REPEATED SELECT COUNT(name) INTO :rowcount FROM list
3326 WHERE name = LEFT(:login,SIZE(name));
3327 if (ingres_errno) return(mr_errcode);
3328 if (rowcount > 0) return(MR_IN_USE);
3329 EXEC SQL REPEATED SELECT COUNT(label) INTO :rowcount FROM filesys
3330 WHERE label = LEFT(:login,SIZE(label));
3331 if (ingres_errno) return(mr_errcode);
3332 if (rowcount > 0) return(MR_IN_USE);
3333 com_err(whoami, 0, "login name OK");
3335 /* choose place for pobox, put in mid */
3336 EXEC SQL DECLARE csr130 CURSOR FOR
3337 SELECT sh.mach_id, m.name FROM serverhosts sh, machine m
3338 WHERE sh.service='POP' AND sh.mach_id=m.mach_id
3339 AND sh.value2 - sh.value1 =
3340 (SELECT MAX(value2 - value1) FROM serverhosts
3341 WHERE service = 'POP');
3342 EXEC SQL OPEN csr130;
3343 EXEC SQL FETCH csr130 INTO :mid, :machname;
3344 if (sqlca.sqlerrd[2] == 0) {
3345 EXEC SQL CLOSE csr130;
3346 if (ingres_errno) return(mr_errcode);
3347 return(MR_NO_POBOX);
3349 EXEC SQL CLOSE csr130;
3350 if (ingres_errno) return(mr_errcode);
3353 /* change login name, set pobox */
3354 sprintf(buffer, "u.users_id = %d", users_id);
3355 incremental_before("users", buffer, 0);
3357 if (ostatus == 5 || ostatus == 6)
3359 EXEC SQL REPEATED UPDATE users SET login = :login, status = :nstatus,
3360 modtime='now', modby = :who, modwith = :entity, potype='POP',
3361 pop_id = :mid, pmodtime='now', pmodby = :who, pmodwith = :entity
3362 WHERE users_id = :users_id;
3364 if (ingres_errno) return(mr_errcode);
3365 if (sqlca.sqlerrd[2] != 1)
3366 return(MR_INTERNAL);
3367 set_pop_usage(mid, 1);
3368 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
3370 incremental_after("users", buffer, 0);
3372 /* create group list */
3373 if (set_next_object_id("gid", "list", 1))
3375 if (set_next_object_id("list_id", "list", 0))
3377 EXEC SQL REPEATED SELECT value INTO :list_id FROM numvalues
3378 WHERE name='list_id';
3379 if (ingres_errno) return(mr_errcode);
3380 if (sqlca.sqlerrd[2] != 1)
3381 return(MR_INTERNAL);
3382 incremental_clear_before();
3383 EXEC SQL SELECT value INTO :gidval FROM numvalues WHERE name = 'gid';
3384 EXEC SQL REPEATED INSERT INTO list
3385 (name, list_id, active, publicflg, hidden, maillist, grouplist,
3386 gid, description, acl_type, acl_id,
3387 modtime, modby, modwith)
3388 VALUES (:login, :list_id, 1, 0, 0, 0, 1,
3389 :gidval, 'User Group', 'USER', :users_id,
3390 'now', :who, :entity);
3391 if (ingres_errno) return(mr_errcode);
3392 if (sqlca.sqlerrd[2] != 1)
3393 return(MR_INTERNAL);
3394 sprintf(buffer, "l.list_id = %d", list_id);
3395 incremental_after("list", buffer, 0);
3396 aargv[0] = (char *) list_id;
3398 aargv[2] = (char *) users_id;
3399 incremental_clear_before();
3400 EXEC SQL REPEATED INSERT INTO imembers
3401 (list_id, member_type, member_id, ref_count, direct)
3402 VALUES (:list_id, 'USER', :users_id, 1, 1);
3403 if (ingres_errno) return(mr_errcode);
3404 if (sqlca.sqlerrd[2] != 1)
3405 return(MR_INTERNAL);
3406 incremental_after("members", 0, aargv);
3409 /* Cell Name (I know, it shouldn't be hard coded...) */
3410 strcpy(machname, "ATHENA.MIT.EDU");
3411 EXEC SQL SELECT mach_id INTO :m_id FROM machine
3412 WHERE name = :machname;
3415 /* create filesystem */
3416 if (set_next_object_id("filsys_id", "filesys", 0))
3418 incremental_clear_before();
3419 if (islower(login[0]) && islower(login[1])) {
3420 sprintf(directory, "/afs/athena.mit.edu/user/%c/%c/%s",
3421 login[0], login[1], login);
3423 sprintf(directory, "/afs/athena.mit.edu/user/other/%s", login);
3426 EXEC SQL SELECT value INTO :fsidval FROM numvalues
3427 WHERE numvalues.name='filsys_id';
3428 EXEC SQL REPEATED INSERT INTO filesys
3429 (filsys_id, phys_id, label, type, mach_id, name,
3430 mount, access, comments, owner, owners, createflg,
3431 lockertype, modtime, modby, modwith)
3433 (:fsidval, 0, :login, 'AFS', :m_id, :directory,
3434 '/mit/'+:login, 'w', 'User Locker', :users_id, :list_id, 1,
3435 'HOMEDIR', 'now', :who, :entity);
3437 if (ingres_errno) return(mr_errcode);
3438 if (sqlca.sqlerrd[2] != 1)
3439 return(MR_INTERNAL);
3440 sprintf(buffer,"fs.filsys_id = %d",fsidval);
3441 incremental_after("filesys", buffer, 0);
3444 if (def_quota == 0) {
3445 EXEC SQL REPEATED SELECT value INTO :def_quota FROM numvalues
3446 WHERE name='def_quota';
3447 if (ingres_errno) return(mr_errcode);
3448 if (sqlca.sqlerrd[2] != 1)
3449 return(MR_NO_QUOTA);
3452 incremental_clear_before();
3453 EXEC SQL REPEATED INSERT INTO quota
3454 (entity_id, filsys_id, type, quota, phys_id, modtime, modby, modwith)
3456 (0, :fsidval, 'ANY', :def_quota, 0, 'now', :who, :entity);
3457 if (ingres_errno) return(mr_errcode);
3458 if (sqlca.sqlerrd[2] != 1)
3459 return(MR_INTERNAL);
3463 sprintf(buffer, "q.entity_id = 0 and q.filsys_id = %d and q.type = 'ANY'", fsidval);
3464 incremental_after("quota", buffer, aargv);
3465 com_err(whoami, 0, "quota of %d assigned", def_quota);
3466 if (ingres_errno) return(mr_errcode);
3468 cache_entry(login, "USER", users_id);
3470 EXEC SQL REPEATED UPDATE tblstats SET updates=updates+1, modtime='now'
3471 WHERE table_name='users';
3472 EXEC SQL REPEATED UPDATE tblstats SET appends=appends+1, modtime='now'
3473 WHERE table_name='list' OR table_name='filesys' OR table_name='quota';
3474 if (ingres_errno) return(mr_errcode);
3480 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
3484 ** delta (will be +/- 1)
3487 ** - incr/decr value field in serverhosts table for pop/mach_id
3491 static int set_pop_usage(id, cnt)
3492 EXEC SQL BEGIN DECLARE SECTION;
3495 EXEC SQL END DECLARE SECTION;
3497 EXEC SQL REPEATED UPDATE serverhosts SET value1 = value1 + :cnt
3498 WHERE serverhosts.service = 'POP' AND serverhosts.mach_id = :id;
3500 if (ingres_errno) return(mr_errcode);
3506 /* Validation Routines */
3508 validate_row(q, argv, v)
3509 register struct query *q;
3511 register struct validate *v;
3513 EXEC SQL BEGIN DECLARE SECTION;
3517 EXEC SQL END DECLARE SECTION;
3519 /* build where clause */
3520 build_qual(v->qual, v->argc, argv, qual);
3522 if (log_flags & LOG_VALID)
3523 /* tell the logfile what we're doing */
3524 com_err(whoami, 0, "validating row: %s", qual);
3526 /* look for the record */
3527 sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",q->rtable,qual);
3528 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3530 return(MR_INTERNAL);
3531 EXEC SQL DECLARE csr126 CURSOR FOR stmt;
3532 EXEC SQL OPEN csr126;
3533 EXEC SQL FETCH csr126 USING DESCRIPTOR :SQLDA;
3534 EXEC SQL CLOSE csr126;
3535 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3537 if (ingres_errno) return(mr_errcode);
3538 if (rowcount == 0) return(MR_NO_MATCH);
3539 if (rowcount > 1) return(MR_NOT_UNIQUE);
3543 validate_fields(q, argv, vo, n)
3545 register char *argv[];
3546 register struct valobj *vo;
3549 register int status;
3554 if (log_flags & LOG_VALID)
3555 com_err(whoami, 0, "validating %s in %s: %s",
3556 vo->namefield, vo->table, argv[vo->index]);
3557 status = validate_name(argv, vo);
3561 if (log_flags & LOG_VALID)
3562 com_err(whoami, 0, "validating %s in %s: %s",
3563 vo->idfield, vo->table, argv[vo->index]);
3564 status = validate_id(q, argv, vo);
3568 if (log_flags & LOG_VALID)
3569 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
3570 status = validate_date(argv, vo);
3574 if (log_flags & LOG_VALID)
3575 com_err(whoami, 0, "validating %s type: %s",
3576 vo->table, argv[vo->index]);
3577 status = validate_type(argv, vo);
3581 if (log_flags & LOG_VALID)
3582 com_err(whoami, 0, "validating typed data (%s): %s",
3583 argv[vo->index - 1], argv[vo->index]);
3584 status = validate_typedata(q, argv, vo);
3588 if (log_flags & LOG_VALID)
3589 com_err(whoami, 0, "validating rename %s in %s",
3590 argv[vo->index], vo->table);
3591 status = validate_rename(argv, vo);
3595 if (log_flags & LOG_VALID)
3596 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
3597 status = validate_chars(argv[vo->index]);
3605 status = lock_table(vo);
3609 status = convert_wildcards(argv[vo->index]);
3613 status = convert_wildcards_uppercase(argv[vo->index]);
3618 if (status != MR_EXISTS) return(status);
3622 if (ingres_errno) return(mr_errcode);
3627 /* validate_chars: verify that there are no illegal characters in
3628 * the string. Legal characters are printing chars other than
3629 * ", *, ?, \, [ and ].
3631 static int illegalchars[] = {
3632 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
3633 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
3634 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
3635 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
3636 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
3637 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
3638 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
3639 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
3640 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3641 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3642 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3643 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3644 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3645 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3646 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3647 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3654 if (illegalchars[*s++])
3655 return(MR_BAD_CHAR);
3660 validate_id(q, argv, vo)
3663 register struct valobj *vo;
3665 EXEC SQL BEGIN DECLARE SECTION;
3666 char *name, *tbl, *namefield, *idfield;
3668 EXEC SQL END DECLARE SECTION;
3672 name = argv[vo->index];
3674 namefield = vo->namefield;
3675 idfield = vo->idfield;
3677 if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
3678 !strcmp(tbl, "machine") ||
3679 !strcmp(tbl, "filesys") ||
3680 !strcmp(tbl, "list") ||
3681 !strcmp(tbl, "cluster") ||
3682 !strcmp(tbl, "strings")) {
3683 if (!strcmp(tbl, "machine"))
3684 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3685 status = name_to_id(name, tbl, &id);
3687 *(int *)argv[vo->index] = id;
3689 } else if (status == MR_NO_MATCH && !strcmp(tbl, "strings") &&
3690 (q->type == APPEND || q->type == UPDATE)) {
3691 EXEC SQL SELECT value INTO :id FROM numvalues
3692 WHERE name = 'strings_id';
3694 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3695 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3696 cache_entry(name, "STRING", id);
3697 *(int *)argv[vo->index] = id;
3699 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
3705 if (!strcmp(namefield, "uid")) {
3706 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = %s",idfield,tbl,namefield,name);
3708 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",idfield,tbl,namefield,name);
3710 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3712 return(MR_INTERNAL);
3713 EXEC SQL DECLARE csr127 CURSOR FOR stmt;
3714 EXEC SQL OPEN csr127;
3716 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3717 if(sqlca.sqlcode == 0) {
3719 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3720 if(sqlca.sqlcode == 0) rowcount++;
3722 EXEC SQL CLOSE csr127;
3726 if (rowcount != 1) return(vo->error);
3727 bcopy(SQLDA->sqlvar[0].sqldata,argv[vo->index],sizeof(int));
3731 validate_name(argv, vo)
3733 register struct valobj *vo;
3735 EXEC SQL BEGIN DECLARE SECTION;
3736 char *name, *tbl, *namefield;
3738 EXEC SQL END DECLARE SECTION;
3741 name = argv[vo->index];
3743 namefield = vo->namefield;
3744 if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
3745 for (c = name; *c; c++)
3749 sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
3750 tbl,tbl,namefield,name);
3751 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3753 return(MR_INTERNAL);
3754 EXEC SQL DECLARE csr128 CURSOR FOR stmt;
3755 EXEC SQL OPEN csr128;
3756 EXEC SQL FETCH csr128 USING DESCRIPTOR :SQLDA;
3757 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3758 EXEC SQL CLOSE csr128;
3760 if (ingres_errno) return(mr_errcode);
3761 return ((rowcount == 1) ? MR_EXISTS : vo->error);
3764 validate_date(argv, vo)
3768 EXEC SQL BEGIN DECLARE SECTION;
3772 EXEC SQL END DECLARE SECTION;
3774 idate = argv[vo->index];
3775 EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
3777 if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
3782 validate_rename(argv, vo)
3786 EXEC SQL BEGIN DECLARE SECTION;
3787 char *name, *tbl, *namefield, *idfield;
3789 EXEC SQL END DECLARE SECTION;
3793 c = name = argv[vo->index];
3795 if (illegalchars[*c++])
3796 return(MR_BAD_CHAR);
3798 /* minor kludge to upcasify machine names */
3799 if (!strcmp(tbl, "machine"))
3800 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3801 namefield = vo->namefield;
3802 idfield = vo->idfield;
3805 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3807 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = LEFT('%s',SIZE(%s))",
3808 namefield,tbl,namefield,name,namefield);
3809 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3811 return(MR_INTERNAL);
3812 EXEC SQL DECLARE csr129 CURSOR FOR stmt;
3813 EXEC SQL OPEN csr129;
3814 EXEC SQL FETCH csr129 USING DESCRIPTOR :SQLDA;
3815 if(sqlca.sqlcode == 0) id=1; else id=0;
3816 EXEC SQL CLOSE csr129;
3818 if (ingres_errno) return(mr_errcode);
3824 status = name_to_id(name, tbl, &id);
3825 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3832 validate_type(argv, vo)
3834 register struct valobj *vo;
3836 EXEC SQL BEGIN DECLARE SECTION;
3840 EXEC SQL END DECLARE SECTION;
3843 typename = vo->table;
3844 c = val = argv[vo->index];
3846 if (illegalchars[*c++])
3847 return(MR_BAD_CHAR);
3850 /* uppercase type fields */
3851 for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
3853 EXEC SQL SELECT COUNT(trans) INTO :cnt FROM alias
3854 WHERE name = :typename AND type='TYPE' AND trans = :val;
3855 if (ingres_errno) return(mr_errcode);
3856 return (cnt ? MR_EXISTS : vo->error);
3859 /* validate member or type-specific data field */
3861 validate_typedata(q, argv, vo)
3862 register struct query *q;
3863 register char *argv[];
3864 register struct valobj *vo;
3866 EXEC SQL BEGIN DECLARE SECTION;
3869 char data_type[129];
3871 EXEC SQL END DECLARE SECTION;
3876 /* get named object */
3877 name = argv[vo->index];
3879 /* get field type string (known to be at index-1) */
3880 field_type = argv[vo->index-1];
3882 /* get corresponding data type associated with field type name */
3883 EXEC SQL SELECT trans INTO :data_type FROM alias
3884 WHERE name = :field_type AND type='TYPEDATA';
3885 if (ingres_errno) return(mr_errcode);
3886 if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
3888 /* now retrieve the record id corresponding to the named object */
3889 if (index(data_type, ' '))
3890 *index(data_type, ' ') = 0;
3891 if (!strcmp(data_type, "user")) {
3893 status = name_to_id(name, data_type, &id);
3894 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3896 if (status) return(status);
3897 } else if (!strcmp(data_type, "list")) {
3899 status = name_to_id(name, data_type, &id);
3900 if (status && status == MR_NOT_UNIQUE)
3902 if (status == MR_NO_MATCH) {
3903 /* if idfield is non-zero, then if argv[0] matches the string
3904 * that we're trying to resolve, we should get the value of
3905 * numvalues.[idfield] for the id.
3907 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3908 set_next_object_id(q->validate->object_id, q->rtable, 0);
3910 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
3912 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
3915 } else if (status) return(status);
3916 } else if (!strcmp(data_type, "machine")) {
3918 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3919 status = name_to_id(name, data_type, &id);
3920 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3922 if (status) return(status);
3923 } else if (!strcmp(data_type, "string")) {
3925 status = name_to_id(name, data_type, &id);
3926 if (status && status == MR_NOT_UNIQUE)
3928 if (status == MR_NO_MATCH) {
3929 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3930 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
3932 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3933 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3934 cache_entry(name, "STRING", id);
3935 } else if (status) return(status);
3936 } else if (!strcmp(data_type, "none")) {
3942 /* now set value in argv */
3943 *(int *)argv[vo->index] = id;
3949 /* Lock the table named by the validation object */
3954 sprintf(stmt_buf,"UPDATE %s SET modtime='now' WHERE %s.%s = 0",
3955 vo->table,vo->table,vo->idfield);
3956 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
3957 if (ingres_errno) return(mr_errcode);
3958 if (sqlca.sqlerrd[2] != 1)
3965 /* Check the database at startup time. For now this just resets the
3966 * inprogress flags that the DCM uses.
3969 sanity_check_database()
3974 /* Dynamic SQL support routines */
3975 MR_SQLDA_T *mr_alloc_SQLDA()
3978 short *null_indicators;
3981 if((it=(MR_SQLDA_T *)malloc(sizeof(MR_SQLDA_T)))==NULL) {
3982 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
3986 if((null_indicators=(short *)calloc(QMAXARGS,sizeof(short)))==NULL) {
3987 com_err(whoami, MR_NO_MEM, "setting up SQLDA null indicators");
3991 for(j=0; j<QMAXARGS; j++) {
3992 if((it->sqlvar[j].sqldata=malloc(sizeof(short)+QMAXARGSIZE))==NULL) {
3993 com_err(whoami, MR_NO_MEM, "setting up SQLDA variables");
3996 it->sqlvar[j].sqllen=QMAXARGSIZE;
3997 it->sqlvar[j].sqlind=null_indicators+j;
3998 null_indicators[j]=0;
4005 /* Use this after FETCH USING DESCRIPTOR one or more
4006 * result columns may contain NULLs. This routine is
4007 * not currently needed, since db/schema creates all
4008 * columns with a NOT NULL WITH DEFAULT clause.
4010 * This is currently dead flesh, since no Moira columns
4011 * allow null values; all use default values.
4013 mr_fix_nulls_in_SQLDA(da)
4016 register IISQLVAR *var;
4020 for(j=0, var=da->sqlvar; j<da->sqld; j++, var++) {
4021 switch(var->sqltype) {
4022 case -IISQ_CHA_TYPE:
4026 case -IISQ_INT_TYPE:
4028 intp=(int *)var->sqldata;
4036 /* prefetch_value():
4037 * This routine fetches an appropriate value from the numvalues table.
4038 * It is a little hack to get around the fact that SQL doesn't let you
4039 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
4041 * It is called from the query table as (*v->pre_rtn)(q,Argv,cl) or
4042 * from within a setup_...() routine with the appropriate arguments.
4044 * Correct functioning of this routine may depend on the assumption
4045 * that this query is an APPEND.
4048 prefetch_value(q,argv,cl)
4053 EXEC SQL BEGIN DECLARE SECTION;
4054 char *name = q->validate->object_id;
4056 EXEC SQL END DECLARE SECTION;
4057 int status, limit, argc;
4059 /* set next object id, limiting it if necessary */
4060 if(!strcmp(name, "uid") || !strcmp(name, "gid"))
4061 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
4064 if((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
4067 /* fetch object id */
4068 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name=:name;
4069 if(ingres_errno) return(mr_errcode);
4070 if(sqlca.sqlerrd[2] != 1) return(MR_INTERNAL);
4072 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
4073 sprintf(argv[argc],"%d",value); /** Could save this step by changing tlist from %s to %d **/
4078 /* prefetch_filesys():
4079 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
4080 * Appends the filsys_id and the phys_id to the argv so they can be
4081 * referenced in an INSERT into a table other than filesys. Also
4082 * see comments at prefetch_value().
4084 * Assumes the existence of a row where filsys_id = argv[0], since a
4085 * filesys label has already been resolved to a filsys_id.
4087 prefetch_filesys(q,argv,cl)
4092 EXEC SQL BEGIN DECLARE SECTION;
4094 EXEC SQL END DECLARE SECTION;
4097 fid = *(int *)argv[0];
4098 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
4099 if(ingres_errno) return(mr_errcode);
4101 argc=q->argc+q->vcnt;
4102 sprintf(argv[argc++],"%d",phid);
4103 sprintf(argv[argc],"%d",fid);
4108 /* Convert normal Unix-style wildcards to SQL voodoo */
4109 convert_wildcards(arg)
4112 static char buffer[QMAXARGSIZE];
4113 register char *s, *d;
4115 for(d=buffer,s=arg;*s;s++) {
4117 case '*': *d++='%'; *d++='%'; break;
4118 case '?': *d++='_'; break;
4121 case ']': *d++='*'; *d++ = *s; break;
4122 case '%': *d++='*'; *d++='%'; *d++='%'; break;
4123 default: *d++ = *s; break;
4128 /* Copy back into argv */
4134 /* This version includes uppercase conversion, for things like gmac.
4135 * This is necessary because "LIKE" doesn't work with "uppercase()".
4136 * Including it in a wildcard routine saves making two passes over
4137 * the argument string.
4139 convert_wildcards_uppercase(arg)
4142 static char buffer[QMAXARGSIZE];
4143 register char *s, *d;
4145 for(d=buffer,s=arg;*s;s++) {
4147 case '*': *d++='%'; *d++='%'; break;
4148 case '?': *d++='_'; break;
4151 case ']': *d++='*'; *d++ = *s; break;
4152 case '%': *d++='*'; *d++='%'; *d++='%'; break;
4153 default: *d++=toupper(*s); break; /* This is the only diff. */
4158 /* Copy back into argv */
4165 /* Looks like it's time to build an abstraction barrier, Yogi */
4167 EXEC SQL BEGIN DECLARE SECTION;
4169 EXEC SQL END DECLARE SECTION;
4173 EXEC SQL PREPARE stmt FROM :stmt;
4174 EXEC SQL DESCRIBE stmt INTO :SQLDA;
4175 if(SQLDA->sqld==0) /* Not a SELECT */
4176 return(MR_INTERNAL);
4177 EXEC SQL DECLARE csr CURSOR FOR stmt;
4179 EXEC SQL FETCH csr USING DESCRIPTOR :SQLDA;
4180 if(sqlca.sqlcode==0)
4182 else if((sqlca.sqlcode<0) && mr_errcode)
4191 /* eof:qsupport.dc */