7 * Copyright (C) 1987 by the Massachusetts Institute of Technology
8 * For copying and distribution information, please see the file
14 static char *rcsid_qsupport_dc = "$Header$";
17 #include <mit-copyright.h>
19 #include "mr_server.h"
24 EXEC SQL INCLUDE sqlca;
25 EXEC SQL INCLUDE sqlda;
28 extern char *whoami, *strsave();
29 extern int ingres_errno, mr_errcode;
31 EXEC SQL BEGIN DECLARE SECTION;
34 extern char stmt_buf[];
35 EXEC SQL END DECLARE SECTION;
37 /* Specialized Access Routines */
39 /* access_user - verify that client name equals specified login name
41 * - since field validation routines are called first, a users_id is
42 * now in argv[0] instead of the login name.
45 EXEC SQL WHENEVER SQLERROR CALL ingerr;
47 access_user(q, argv, cl)
52 if (cl->users_id != *(int *)argv[0])
60 /* access_login - verify that client name equals specified login name
62 * argv[0...n] contain search info. q->
65 access_login(q, argv, cl)
70 EXEC SQL BEGIN DECLARE SECTION;
73 EXEC SQL END DECLARE SECTION;
75 build_qual(q->qual, q->argc, argv, qual);
76 EXEC SQL SELECT users_id INTO :id FROM users WHERE :qual;
78 if (sqlca.sqlerrd[2] != 1 || id != cl->users_id)
86 /* access_list - check access for most list operations
88 * Inputs: argv[0] - list_id
90 * argv[2] - member ID (only for queries "amtl" and "dmfl")
91 * argv[7] - group IID (only for query "ulis")
94 * - check that client is a member of the access control list
95 * - OR, if the query is add_member_to_list or delete_member_from_list
96 * and the list is public, allow access if client = member
99 access_list(q, argv, cl)
104 EXEC SQL BEGIN DECLARE SECTION;
105 int list_id, acl_id, flags, gid;
107 EXEC SQL END DECLARE SECTION;
109 int client_id, status;
111 list_id = *(int *)argv[0];
112 EXEC SQL SELECT acl_id, acl_type, gid, publicflg
113 INTO :acl_id, :acl_type, :gid, :flags
115 WHERE list_id = :list_id;
117 if (sqlca.sqlerrd[2] != 1)
120 /* parse client structure */
121 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
124 /* if amtl or dmfl and list is public allow client to add or delete self */
125 if (((!strcmp("amtl", q->shortname) && flags) ||
126 (!strcmp("dmfl", q->shortname))) &&
127 (!strcmp("USER", argv[1]))) {
128 if (*(int *)argv[2] == client_id) return(MR_SUCCESS);
129 /* if update_list, don't allow them to change the GID */
130 } else if (!strcmp("ulis", q->shortname)) {
131 if ((!strcmp(argv[7], UNIQUE_GID) && (gid != -1)) ||
132 (strcmp(argv[7], UNIQUE_GID) && (gid != atoi(argv[7]))))
136 /* check for client in access control list */
137 status = find_member(acl_type, acl_id, client_type, client_id, 0);
138 if (!status) return(MR_PERM);
144 /* access_visible_list - allow access to list only if it is not hidden,
145 * or if the client is on the ACL
147 * Inputs: argv[0] - list_id
148 * cl - client identifier
151 access_visible_list(q, argv, cl)
156 EXEC SQL BEGIN DECLARE SECTION;
157 int list_id, acl_id, flags ;
159 EXEC SQL END DECLARE SECTION;
161 int client_id, status;
163 list_id = *(int *)argv[0];
164 EXEC SQL SELECT hidden, acl_id, acl_type
165 INTO :flags, :acl_id, :acl_type
167 WHERE list_id = :list_id;
168 if (sqlca.sqlerrd[2] != 1)
173 /* parse client structure */
174 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
177 /* check for client in access control list */
178 status = find_member(acl_type, acl_id, client_type, client_id, 0);
186 /* access_vis_list_by_name - allow access to list only if it is not hidden,
187 * or if the client is on the ACL
189 * Inputs: argv[0] - list name
190 * cl - client identifier
193 access_vis_list_by_name(q, argv, cl)
198 EXEC SQL BEGIN DECLARE SECTION;
199 int acl_id, flags, rowcount;
200 char acl_type[9], *listname;
201 EXEC SQL END DECLARE SECTION;
203 int client_id, status;
206 EXEC SQL SELECT hidden, acl_id, acl_type INTO :flags, :acl_id, :acl_type
207 FROM list WHERE name = :listname;
209 rowcount=sqlca.sqlerrd[2];
217 /* parse client structure */
218 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
221 /* check for client in access control list */
222 status = find_member(acl_type, acl_id, client_type, client_id, 0);
230 /* access_member - allow user to access member of type "USER" and name matches
231 * username, or to access member of type "LIST" and list is one that user is
232 * on the acl of, or the list is visible.
235 access_member(q, argv, cl)
240 if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST"))
241 return(access_visible_list(q, &argv[1], cl));
243 if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) {
244 if (cl->users_id == *(int *)argv[1])
252 /* access_qgli - special access routine for Qualified_get_lists. Allows
253 * access iff argv[0] == "TRUE" and argv[2] == "FALSE".
256 access_qgli(q, argv, cl)
261 if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE"))
267 /* access_service - allow access if user is on ACL of service. Don't
268 * allow access if a wildcard is used.
271 access_service(q, argv, cl)
276 EXEC SQL BEGIN DECLARE SECTION;
278 char *name, acl_type[9];
279 EXEC SQL END DECLARE SECTION;
280 int client_id, status;
281 char *client_type, *c;
284 for(c=name;*c;c++) if(islower(*c)) *c = toupper(*c); /* uppercasify */
285 EXEC SQL SELECT acl_id, acl_type INTO :acl_id, :acl_type FROM servers
287 if (sqlca.sqlerrd[2] > 1)
290 /* parse client structure */
291 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
294 /* check for client in access control list */
295 status = find_member(acl_type, acl_id, client_type, client_id, 0);
296 if (!status) return(MR_PERM);
302 /* access_filesys - verify that client is owner or on owners list of filesystem
306 access_filesys(q, argv, cl)
311 EXEC SQL BEGIN DECLARE SECTION;
312 int users_id, list_id;
314 EXEC SQL END DECLARE SECTION;
315 int status, client_id;
319 EXEC SQL SELECT owner, owners INTO :users_id, :list_id FROM filesys
322 if (sqlca.sqlerrd[2] != 1)
324 if (users_id == cl->users_id)
326 if ((status = get_client(cl, &client_type, &client_id)) != MR_SUCCESS)
328 status = find_member("LIST", list_id, client_type, client_id, 0);
339 /* Setup routine for add_user
341 * Inputs: argv[0] - login
346 * - if argv[1] == UNIQUE_UID then set argv[1] = next(uid)
347 * - if argv[0] == UNIQUE_LOGIN then set argv[0] = "#<uid>"
350 setup_ausr(q, argv, cl)
352 register char *argv[];
356 EXEC SQL BEGIN DECLARE SECTION;
358 EXEC SQL END DECLARE SECTION;
360 if (!strcmp(q->shortname, "uusr") || !strcmp(q->shortname, "uuac"))
364 if (!strcmp(argv[row], UNIQUE_UID) || atoi(argv[row]) == -1) {
365 if (set_next_object_id("uid", "users", 1))
366 return(MR_INGRES_ERR);
367 EXEC SQL SELECT value INTO :nuid FROM numvalues WHERE name = 'uid';
368 if (sqlca.sqlerrd[2] != 1)
370 sprintf(argv[row], "%d", nuid);
373 if (!strcmp(argv[0], UNIQUE_LOGIN) || atoi(argv[row]) == -1) {
374 sprintf(argv[0], "#%s", argv[row]);
377 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
384 /* setup_dusr - verify that the user is no longer being referenced
385 * and may safely be deleted.
388 int setup_dusr(q, argv)
392 EXEC SQL BEGIN DECLARE SECTION;
394 EXEC SQL END DECLARE SECTION;
396 id = *(int *)argv[0];
398 /* For now, only allow users to be deleted if their status is 0 */
399 EXEC SQL REPEATED SELECT status INTO :flag FROM users
400 WHERE users_id = :id;
401 if (flag != 0 && flag != 4)
404 EXEC SQL REPEATED DELETE FROM quota WHERE entity_id = :id AND type = 'USER';
405 EXEC SQL REPEATED DELETE FROM krbmap WHERE users_id = :id;
406 EXEC SQL REPEATED SELECT member_id INTO :idummy FROM imembers
407 WHERE member_id = :id AND member_type = 'USER';
408 if (sqlca.sqlerrd[2] > 0)
410 EXEC SQL REPEATED SELECT label INTO :cdummy FROM filesys WHERE owner = :id;
411 if (sqlca.sqlerrd[2]> 0)
413 EXEC SQL REPEATED SELECT name INTO :cdummy FROM list
414 WHERE acl_id = :id AND acl_type = 'USER';
415 if (sqlca.sqlerrd[2] > 0)
417 EXEC SQL REPEATED SELECT name INTO :cdummy FROM servers
418 WHERE acl_id = :id AND acl_type = 'USER';
419 if (sqlca.sqlerrd[2] > 0)
421 EXEC SQL REPEATED SELECT acl_id INTO :idummy FROM hostaccess
422 WHERE acl_id = :id AND acl_type = 'USER';
423 if (sqlca.sqlerrd[2] > 0)
431 /* setup_spop: verify that there is already a valid POP machine_id in the
432 * pop_id field. Also take care of keeping track of the post office usage.
434 int setup_spop(q, argv)
438 EXEC SQL BEGIN DECLARE SECTION;
441 EXEC SQL END DECLARE SECTION;
443 id = *(int *)argv[0];
444 EXEC SQL REPEATED SELECT potype, pop_id INTO :type, :mid FROM users
445 WHERE users_id = :id;
446 if(sqlca.sqlerrd[2] = 0)
448 EXEC SQL REPEATED SELECT mach_id INTO :mid FROM machine
449 WHERE mach_id = :mid;
450 if (sqlca.sqlerrd[2] = 0)
452 if (strcmp(strtrim(type), "POP"))
453 set_pop_usage(mid, 1);
458 /* setup_dpob: Take care of keeping track of the post office usage.
460 int setup_dpob(q, argv)
464 EXEC SQL BEGIN DECLARE SECTION;
467 EXEC SQL END DECLARE SECTION;
469 user = *(int *)argv[0];
470 EXEC SQL REPEATED SELECT potype, pop_id INTO :type, :id FROM users
471 WHERE users_id = :user;
472 if (ingres_errno) return(mr_errcode);
474 if (!strcmp(strtrim(type), "POP"))
475 set_pop_usage(id, -1);
480 /* setup_dmac - verify that the machine is no longer being referenced
481 * and may safely be deleted.
484 int setup_dmac(q, argv)
488 EXEC SQL BEGIN DECLARE SECTION;
490 EXEC SQL END DECLARE SECTION;
492 id = *(int *)argv[0];
493 EXEC SQL REPEATED SELECT login INTO :cdummy FROM users
494 WHERE potype='POP' AND pop_id = :id;
495 if (sqlca.sqlerrd[2] > 0)
497 EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM serverhosts
499 if (sqlca.sqlerrd[2] > 0)
501 EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM nfsphys
503 if (sqlca.sqlerrd[2] > 0)
505 EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM hostaccess
507 if (sqlca.sqlerrd[2] > 0)
509 EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM printcap
511 if (sqlca.sqlerrd[2] > 0)
513 EXEC SQL REPEATED SELECT quotaserver INTO :idummy FROM printcap
514 WHERE quotaserver = :id;
515 if (sqlca.sqlerrd[2] > 0)
517 EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM palladium
519 if (sqlca.sqlerrd[2] > 0)
522 EXEC SQL REPEATED DELETE FROM mcmap WHERE mach_id = :id;
523 if (ingres_errno) return(mr_errcode);
528 /* setup_dclu - verify that the cluster is no longer being referenced
529 * and may safely be deleted.
532 int setup_dclu(q, argv)
536 EXEC SQL BEGIN DECLARE SECTION;
538 EXEC SQL END DECLARE SECTION;
540 id = *(int *)argv[0];
541 EXEC SQL REPEATED SELECT mach_id INTO :idummy FROM mcmap
543 if (sqlca.sqlerrd[2] > 0)
545 EXEC SQL REPEATED SELECT clu_id INTO :idummy FROM svc
547 if (sqlca.sqlerrd[2] > 0)
555 /* setup_alis - if argv[5] is non-zero and argv[6] is UNIQUE_ID, then allocate
556 * a new gid and put it in argv[6]. Otherwise if argv[6] is UNIQUE_ID but
557 * argv[5] is not, then remember that UNIQUE_ID is being stored by putting
558 * a -1 there. Remember that this is also used for ulis, with the indexes
562 int setup_alis(q, argv, cl)
567 EXEC SQL BEGIN DECLARE SECTION;
569 EXEC SQL END DECLARE SECTION;
573 if (!strcmp(q->shortname, "alis"))
575 else if (!strcmp(q->shortname, "ulis"))
578 if (!strcmp(argv[idx], UNIQUE_GID) || atoi(argv[idx]) == -1) {
579 if (atoi(argv[idx - 1])) {
580 if (set_next_object_id("gid", "list", 1))
581 return(MR_INGRES_ERR);
582 EXEC SQL REPEATED SELECT value INTO :ngid FROM numvalues
584 if (ingres_errno) return(mr_errcode);
585 sprintf(argv[idx], "%d", ngid);
587 strcpy(argv[idx], "-1");
591 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
598 /* setup_dlis - verify that the list is no longer being referenced
599 * and may safely be deleted.
602 int setup_dlis(q, argv)
606 EXEC SQL BEGIN DECLARE SECTION;
608 EXEC SQL END DECLARE SECTION;
610 id = *(int *)argv[0];
611 EXEC SQL REPEATED SELECT member_id INTO :idummy FROM imembers
612 WHERE member_id = :id AND member_type='LIST';
613 if (sqlca.sqlerrd[2] > 0)
615 EXEC SQL REPEATED SELECT member_id INTO :idummy FROM imembers
617 if (sqlca.sqlerrd[2] > 0)
619 EXEC SQL REPEATED SELECT label INTO :cdummy FROM filesys
621 if (sqlca.sqlerrd[2] > 0)
623 EXEC SQL REPEATED SELECT tag INTO :cdummy FROM capacls
625 if (sqlca.sqlerrd[2] > 0)
627 EXEC SQL REPEATED SELECT name INTO :cdummy FROM list
628 WHERE acl_id = :id AND acl_type='LIST' AND list_id = :id;
629 if (sqlca.sqlerrd[2] > 0)
631 EXEC SQL REPEATED SELECT name INTO :cdummy FROM servers
632 WHERE acl_id = :id AND acl_type='LIST';
633 if (sqlca.sqlerrd[2] > 0)
635 EXEC SQL REPEATED SELECT entity_id INTO :idummy FROM quota
636 WHERE entity_id = :id AND type='GROUP';
637 if (sqlca.sqlerrd[2] > 0)
639 EXEC SQL REPEATED SELECT acl_id INTO :idummy FROM hostaccess
640 WHERE acl_id = :id AND acl_type='LIST';
641 if (sqlca.sqlerrd[2] > 0)
643 EXEC SQL REPEATED SELECT class INTO :cdummy FROM zephyr z
644 WHERE zephyr.xmt_type = 'LIST' AND z.xmt_id = :id
645 OR z.sub_type = 'LIST' AND z.sub_id = :id
646 OR z.iws_type = 'LIST' AND z.iws_id = :id
647 OR z.iui_type = 'LIST' AND z.iui_id = :id;
648 if (sqlca.sqlerrd[2] > 0)
656 /* setup_dsin - verify that the service is no longer being referenced
657 * and may safely be deleted.
660 int setup_dsin(q, argv)
664 EXEC SQL BEGIN DECLARE SECTION;
666 EXEC SQL END DECLARE SECTION;
670 for(c=name;*c;c++) if(islower(*c)) *c = toupper(*c);
671 EXEC SQL REPEATED SELECT service INTO :cdummy FROM serverhosts
672 WHERE service = :name;
673 if (sqlca.sqlerrd[2] > 0)
675 EXEC SQL REPEATED SELECT inprogress INTO :idummy FROM servers
677 if (sqlca.sqlerrd[2] > 0)
685 /* setup_dshi - verify that the service-host is no longer being referenced
686 * and may safely be deleted.
689 int setup_dshi(q, argv)
693 EXEC SQL BEGIN DECLARE SECTION;
696 EXEC SQL END DECLARE SECTION;
699 for(c=name;*c;c++) if(islower(*c)) *c = toupper(*c); /* to uppercase */
700 id = *(int *)argv[1];
701 EXEC SQL REPEATED SELECT inprogress INTO :idummy FROM serverhosts
702 WHERE service = :name AND mach_id = :id;
703 if (sqlca.sqlerrd[2] > 0)
712 ** setup_add_filesys - verify existance of referenced file systems
724 ** * extract directory prefix from name
725 ** * verify mach_id/dir in nfsphys
726 ** * verify access in {r, w, R, W}
728 ** Side effect: sets variable var_phys_id to the ID of the physical
729 ** filesystem (nfsphys_id for NFS, 0 for RVD)
732 ** MR_NFS - specified directory not exported
733 ** MR_FILESYS_ACCESS - invalid filesys access
737 EXEC SQL BEGIN DECLARE SECTION;
738 static int var_phys_id;
739 EXEC SQL END DECLARE SECTION;
741 setup_afil(q, argv, cl)
748 EXEC SQL BEGIN DECLARE SECTION;
750 char ftype[32], *access;
751 EXEC SQL END DECLARE SECTION;
754 mach_id = *(int *)argv[2];
759 sprintf(ftype, "fs_access_%s", type);
760 EXEC SQL SELECT trans INTO :cdummy FROM alias
761 WHERE name = :ftype AND type = 'TYPE' and trans = :access;
762 if (ingres_errno) return(mr_errcode);
763 if (sqlca.sqlerrd[2] == 0) return(MR_FILESYS_ACCESS);
765 if (!strcmp(type, "NFS"))
766 return (check_nfs(mach_id, name, access));
768 if((mr_errcode=prefetch_value(q,argv,cl))!=MR_SUCCESS)
775 /* Verify the arguments, depending on the FStype. Also, if this is an
776 * NFS filesystem, then update any quotas for that filesystem to reflect
780 setup_ufil(q, argv, cl)
787 EXEC SQL BEGIN DECLARE SECTION;
789 char *entity, ftype[32], *access;
791 EXEC SQL END DECLARE SECTION;
794 mach_id = *(int *)argv[3];
797 fid = *(int *)argv[0];
801 sprintf(ftype, "fs_access_%s", type);
802 EXEC SQL SELECT trans INTO :cdummy FROM alias
803 WHERE name = :ftype AND type='TYPE' AND trans = :access;
804 if (ingres_errno) return(mr_errcode);
805 if (sqlca.sqlerrd[2] == 0) return(MR_FILESYS_ACCESS);
807 if (!strcmp(type, "NFS")) {
808 status = check_nfs(mach_id, name, access);
809 EXEC SQL UPDATE quota SET phys_id = :var_phys_id
810 WHERE filsys_id = :fid;
811 if (ingres_errno) return(mr_errcode);
813 } else if (!strcmp(type, "AFS")) {
815 EXEC SQL REPEATED DELETE FROM quota
816 WHERE type = 'ANY' AND filsys_id = :fid;
817 EXEC SQL SELECT SUM (quota) INTO :total FROM quota
818 WHERE filsys_id = :fid AND phys_id != 0;
819 if (ingres_errno) return(mr_errcode);
822 * append quota (quota = total, filsys_id = fid,
823 * phys_id = 0, entity_id = 0, type = "ANY",
824 * modtime = "now", modby = who, modwith = entity)
826 EXEC SQL INSERT INTO quota (quota, filsys_id, phys_id, entity_id,
827 type, modtime, modby, modwith)
828 VALUES (:total, :fid, 0, 0,
829 'ANY', 'now', :who, :entity) ;
830 if (ingres_errno) return(mr_errcode);
833 EXEC SQL UPDATE quota SET phys_id = 0 WHERE filsys_id = :fid;
834 if (ingres_errno) return(mr_errcode);
840 /* Find the NFS physical partition that the named directory is on.
841 * This is done by comparing the dir against the mount point of the
842 * partition. To make sure we get the correct match when there is
843 * more than one, we sort the query in reverse order by dir name.
846 check_nfs(mach_id, name, access)
847 EXEC SQL BEGIN DECLARE SECTION;
849 EXEC SQL END DECLARE SECTION;
853 EXEC SQL BEGIN DECLARE SECTION;
855 EXEC SQL END DECLARE SECTION;
862 EXEC SQL DECLARE csr101 CURSOR FOR
863 SELECT nfsphys_id, TRIM (dir) FROM nfsphys
864 WHERE mach_id = :mach_id
866 EXEC SQL OPEN csr101;
868 EXEC SQL FETCH csr101 INTO :var_phys_id, :dir;
869 if(sqlca.sqlcode != 0) break;
873 if (*cp1++ != *cp2) break;
881 EXEC SQL CLOSE csr101;
888 /* setup_dfil: free any quota records and fsgroup info associated with
889 * a filesystem when it is deleted. Also adjust the allocation numbers.
892 setup_dfil(q, argv, cl)
897 EXEC SQL BEGIN DECLARE SECTION;
899 EXEC SQL END DECLARE SECTION;
901 id = *(int *)argv[0];
902 EXEC SQL REPEATED SELECT SUM (quota) INTO :total FROM quota
903 WHERE filsys_id = :id;
904 EXEC SQL REPEATED UPDATE nfsphys SET allocated = allocated - :total
905 WHERE nfsphys_id = filesys.phys_id AND filesys.filsys_id = :id;
906 /** Is SQL smart enough to do the PRODUCT above? */
907 /** Or should we code it using another SELECT? */
909 EXEC SQL REPEATED DELETE FROM quota WHERE filsys_id = :id;
910 EXEC SQL REPEATED DELETE FROM fsgroup WHERE filsys_id = :id;
911 EXEC SQL REPEATED DELETE FROM fsgroup WHERE group_id = :id;
912 if (ingres_errno) return(mr_errcode);
917 /* setup_dnfp: check to see that the nfs physical partition does not have
918 * any filesystems assigned to it before allowing it to be deleted.
921 setup_dnfp(q, argv, cl)
926 EXEC SQL BEGIN DECLARE SECTION;
929 EXEC SQL END DECLARE SECTION;
931 id = *(int *)argv[0];
933 EXEC SQL REPEATED SELECT label INTO :cdummy FROM filesys fs, nfsphys np
934 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
935 AND np.mach_id = :id AND np.dir = :dir;
936 if (sqlca.sqlerrd[2] > 0)
944 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
945 * argv[0] = filsys_id
946 * argv[1] = type if "update_quota" or "delete_quota"
947 * argv[2 or 1] = users_id or list_id
950 setup_dqot(q, argv, cl)
955 EXEC SQL BEGIN DECLARE SECTION;
958 EXEC SQL END DECLARE SECTION;
960 fs = *(int *)argv[0];
961 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
963 id = *(int *)argv[2];
966 id = *(int *)argv[1];
969 EXEC SQL REPEATED SELECT quota INTO :quota FROM quota
970 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
971 EXEC SQL REPEATED UPDATE nfsphys
972 SET allocated = nfsphys.allocated - :quota
973 WHERE nfsphys_id = filesys.physid AND filesys.filsys_id = :fs;
975 if (ingres_errno) return(mr_errcode);
980 /* setup_sshi: don't exclusive lock the machine table during
981 * set_server_host_internal.
984 setup_sshi(q, argv, cl)
990 EXEC SQL set lockmode session where readlock = system;
995 /* setup add_kerberos_user_mapping: add the string to the string
996 * table if necessary.
999 setup_akum(q, argv, cl)
1004 EXEC SQL BEGIN DECLARE SECTION;
1007 EXEC SQL END DECLARE SECTION;
1010 if (name_to_id(name, "STRING", &id) != MR_SUCCESS) {
1011 if (q->type != APPEND) return(MR_STRING);
1012 EXEC SQL SELECT value INTO :id FROM numvalues
1013 WHERE name = 'strings_id';
1015 EXEC SQL UPDATE numvalues SET value = :id
1016 WHERE name = 'strings_id';
1017 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
1018 cache_entry(name, "STRING", id);
1020 if (ingres_errno) return(mr_errcode);
1021 *(int *)argv[1] = id;
1027 /* FOLLOWUP ROUTINES */
1029 /* generic set_modtime routine. This takes the table name from the query,
1030 * and will update the modtime, modby, and modwho fields in the entry in
1031 * the table whose name field matches argv[0].
1034 set_modtime(q, argv, cl)
1039 char *name, *entity, *table;
1042 entity = cl->entity;
1043 who = cl->client_id;
1047 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, \
1048 modwith = '%s' WHERE %s.name = '%s'",table,who,entity,table,name);
1049 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1054 /* generic set_modtime_by_id routine. This takes the table name from
1055 * the query, and the id name from the validate record,
1056 * and will update the modtime, modby, and modwho fields in the entry in
1057 * the table whose id matches argv[0].
1060 set_modtime_by_id(q, argv, cl)
1065 char *entity, *table, *id_name;
1068 entity = cl->entity;
1069 who = cl->client_id;
1071 id_name = q->validate->object_id;
1073 id = *(int *)argv[0];
1074 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, \
1075 modwith = '%s' WHERE %s.%s = %d",table,who,entity,table,id_name,id);
1076 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1081 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
1084 set_finger_modtime(q, argv, cl)
1089 EXEC SQL BEGIN DECLARE SECTION;
1092 EXEC SQL END DECLARE SECTION;
1094 entity = cl->entity;
1095 who = cl->client_id;
1096 users_id = *(int *)argv[0];
1098 EXEC SQL UPDATE users SET fmodtime='now', fmodby = :who, fmodwith = :entity
1099 WHERE users.users_id = :users_id;
1105 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
1108 set_pobox_modtime(q, argv, cl)
1113 EXEC SQL BEGIN DECLARE SECTION;
1116 EXEC SQL END DECLARE SECTION;
1118 entity = cl->entity;
1119 who = cl->client_id;
1120 users_id = *(int *)argv[0];
1122 EXEC SQL UPDATE users SET pmodtime='now', pmodby = :who, pmodwith = entity
1123 WHERE users.users_id = users_id;
1129 /* Like set_modtime, but uppercases the name first.
1132 set_uppercase_modtime(q, argv, cl)
1137 char *name, *entity, *table, *c;
1140 entity = cl->entity;
1141 who = cl->client_id;
1144 for(c=name;*c;c++) if(islower(*c)) *c = toupper(*c); /** INGRES has an uppercase() functiuons, but it's not portable. */
1146 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, \
1147 modwith = '%s' WHERE %s.name = '%s'",table,who,entity,table,name);
1148 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1154 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
1155 * is necessary for add_machine_to_cluster becuase the table that query
1156 * operates on is "mcm", not "machine".
1159 set_mach_modtime_by_id(q, argv, cl)
1164 EXEC SQL BEGIN DECLARE SECTION;
1167 EXEC SQL END DECLARE SECTION;
1169 entity = cl->entity;
1170 who = cl->client_id;
1171 id = *(int *)argv[0];
1172 EXEC SQL UPDATE machine SET modtime='now', modby = :who, modwith = :entity
1173 WHERE machine.mach_id = :id;
1179 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
1180 * is necessary for add_cluster_data and delete_cluster_data becuase the
1181 * table that query operates on is "svc", not "cluster".
1184 set_cluster_modtime_by_id(q, argv, cl)
1189 EXEC SQL BEGIN DECLARE SECTION;
1192 EXEC SQL END DECLARE SECTION;
1194 entity = cl->entity;
1195 who = cl->client_id;
1197 id = *(int *)argv[0];
1198 EXEC SQL UPDATE cluster SET modtime='now', modby = :who, modwith = :entity
1199 WHERE cluster.clu_id = :id;
1204 /* sets the modtime on the serverhost where the service name is in argv[0]
1205 * and the mach_id is in argv[1].
1208 set_serverhost_modtime(q, argv, cl)
1213 EXEC SQL BEGIN DECLARE SECTION;
1214 char *entity, *serv;
1216 EXEC SQL END DECLARE SECTION;
1218 entity = cl->entity;
1219 who = cl->client_id;
1222 id = *(int *)argv[1];
1223 EXEC SQL UPDATE serverhosts
1224 SET modtime = 'now', modby = :who, modwith = :entity
1225 WHERE service = :serv AND mach_id = :id;
1230 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1231 * directory name is in argv[1].
1234 set_nfsphys_modtime(q, argv, cl)
1239 EXEC SQL BEGIN DECLARE SECTION;
1242 EXEC SQL END DECLARE SECTION;
1244 entity = cl->entity;
1245 who = cl->client_id;
1247 id = *(int *)argv[0];
1249 EXEC SQL UPDATE nfsphys SET modtime = 'now', modby = :who, modwith = :entity
1250 WHERE dir = :dir AND mach_id = :id;
1255 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1259 set_filesys_modtime(q, argv, cl)
1264 EXEC SQL BEGIN DECLARE SECTION;
1265 char *label, *entity;
1267 EXEC SQL END DECLARE SECTION;
1269 entity = cl->entity;
1270 who = cl->client_id;
1273 if (!strcmp(q->shortname, "ufil"))
1276 EXEC SQL UPDATE filesys SET modtime = 'now', modby = :who,
1277 modwith = :entity, phys_id = :var_phys_id
1278 WHERE label = :label;
1283 /* sets the modtime on a zephyr class, where argv[0] contains the class
1287 set_zephyr_modtime(q, argv, cl)
1292 EXEC SQL BEGIN DECLARE SECTION;
1293 char *class, *entity;
1295 EXEC SQL END DECLARE SECTION;
1297 entity = cl->entity;
1298 who = cl->client_id;
1302 EXEC SQL UPDATE zephyr SET modtime = 'now', modby = :who, modwith = :entity
1303 WHERE class = :class;
1309 /* fixes the modby field. This will be the second to last thing in the
1310 * argv, the argv length is determined from the query structure. It is
1311 * passed as a pointer to an integer. This will either turn it into a
1312 * username, or # + the users_id.
1314 followup_fix_modby(q, sq, v, action, actarg, cl)
1316 register struct save_queue *sq;
1318 register int (*action)();
1319 register int actarg;
1323 char **argv, *malloc();
1327 while (sq_get_data(sq, &argv)) {
1330 status = id_to_name(id, "USER", &argv[i]);
1332 status = id_to_name(-id, "STRING", &argv[i]);
1333 if (status && status != MR_NO_MATCH)
1335 (*action)(q->vcnt, argv, actarg);
1336 for (j = 0; j < q->vcnt; j++)
1345 /* After retrieving a user account, fix the modby field and signature.
1346 * The modby field is the second to last thing in the
1347 * argv, the argv length is determined from the query structure. It is
1348 * passed as a pointer to an integer. This will either turn it into a
1349 * username, or # + the users_id. Only "gua*" queries have a signature,
1350 * these are ones with U_END return values. "gub*" queries also use this
1351 * routine but don't have a signature.
1353 followup_guax(q, sq, v, action, actarg, cl)
1355 register struct save_queue *sq;
1357 register int (*action)();
1358 register int actarg;
1362 char **argv, *malloc();
1364 char sigbuf[256], *rawsig, *kname;
1370 while (sq_get_data(sq, &argv)) {
1373 status = id_to_name(id, "USER", &argv[i]);
1375 status = id_to_name(-id, "STRING", &argv[i]);
1376 if (status && status != MR_NO_MATCH)
1379 if (q->vcnt == U_END) {
1380 com_err(whoami, 0, "compressing signature");
1381 rawsig = argv[U_SIGNATURE];
1382 bcopy(&rawsig[0], &id, sizeof(int));
1384 status = id_to_name(id, "STRING", &kname);
1385 bcopy(&rawsig[4], &si.timestamp, sizeof(int));
1386 si.timestamp = ntohl(si.timestamp);
1387 si.SigInfoVersion = 0; /* XXXXX this isn't used */
1388 kname_parse(si.pname, si.pinst, si.prealm, kname);
1389 si.rawsig = (unsigned char *)&rawsig[8];
1390 GDSS_Recompose(&si, sigbuf);
1391 argv[U_SIGNATURE] = strsave(sigbuf);
1394 (*action)(q->vcnt, argv, actarg);
1395 for (j = 0; j < q->vcnt; j++)
1405 ** followup_ausr - add finger and pobox entries, set_user_modtime
1408 ** argv[0] - login (add_user)
1409 ** argv[3] - last name
1410 ** argv[4] - first name
1411 ** argv[5] - middle name
1415 followup_ausr(q, argv, cl)
1420 EXEC SQL BEGIN DECLARE SECTION;
1421 int who, status, sigwho, id;
1422 char *login, *entity, *src, *dst, *name;
1424 EXEC SQL END DECLARE SECTION;
1426 char databuf[32], *kname_unparse();
1427 EXEC SQL BEGIN DECLARE SECTION;
1429 EXEC SQL END DECLARE SECTION;
1433 /* build fullname */
1434 if (strlen(argv[4]) && strlen(argv[5]))
1435 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1436 else if (strlen(argv[4]))
1437 sprintf(fullname, "%s %s", argv[4], argv[3]);
1439 sprintf(fullname, "%s", argv[3]);
1442 sprintf(databuf, "%s:%s", argv[U_NAME], argv[U_MITID]);
1443 /* skip bytes for timestamp & kname */
1444 si.rawsig = (unsigned char *)&rawsig[8];
1445 status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE], &si);
1447 name = kname_unparse(si.pname, si.pinst, si.prealm);
1448 status = name_to_id(name, "STRING", &sigwho);
1449 if (status == MR_NO_MATCH) {
1450 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1451 WHERE name = 'strings_id';
1453 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1454 WHERE name = 'strings_id';
1455 EXEC SQL INSERT INTO strings (string_id, string)
1456 VALUES (:sigwho, :name);
1459 sigwho = htonl(sigwho);
1460 bcopy(&sigwho, &rawsig[0], sizeof(int));
1461 si.timestamp = htonl(si.timestamp);
1462 bcopy(&si.timestamp, &rawsig[4], sizeof(int));
1468 who = cl->client_id;
1469 entity = cl->entity;
1471 /* create finger entry, pobox & set modtime on user */
1473 EXEC SQL REPEATED UPDATE users
1474 SET modtime='now', modby=:who, modwith = :entity,
1475 fullname = :fullname, affiliation = type,
1476 signature = :rawsig,
1477 fmodtime='now', fmodby = :who, fmodwith = :entity,
1478 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1479 WHERE login = :login;
1481 EXEC SQL REPEATED UPDATE users
1482 SET modtime='now', modby=:who, modwith = :entity,
1483 fullname = :fullname, affiliation = type,
1484 fmodtime='now', fmodby = :who, fmodwith = :entity,
1485 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1486 WHERE login = :login;
1493 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1494 * type in argv[1]. Then completes the upcall to the user.
1496 * argv[2] is of the form "123:234" where the first integer is the machine
1497 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1498 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1502 followup_gpob(q, sq, v, action, actarg, cl)
1503 register struct query *q;
1504 register struct save_queue *sq;
1505 register struct validate *v;
1506 register int (*action)();
1510 char **argv, *index();
1512 int mid, sid, status;
1515 while (sq_get_data(sq, &argv)) {
1516 mr_trim_args(2, argv);
1518 p = index(argv[2], ':');
1520 mid = atoi(argv[2]);
1523 if (!strcmp(ptype, "POP")) {
1524 status = id_to_name(mid, "MACHINE", &argv[2]);
1525 if (status == MR_NO_MATCH)
1527 } else if (!strcmp(ptype, "SMTP")) {
1528 status = id_to_name(sid, "STRING", &argv[2]);
1529 if (status == MR_NO_MATCH)
1531 } else /* ptype == "NONE" */ {
1534 if (status) return(status);
1536 if (!strcmp(q->shortname, "gpob")) {
1537 sid = atoi(argv[4]);
1539 status = id_to_name(sid, "USER", &argv[4]);
1541 status = id_to_name(-sid, "STRING", &argv[4]);
1543 if (status && status != MR_NO_MATCH) return(status);
1545 (*action)(q->vcnt, argv, actarg);
1547 /* free saved data */
1555 return (MR_SUCCESS);
1559 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1560 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1561 * proper name based on the type, and repace that string in the argv.
1562 * Also fixes the modby field by called followup_fix_modby.
1565 followup_glin(q, sq, v, action, actarg, cl)
1566 register struct query *q;
1567 register struct save_queue *sq;
1568 register struct validate *v;
1569 register int (*action)();
1573 char **argv, *malloc(), *realloc(), *type;
1574 int id, i, idx, status;
1577 if (!strcmp(q->shortname, "gsin"))
1580 while (sq_get_data(sq, &argv)) {
1581 mr_trim_args(q->vcnt, argv);
1583 id = atoi(argv[i = q->vcnt - 2]);
1585 status = id_to_name(id, "USER", &argv[i]);
1587 status = id_to_name(-id, "STRING", &argv[i]);
1588 if (status && status != MR_NO_MATCH)
1591 id = atoi(argv[idx]);
1592 type = argv[idx - 1];
1594 if (!strcmp(type, "LIST")) {
1595 status = id_to_name(id, "LIST", &argv[idx]);
1596 } else if (!strcmp(type, "USER")) {
1597 status = id_to_name(id, "USER", &argv[idx]);
1598 } else if (!strcmp(type, "KERBEROS")) {
1599 status = id_to_name(id, "STRING", &argv[idx]);
1600 } else if (!strcmp(type, "NONE")) {
1603 argv[idx] = strsave("NONE");
1607 argv[idx] = strsave("???");
1609 if (status && status != MR_NO_MATCH)
1612 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1613 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1614 strcpy(argv[6], UNIQUE_GID);
1618 (*action)(q->vcnt, argv, actarg);
1620 /* free saved data */
1621 for (i = 0; i < q->vcnt; i++)
1627 return (MR_SUCCESS);
1631 /* followup_gqot: Fix the entity name, directory name & modby fields
1632 * argv[0] = filsys_id
1634 * argv[2] = entity_id
1635 * argv[3] = ascii(quota)
1638 followup_gqot(q, sq, v, action, actarg, cl)
1640 register struct save_queue *sq;
1642 register int (*action)();
1643 register int actarg;
1647 char **argv, *malloc();
1648 EXEC SQL BEGIN DECLARE SECTION;
1651 EXEC SQL END DECLARE SECTION;
1654 if (!strcmp(q->name, "get_quota") ||
1655 !strcmp(q->name, "get_quota_by_filesys"))
1659 while (sq_get_data(sq, &argv)) {
1661 switch (argv[1][0]) {
1663 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1667 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1671 argv[2] = strsave("system:anyuser");
1675 argv[2] = malloc(8);
1676 sprintf(argv[2], "%d", id);
1679 id = atoi(argv[idx]);
1681 argv[idx] = malloc(256);
1685 EXEC SQL REPEATED SELECT name INTO :name FROM filesys
1686 WHERE label = :label;
1688 EXEC SQL REPEATED SELECT dir INTO :name FROM nfsphys
1689 WHERE nfsphys_id = :id;
1691 if (sqlca.sqlerrd[2] != 1) {
1692 sprintf(argv[idx], "#%d", id);
1695 id = atoi(argv[idx+3]);
1697 status = id_to_name(id, "USER", &argv[idx+3]);
1699 status = id_to_name(-id, "STRING", &argv[idx+3]);
1700 if (status && status != MR_NO_MATCH)
1702 (*action)(q->vcnt, argv, actarg);
1703 for (j = 0; j < q->vcnt; j++)
1712 /* followup_aqot: Add allocation to nfsphys after creating quota.
1713 * argv[0] = filsys_id
1714 * argv[1] = type if "add_quota" or "update_quota"
1716 * argv[3 or 2] = ascii(quota)
1719 followup_aqot(q, argv, cl)
1724 EXEC SQL BEGIN DECLARE SECTION;
1725 int quota, id, fs, who;
1726 char *entity, *qtype;
1727 EXEC SQL END DECLARE SECTION;
1729 fs = *(int *)argv[0];
1730 if (!strcmp(q->name, "add_quota") || !strcmp(q->name, "update_quota")) {
1732 id = *(int *)argv[2];
1733 quota = atoi(argv[3]);
1736 id = *(int *)argv[1];
1737 quota = atoi(argv[2]);
1739 who = cl->client_id;
1740 entity = cl->entity;
1742 EXEC SQL REPEATED UPDATE quota
1743 SET modtime = 'now', modby = :who, modwith = :entity
1744 WHERE filsys_id = :fs and type = :qtype and entity_id = :id;
1745 EXEC SQL REPEATED UPDATE nfsphys
1746 SET allocated = allocated + :quota
1747 WHERE nfsphys_id = filesys.phys_id AND filesys.filsys_id = :fs;
1748 if (ingres_errno) return(mr_errcode);
1753 followup_gpce(q, sq, v, action, actarg, cl)
1755 register struct save_queue *sq;
1757 register int (*action)();
1758 register int actarg;
1762 char **argv, *malloc();
1766 while (sq_get_data(sq, &argv)) {
1767 id = atoi(argv[PCAP_QSERVER]);
1768 status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
1769 if (status) return (status);
1772 status = id_to_name(id, "USER", &argv[i]);
1774 status = id_to_name(-id, "STRING", &argv[i]);
1775 if (status && status != MR_NO_MATCH)
1777 (*action)(q->vcnt, argv, actarg);
1778 for (j = 0; j < q->vcnt; j++)
1790 followup_gzcl(q, sq, v, action, actarg, cl)
1791 register struct query *q;
1792 register struct save_queue *sq;
1793 register struct validate *v;
1794 register int (*action)();
1801 while (sq_get_data(sq, &argv)) {
1802 mr_trim_args(q->vcnt, argv);
1804 id = atoi(argv[i = q->vcnt - 2]);
1806 status = id_to_name(id, "USER", &argv[i]);
1808 status = id_to_name(-id, "STRING", &argv[i]);
1809 if (status && status != MR_NO_MATCH)
1812 for (i = 1; i < 8; i+=2) {
1813 id = atoi(argv[i+1]);
1814 if (!strcmp(argv[i], "LIST")) {
1815 status = id_to_name(id, "LIST", &argv[i+1]);
1816 } else if (!strcmp(argv[i], "USER")) {
1817 status = id_to_name(id, "USER", &argv[i+1]);
1818 } else if (!strcmp(argv[i], "KERBEROS")) {
1819 status = id_to_name(id, "STRING", &argv[i+1]);
1820 } else if (!strcmp(argv[i], "NONE")) {
1823 argv[i+1] = strsave("NONE");
1827 argv[i+1] = strsave("???");
1829 if (status && status != MR_NO_MATCH)
1834 (*action)(q->vcnt, argv, actarg);
1836 /* free saved data */
1837 for (i = 0; i < q->vcnt; i++)
1849 followup_gsha(q, sq, v, action, actarg, cl)
1850 register struct query *q;
1851 register struct save_queue *sq;
1852 register struct validate *v;
1853 register int (*action)();
1860 while (sq_get_data(sq, &argv)) {
1861 mr_trim_args(q->vcnt, argv);
1865 status = id_to_name(id, "USER", &argv[4]);
1867 status = id_to_name(-id, "STRING", &argv[4]);
1868 if (status && status != MR_NO_MATCH)
1872 if (!strcmp(argv[1], "LIST")) {
1873 status = id_to_name(id, "LIST", &argv[2]);
1874 } else if (!strcmp(argv[1], "USER")) {
1875 status = id_to_name(id, "USER", &argv[2]);
1876 } else if (!strcmp(argv[1], "KERBEROS")) {
1877 status = id_to_name(id, "STRING", &argv[2]);
1878 } else if (!strcmp(argv[1], "NONE")) {
1881 argv[2] = strsave("NONE");
1885 argv[2] = strsave("???");
1887 if (status && status != MR_NO_MATCH)
1891 (*action)(q->vcnt, argv, actarg);
1893 /* free saved data */
1894 for (i = 0; i < q->vcnt; i++)
1904 /* Special query routines */
1906 /* set_pobox - this does all of the real work.
1907 * argv = user_id, type, box
1908 * if type is POP, then box should be a machine, and its ID should be put in
1909 * pop_id. If type is SMTP, then box should be a string and its ID should
1910 * be put in box_id. If type is NONE, then box doesn't matter.
1913 int set_pobox(q, argv, cl)
1918 EXEC SQL BEGIN DECLARE SECTION;
1920 char *box, potype[9];
1921 EXEC SQL END DECLARE SECTION;
1925 user = *(int *)argv[0];
1927 EXEC SQL REPEATED SELECT pop_id, potype INTO :id, :potype FROM users
1928 WHERE users_id = :user;
1929 if (ingres_errno) return(mr_errcode);
1930 if (!strcmp(strtrim(potype), "POP"))
1931 set_pop_usage(id, -1);
1933 if (!strcmp(argv[1], "POP")) {
1934 status = name_to_id(box, "MACHINE", &id);
1935 if (status == MR_NO_MATCH)
1939 EXEC SQL REPEATED UPDATE users SET potype = 'POP', pop_id = :id
1940 WHERE users_id = :user;
1941 set_pop_usage(id, 1);
1942 } else if (!strcmp(argv[1], "SMTP")) {
1943 if (index(box, '/') || index(box, '|'))
1944 return(MR_BAD_CHAR);
1945 status = name_to_id(box, "STRING", &id);
1946 if (status == MR_NO_MATCH) {
1947 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
1948 WHERE name='strings_id';
1950 EXEC SQL REPEATED UPDATE numvalues SET value = :id
1951 WHERE name='strings_id';
1952 EXEC SQL INSERT INTO strings (string_id, string)
1956 EXEC SQL REPEATED UPDATE users SET potype='SMTP', box_id = :id
1957 WHERE users_id = :user;
1958 } else /* argv[1] == "NONE" */ {
1959 EXEC SQL REPEATED UPDATE users SET potype='NONE'
1960 WHERE users_id = :user;
1963 set_pobox_modtime(q, argv, cl);
1964 EXEC SQL REPEATED UPDATE tblstats SET updates = updates+1, modtime='now'
1965 WHERE tblstats.table_name='users';
1966 if (ingres_errno) return(mr_errcode);
1971 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1972 * each list. This is tricky: first build a queue of all requested
1973 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1976 get_list_info(q, aargv, cl, action, actarg)
1977 register struct query *q;
1980 register int (*action)();
1983 char *argv[13], *malloc(), *realloc();
1984 EXEC SQL BEGIN DECLARE SECTION;
1985 char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
1986 char maillist[5], grouplist[5], gid_str[6], acl_name[256], desc[256];
1987 char modtime[27], modby[256], modwith[9];
1988 int id, rowcount, acl_id, hid, modby_id;
1989 EXEC SQL END DECLARE SECTION;
1990 int returned, status;
1991 struct save_queue *sq, *sq_create();
1993 returned = rowcount = 0;
1997 EXEC SQL DECLARE csr102 CURSOR FOR SELECT list_id FROM list
1999 EXEC SQL OPEN csr102;
2002 EXEC SQL FETCH csr102 INTO :id;
2003 if(sqlca.sqlcode!=0) break;
2004 sq_save_data(sq, id);
2007 EXEC SQL CLOSE csr102;
2009 if (ingres_errno) return(mr_errcode);
2011 return(MR_NO_MATCH);
2013 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
2014 argv[4] = maillist; argv[5] = grouplist; argv[6] = gid_str;
2015 argv[7] = acl_type; argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
2017 while (sq_get_data(sq, &id)) {
2022 * repeat retrieve (listname = l.#name, active = text(l.#active),
2023 * public = text(l.#public), hidden = text(l.#hidden),
2024 * hid = l.#hidden, maillist = text(l.#maillist),
2025 * group = text(l.#group), gid = text(l.#gid),
2026 * acl_type = trim(l.#acl_type), acl_id = l.#acl_id,
2027 * desc = l.#desc, modtime = l.#modtime, modby_id = l.#modby,
2028 * modwith =l.#modwith)
2029 * where l.list_id = :id
2031 /** Won't the TRIM() die a horrible INGRES death? **/
2032 EXEC SQL REPEATED SELECT name, CHAR(active), CHAR(publicflg),
2033 CHAR(hidden), hidden, CHAR(maillist), CHAR(grouplist), CHAR(gid),
2034 TRIM(acl_type), acl_id, description, CHAR(modtime), modby, modwith
2035 INTO :listname, :active, :public, :hidden, :hid, :maillist,
2036 :grouplist, :gid_str, :acl_type, :acl_id, :desc,
2037 :modtime, :modby_id, :modwith
2038 FROM list WHERE list_id = :id;
2040 if (ingres_errno) return(mr_errcode);
2042 if (atoi(gid_str) == -1)
2043 argv[6] = UNIQUE_GID;
2045 argv[8] = malloc(0);
2046 if (!strcmp(acl_type, "LIST")) {
2047 status = id_to_name(acl_id, "LIST", &argv[8]);
2048 } else if (!strcmp(acl_type, "USER")) {
2049 status = id_to_name(acl_id, "USER", &argv[8]);
2050 } else if (!strcmp(acl_type, "KERBEROS")) {
2051 status = id_to_name(acl_id, "STRING", &argv[8]);
2052 } else if (!strcmp(acl_type, "NONE")) {
2055 argv[8] = strsave("NONE");
2059 argv[8] = strsave("???");
2061 if (status && status != MR_NO_MATCH) return(status);
2063 argv[11] = malloc(0);
2065 status = id_to_name(modby_id, "USER", &argv[11]);
2067 status = id_to_name(-modby_id, "STRING", &argv[11]);
2068 if (status && status != MR_NO_MATCH) return(status);
2070 mr_trim_args(q->vcnt, argv);
2072 (*action)(q->vcnt, argv, actarg);
2078 if (ingres_errno) return(mr_errcode);
2079 return (MR_SUCCESS);
2083 /* Add_member_to_list: do list flattening as we go! MAXLISTDEPTH is
2084 * how many different ancestors a member is allowed to have.
2087 #define MAXLISTDEPTH 1024
2089 int add_member_to_list(q, argv, cl)
2094 EXEC SQL BEGIN DECLARE SECTION;
2095 int id, lid, mid, error, who, ref;
2096 char *mtype, dtype[9], *entity;
2097 EXEC SQL END DECLARE SECTION;
2098 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2099 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2101 char *dtypes[MAXLISTDEPTH];
2102 char *iargv[3], *buf;
2104 lid = *(int *)argv[0];
2106 mid = *(int *)argv[2];
2107 /* if the member is already a direct member of the list, punt */
2109 * repeat retrieve (exists = any(m.list_id where m.list_id=@lid and
2110 * m.member_id = :mid and m.member_type = :mtype
2111 * and m.direct = 1))
2113 EXEC SQL REPEATED SELECT list_id INTO :idummy FROM imembers
2114 WHERE list_id = :lid AND member_id = :mid
2115 AND member_type = :mtype AND direct = 1;
2116 if (sqlca.sqlerrd[2] > 0)
2118 if (!strcasecmp(mtype, "STRING")) {
2120 status = id_to_name(mid, "STRING", &buf);
2121 if (status) return(status);
2122 if (index(buf, '/') || index(buf, '|')) {
2124 return(MR_BAD_CHAR);
2132 EXEC SQL DECLARE csr103 CURSOR FOR
2133 SELECT list_id, ref_count FROM imembers
2134 WHERE member_id = :lid AND member_type='LIST';
2135 EXEC SQL OPEN csr103;
2137 EXEC SQL FETCH csr103 INTO :id, :ref;
2138 if(sqlca.sqlcode != 0) break;
2140 ancestors[acount++] = id;
2141 if (acount >= MAXLISTDEPTH) break;
2143 EXEC SQL CLOSE csr103;
2144 if (ingres_errno) return(mr_errcode);
2145 if (acount >= MAXLISTDEPTH) {
2146 return(MR_INTERNAL);
2148 descendants[0] = mid;
2153 if (!strcmp(mtype, "LIST")) {
2154 EXEC SQL DECLARE csr104 CURSOR FOR
2155 SELECT member_id, member_type, ref_count
2157 WHERE list_id = :mid;
2158 EXEC SQL OPEN csr104;
2160 EXEC SQL FETCH csr104 INTO :id, :dtype, :ref;
2161 if(sqlca.sqlcode != 0) break;
2164 dtypes[dcount] = "LIST";
2167 dtypes[dcount] = "USER";
2170 dtypes[dcount] = "STRING";
2173 dtypes[dcount] = "KERBEROS";
2180 descendants[dcount++] = id;
2181 if (dcount >= MAXLISTDEPTH) {
2186 EXEC SQL CLOSE csr104;
2187 if (ingres_errno) return(mr_errcode);
2189 return(MR_INTERNAL);
2191 for (a = 0; a < acount; a++) {
2193 for (d = 0; d < dcount; d++) {
2194 mid = descendants[d];
2196 if (mid == lid && !strcmp(mtype, "LIST")) {
2197 return(MR_LISTLOOP);
2200 * repeat retrieve (exists = any(m.ref_count where m.list_id = :lid
2201 * and m.member_id = :mid
2202 * and m.member_type = :mtype))
2204 EXEC SQL REPEATED SELECT ref_count INTO :idummy FROM imembers
2205 WHERE list_id = :lid AND member_id = :mid
2206 AND m.member_type = :mtype;
2207 ref = aref[a] * dref[d];
2208 if (sqlca.sqlerrd[2] > 0) {
2209 if (a == 0 && d == 0) {
2210 EXEC SQL UPDATE imembers
2211 SET ref_count = ref_count+ref, direct=1
2212 WHERE list_id = :lid AND member_id = :mid
2213 AND member_type = :mtype;
2215 EXEC SQL UPDATE imembers
2216 SET ref_count = ref_count+ref
2217 WHERE list_id = :lid AND member_id = :mid
2218 AND member_type = :mtype;
2221 incremental_clear_before();
2222 if (a == 0 && d == 0) {
2223 EXEC SQL INSERT INTO imembers
2224 (list_id, member_id, direct, member_type, ref_count)
2225 VALUES (:lid, :mid, 1, :mtype, 1);
2227 EXEC SQL INSERT INTO imembers
2228 (list_id, member_id, member_type, ref_count)
2229 VALUES (:lid, :mid, :mtype, 1);
2231 iargv[0] = (char *)lid;
2233 iargv[2] = (char *)mid;
2234 incremental_after("members", 0, iargv);
2238 lid = *(int *)argv[0];
2239 entity = cl->entity;
2240 who = cl->client_id;
2241 EXEC SQL REPEATED UPDATE list
2242 SET modtime='now', modby = :who, modwith = :entity
2243 WHERE list_id = :lid;
2244 if (ingres_errno) return(mr_errcode);
2249 /* Delete_member_from_list: do list flattening as we go!
2252 int delete_member_from_list(q, argv, cl)
2257 EXEC SQL BEGIN DECLARE SECTION;
2258 int id, lid, mid, cnt, error, who, ref;
2259 char *mtype, dtype[9], *entity;
2260 EXEC SQL END DECLARE SECTION;
2261 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2262 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2263 char *dtypes[MAXLISTDEPTH];
2266 lid = *(int *)argv[0];
2268 mid = *(int *)argv[2];
2269 /* if the member is not a direct member of the list, punt */
2271 * repeat retrieve (exists = any(m.list_id where m.list_id=@lid and
2272 * m.member_id = :mid and m.member_type = :mtype
2273 * and m.direct = 1))
2275 EXEC SQL REPEATED SELECT list_id INTO :idummy FROM imembers
2276 WHERE list_id = :lid AND member_id = :mid
2277 AND member_type = :mtype AND direct = 1;
2278 if (ingres_errno) return(mr_errcode);
2279 if (sqlca.sqlcode == 100)
2280 return(MR_NO_MATCH);
2284 EXEC SQL DECLARE csr105 CURSOR FOR
2285 SELECT list_id, ref_count FROM imembers
2286 WHERE member_id = :lid AND member_type = 'LIST';
2287 EXEC SQL OPEN csr105;
2289 EXEC SQL FETCH csr105 INTO :id, :ref;
2290 if(sqlca.sqlcode!=0) break;
2292 ancestors[acount++] = id;
2293 if (acount >= MAXLISTDEPTH) break;
2295 EXEC SQL CLOSE csr105;
2298 if (acount >= MAXLISTDEPTH)
2299 return(MR_INTERNAL);
2300 descendants[0] = mid;
2305 if (!strcmp(mtype, "LIST")) {
2306 EXEC SQL DECLARE csr106 CURSOR FOR
2307 SELECT member_id, member_type, ref_count FROM imembers
2308 WHERE list_id = :mid;
2309 EXEC SQL OPEN csr106;
2311 EXEC SQL FETCH csr106 INTO :id, :dtype, :ref;
2312 if(sqlca.sqlcode!=0) break;
2315 dtypes[dcount] = "LIST";
2318 dtypes[dcount] = "USER";
2321 dtypes[dcount] = "STRING";
2324 dtypes[dcount] = "KERBEROS";
2331 descendants[dcount++] = id;
2332 if (dcount >= MAXLISTDEPTH) break;
2334 EXEC SQL CLOSE csr106;
2338 return(MR_INTERNAL);
2340 for (a = 0; a < acount; a++) {
2342 for (d = 0; d < dcount; d++) {
2343 mid = descendants[d];
2345 if (mid == lid && !strcmp(mtype, "LIST")) {
2346 return(MR_LISTLOOP);
2348 EXEC SQL REPEATED SELECT ref_count INTO :cnt FROM imembers
2349 WHERE list_id = :lid AND member_id = :mid AND member_type = :mtype;
2350 ref = aref[a] * dref[d];
2352 iargv[0] = (char *)lid;
2354 iargv[2] = (char *)mid;
2355 incremental_before("members", 0, iargv);
2356 EXEC SQL DELETE FROM imembers
2357 WHERE list_id = :lid AND member_id = :mid
2358 AND member_type= :mtype;
2359 incremental_clear_after();
2360 } else if (a == 0 && d == 0) {
2361 EXEC SQL UPDATE imembers
2362 SET ref_count = refcount - :ref, direct = 0
2363 WHERE list_id = :lid AND member_id = :mid
2364 AND member_type = :mtype;
2366 EXEC SQL UPDATE imembers
2367 SET ref_count=refcount-:ref
2368 WHERE list_id = :lid AND member_id = :mid
2369 AND member_type = :mtype;
2373 lid = *(int *)argv[0];
2374 entity = cl->entity;
2375 who = cl->client_id;
2376 EXEC SQL UPDATE list SET modtime = 'now', modby = :who, modwith = :entity
2377 WHERE list_id = :lid;
2378 if (ingres_errno) return(mr_errcode);
2383 /* get_ace_use - given a type and a name, return a type and a name.
2384 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2385 * and argv[1] will contain the ID of the entity in question. The R*
2386 * types mean to recursively look at every containing list, not just
2387 * when the object in question is a direct member. On return, the
2388 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2391 int get_ace_use(q, argv, cl, action, actarg)
2399 EXEC SQL BEGIN DECLARE SECTION;
2401 int aid, listid, id;
2402 EXEC SQL END DECLARE SECTION;
2403 struct save_queue *sq, *sq_create();
2406 aid = *(int *)argv[1];
2407 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2408 !strcmp(atype, "KERBEROS")) {
2409 return(get_ace_internal(atype, aid, action, actarg));
2413 if (!strcmp(atype, "RLIST")) {
2414 sq_save_data(sq, aid);
2415 /* get all the list_id's of containing lists */
2416 EXEC SQL DECLARE csr107 CURSOR FOR
2417 SELECT list_id FROM imembers
2418 WHERE member_type='LIST' AND member_id = :aid;
2419 EXEC SQL OPEN csr107;
2421 EXEC SQL FETCH csr107 INTO :listid;
2422 if(sqlca.sqlcode != 0) break;
2423 sq_save_unique_data(sq, listid);
2425 EXEC SQL CLOSE csr107;
2426 /* now process each one */
2427 while (sq_get_data(sq, &id)) {
2428 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2433 if (!strcmp(atype, "RUSER")) {
2434 EXEC SQL DECLARE csr108 CURSOR FOR
2435 SELECT list_id FROM imembers
2436 WHERE member_type='USER' AND member_id = :aid;
2437 EXEC SQL OPEN csr108;
2439 EXEC SQL FETCH csr108 INTO :listid;
2440 if(sqlca.sqlcode != 0) break;
2441 sq_save_data(sq, listid);
2443 EXEC SQL CLOSE csr108;
2444 /* now process each one */
2445 while (sq_get_data(sq, &id)) {
2446 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2449 if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2453 if (!strcmp(atype, "RKERBERO")) {
2454 EXEC SQL DECLARE csr109 CURSOR FOR
2455 SELECT list_id FROM imembers
2456 WHERE member_type='KERBEROS' AND member_id = :aid;
2457 EXEC SQL OPEN csr109;
2459 EXEC SQL FETCH csr109 INTO :listid;
2460 if(sqlca.sqlcode != 0) break;
2461 sq_save_data(sq, listid);
2463 EXEC SQL CLOSE csr109;
2464 /* now process each one */
2465 while (sq_get_data(sq, &id)) {
2466 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2469 if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2474 if (ingres_errno) return(mr_errcode);
2475 if (!found) return(MR_NO_MATCH);
2480 /* This looks up a single list or user for ace use. atype must be "USER"
2481 * or "LIST", and aid is the ID of the corresponding object. This is used
2482 * by get_ace_use above.
2485 get_ace_internal(atype, aid, action, actarg)
2486 EXEC SQL BEGIN DECLARE SECTION;
2489 EXEC SQL END DECLARE SECTION;
2495 EXEC SQL BEGIN DECLARE SECTION;
2497 EXEC SQL END DECLARE SECTION;
2500 if (!strcmp(atype, "LIST")) {
2501 rargv[0] = "FILESYS";
2502 EXEC SQL DECLARE csr110 CURSOR FOR
2503 SELECT label FROM filesys
2504 WHERE owners = :aid;
2505 EXEC SQL OPEN csr110;
2507 EXEC SQL FETCH csr110 INTO :name;
2508 if(sqlca.sqlcode != 0) break;
2509 (*action)(2, rargv, actarg);
2512 EXEC SQL CLOSE csr110;
2515 EXEC SQL DECLARE csr111 CURSOR FOR
2516 SELECT capability FROM capacls
2517 WHERE list_id = :aid ;
2518 EXEC SQL OPEN csr111;
2520 EXEC SQL FETCH csr111 INTO :name ;
2521 if(sqlca.sqlcode != 0) break;
2522 (*action)(2, rargv, actarg);
2525 EXEC SQL CLOSE csr111;
2526 } else if (!strcmp(atype, "USER")) {
2527 rargv[0] = "FILESYS";
2528 EXEC SQL DECLARE csr112 CURSOR FOR
2529 SELECT label FROM filesys
2531 EXEC SQL OPEN csr112;
2533 EXEC SQL FETCH csr112 INTO :name ;
2534 if(sqlca.sqlcode != 0) break;
2535 (*action)(2, rargv, actarg);
2538 EXEC SQL CLOSE csr112;
2542 EXEC SQL DECLARE csr113 CURSOR FOR
2543 SELECT name FROM list
2544 WHERE acl_type = :atype AND acl_id = :aid;
2545 EXEC SQL OPEN csr113;
2547 EXEC SQL FETCH csr113 INTO :name;
2548 if(sqlca.sqlcode != 0) break;
2549 (*action)(2, rargv, actarg);
2552 EXEC SQL CLOSE csr113;
2554 rargv[0] = "SERVICE";
2555 EXEC SQL DECLARE csr114 CURSOR FOR
2556 SELECT name FROM servers
2557 WHERE acl_type = :atype AND acl_id = :aid;
2558 EXEC SQL OPEN csr114;
2560 EXEC SQL FETCH csr114 INTO :name;
2561 if(sqlca.sqlcode != 0) break;
2562 (*action)(2, rargv, actarg);
2565 EXEC SQL CLOSE csr114;
2567 rargv[0] = "HOSTACCESS";
2568 EXEC SQL DECLARE csr115 CURSOR FOR
2569 SELECT name FROM machine, hostaccess
2570 WHERE mach_id = hostaccess.mach_id AND hostaccess.acl_type = :atype
2571 AND hostaccess.acl_id = :aid;
2572 EXEC SQL OPEN csr115;
2574 EXEC SQL FETCH csr115 INTO :name;
2575 if(sqlca.sqlcode != 0) break;
2576 (*action)(2, rargv, actarg);
2579 EXEC SQL CLOSE csr115;
2581 rargv[0] = "ZEPHYR";
2582 EXEC SQL DECLARE csr116 CURSOR FOR
2583 SELECT class FROM zephyr
2584 WHERE zephyr.xmt_type = :atype AND zephyr.xmt_id = :aid
2585 OR zephyr.sub_type = :atype AND zephyr.sub_id = :aid
2586 OR zephyr.iws_type = :atype AND zephyr.iws_id = :aid
2587 OR zephyr.iui_type = :atype AND zephyr.iui_id = :aid;
2588 EXEC SQL OPEN csr116;
2590 EXEC SQL FETCH csr116 INTO :name;
2591 if(sqlca.sqlcode != 0) break;
2592 (*action)(2, rargv, actarg);
2595 EXEC SQL CLOSE csr116;
2597 if (!found) return(MR_NO_MATCH);
2602 /* get_lists_of_member - given a type and a name, return the name and flags
2603 * of all of the lists of the given member. The member_type is one of
2604 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2605 * and argv[1] will contain the ID of the entity in question. The R*
2606 * types mean to recursively look at every containing list, not just
2607 * when the object in question is a direct member.
2610 int get_lists_of_member(q, argv, cl, action, actarg)
2617 int found = 0, direct = 1;
2619 EXEC SQL BEGIN DECLARE SECTION;
2621 int aid, listid, id;
2622 char name[33], active[5], public[5], hidden[5], maillist[5], grouplist[5];
2623 EXEC SQL END DECLARE SECTION;
2626 aid = *(int *)argv[1];
2627 if (!strcmp(atype, "RLIST")) {
2631 if (!strcmp(atype, "RUSER")) {
2635 if (!strcmp(atype, "RSTRING")) {
2639 if (!strcmp(atype, "RKERBEROS")) {
2648 rargv[4] = maillist;
2649 rargv[5] = grouplist;
2652 * repeat retrieve (name = list.#name, active = text(list.#active),
2653 * public = text(list.#public), hidden = text(list.#hidden),
2654 * maillist = text(list.#maillist), group = text(list.#group))
2655 * where list.list_id = m.list_id and m.direct = 1 and
2656 * m.member_type = :atype and m.member_id = :aid
2658 EXEC SQL DECLARE csr117a CURSOR FOR
2659 SELECT name, CHAR(active), CHAR(publicflg), CHAR(hidden),
2660 CHAR(maillist), CHAR(grouplist)
2661 FROM list l, imembers m
2662 WHERE l.list_id = m.list_id AND m.direct = 1
2663 AND m.member_type = :atype AND m.member_id = :aid;
2664 EXEC SQL OPEN csr117a;
2666 EXEC SQL FETCH csr117a
2667 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2668 if(sqlca.sqlcode != 0) break;
2669 (*action)(6, rargv, actarg);
2672 EXEC SQL CLOSE csr117a;
2674 EXEC SQL DECLARE csr117b CURSOR FOR
2675 SELECT name, CHAR(active), CHAR(publicflg), CHAR(hidden),
2676 CHAR(maillist), CHAR(grouplist)
2677 FROM list l, imembers m
2678 WHERE l.list_id = m.list_id
2679 AND m.member_type = :atype AND m.member_id = :aid;
2680 EXEC SQL OPEN csr117b;
2682 EXEC SQL FETCH csr117b
2683 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2684 if(sqlca.sqlcode != 0) break;
2685 (*action)(6, rargv, actarg);
2688 EXEC SQL CLOSE csr117b;
2691 if (ingres_errno) return(mr_errcode);
2692 if (!found) return(MR_NO_MATCH);
2697 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2698 * the five flags associated with each list. It will return the name of
2699 * each list that meets the quailifications. It does this by building a
2700 * where clause based on the arguments, then doing a retrieve.
2703 static char *lflags[5] = { "active", "publicflg", "hidden", "maillist", "group" };
2705 int qualified_get_lists(q, argv, cl, action, actarg)
2712 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2713 "l", "name", lflags));
2717 /** get_members_of_list - optimized query for retrieval of list members
2720 ** argv[0] - list_id
2723 ** - retrieve USER members, then LIST members, then STRING members
2726 get_members_of_list(q, argv, cl, action, actarg)
2733 EXEC SQL BEGIN DECLARE SECTION;
2734 int list_id, member_id;
2735 char member_name[129], member_type[9];
2736 EXEC SQL END DECLARE SECTION;
2739 struct save_queue *sq;
2741 list_id = *(int *)argv[0];
2745 EXEC SQL DECLARE csr118 CURSOR FOR
2746 SELECT member_type, member_id FROM imembers
2747 WHERE list_id = :list_id AND direct=1;
2748 EXEC SQL OPEN csr118;
2750 EXEC SQL FETCH csr118 INTO :member_type, :member_id;
2751 if (sqlca.sqlcode != 0) break;
2754 sq_save_data(sq, ((int)member_type[0] << 24) | (member_id & 0xffffff));
2756 EXEC SQL CLOSE csr118;
2758 if (members <= 49) {
2759 targv[1] = malloc(0);
2760 while (sq_remove_data(sq, &member_id)) {
2761 switch (member_id >> 24) {
2764 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
2765 (*action)(2, targv, actarg);
2769 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
2770 (*action)(2, targv, actarg);
2773 targv[0] = "STRING";
2774 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2775 (*action)(2, targv, actarg);
2778 targv[0] = "KERBEROS";
2779 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2780 (*action)(2, targv, actarg);
2784 return(MR_INTERNAL);
2793 targv[1] = member_name;
2795 EXEC SQL DECLARE csr119 CURSOR FOR
2796 SELECT users.login FROM users, imembers
2797 WHERE imembers.list_id = :list_id AND imembers.member_type = 'USER'
2798 AND imembers.member_id = users.users_id AND imembers.direct=1
2800 EXEC SQL OPEN csr119;
2802 EXEC SQL FETCH csr119 INTO :member_name;
2803 if(sqlca.sqlcode != 0) break;
2804 (*action)(2, targv, actarg);
2806 EXEC SQL CLOSE csr119;
2807 if (ingres_errno) return(mr_errcode);
2810 EXEC SQL DECLARE csr120 CURSOR FOR
2811 SELECT list.name FROM list, imembers
2812 WHERE imembers.list_id = :list_id AND imembers.member_type='LIST'
2813 AND imembers.member_id = list.list_id AND imembers.direct=1
2815 EXEC SQL OPEN csr120;
2817 EXEC SQL FETCH csr120 INTO :member_name;
2818 if(sqlca.sqlcode != 0) break;
2819 (*action)(2, targv, actarg);
2821 EXEC SQL CLOSE csr120;
2822 if (ingres_errno) return(mr_errcode);
2824 targv[0] = "STRING";
2825 EXEC SQL DECLARE csr121 CURSOR FOR
2826 SELECT strings.string FROM strings, imembers
2827 WHERE imembers.list_id = :list_id AND imembers.member_type='STRING'
2828 AND imembers.member_id = strings.string_id AND imembers.direct=1
2830 EXEC SQL OPEN csr121;
2832 EXEC SQL FETCH csr121 INTO :member_name;
2833 if(sqlca.sqlcode != 0) break;
2834 (*action)(2, targv, actarg);
2836 EXEC SQL CLOSE csr121;
2837 if (ingres_errno) return(mr_errcode);
2839 targv[0] = "KERBEROS";
2840 EXEC SQL DECLARE csr122 CURSOR FOR
2841 SELECT strings.string FROM strings, imembers
2842 WHERE imembers.list_id = :list_id AND imembers.member_type='KERBEROS'
2843 AND imembers.member_id = strings.string_id AND imembers.direct=1
2845 EXEC SQL OPEN csr122;
2847 EXEC SQL FETCH csr122 INTO :member_name;
2848 if(sqlca.sqlcode != 0) break;
2849 (*action)(2, targv, actarg);
2851 EXEC SQL CLOSE csr122;
2852 if (ingres_errno) return(mr_errcode);
2858 /* count_members_of_list: this is a simple query, but it cannot be done
2859 * through the dispatch table.
2862 int count_members_of_list(q, argv, cl, action, actarg)
2869 EXEC SQL BEGIN DECLARE SECTION;
2871 EXEC SQL END DECLARE SECTION;
2872 char *rargv[1], countbuf[5];
2874 list = *(int *)argv[0];
2875 rargv[0] = countbuf;
2876 EXEC SQL REPEATED SELECT count (*) INTO :ct FROM imembers
2877 WHERE list_id = :list AND direct=1;
2878 if (ingres_errno) return(mr_errcode);
2879 sprintf(countbuf, "%d", ct);
2880 (*action)(1, rargv, actarg);
2885 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2886 * the three flags associated with each service. It will return the name of
2887 * each service that meets the quailifications. It does this by building a
2888 * where clause based on the arguments, then doing a retrieve.
2891 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2893 int qualified_get_server(q, argv, cl, action, actarg)
2900 return(qualified_get(q, argv, action, actarg, "s.name != ''",
2901 "s", "name", sflags));
2905 /* generic qualified get routine, used by qualified_get_lists,
2906 * qualified_get_server, and qualified_get_serverhost.
2908 * start - a simple where clause, must not be empty
2909 * range - the name of the range variable
2910 * field - the field to return
2911 * flags - an array of strings, names of the flag variables
2914 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2924 char name[33], qual[256];
2926 char *rargv[1], buf[32];
2928 strcpy(qual, start);
2929 for (i = 0; i < q->argc; i++) {
2930 if (!strcmp(argv[i], "TRUE")) {
2931 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2932 (void) strcat(qual, buf);
2933 } else if (!strcmp(argv[i], "FALSE")) {
2934 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2935 (void) strcat(qual, buf);
2939 rargv[0] = SQLDA->sqlvar[0].sqldata;
2940 sprintf(stmt_buf,"SELECT %s.%s FROM %s %s WHERE %s",q->rtable,field,q->rtable,q->rvar,qual);
2941 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
2942 if((mr_errcode=mr_check_SQLDA(SQLDA)) != MR_SUCCESS)
2944 EXEC SQL DECLARE csr123 CURSOR FOR stmt;
2945 EXEC SQL OPEN csr123;
2947 EXEC SQL FETCH csr123 USING DESCRIPTOR :SQLDA;
2948 if(sqlca.sqlcode != 0) break;
2950 (*action)(1, rargv, actarg);
2952 EXEC SQL CLOSE csr123;
2953 if (ingres_errno) return(mr_errcode);
2955 return(MR_NO_MATCH);
2960 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2961 * the five flags associated with each serverhost. It will return the name of
2962 * each service and host that meets the quailifications. It does this by
2963 * building a where clause based on the arguments, then doing a retrieve.
2966 static char *shflags[6] = { "service", "enable", "override", "success",
2967 "inprogress", "hosterror" };
2969 int qualified_get_serverhost(q, argv, cl, action, actarg)
2976 EXEC SQL BEGIN DECLARE SECTION;
2977 char sname[33], mname[33], qual[256];
2978 EXEC SQL END DECLARE SECTION;
2979 char *rargv[2], buf[32];
2982 /** the uppercase() function is INGRES-specific */
2983 sprintf(qual, "machine.mach_id = serverhosts.mach_id AND \
2984 serverhosts.service = uppercase('%s')",
2986 for (i = 1; i < q->argc; i++) {
2987 if (!strcmp(argv[i], "TRUE")) {
2988 sprintf(buf, " AND serverhosts.%s != 0", shflags[i]);
2990 } else if (!strcmp(argv[i], "FALSE")) {
2991 sprintf(buf, " AND serverhosts.%s = 0", shflags[i]);
2998 EXEC SQL DECLARE csr124 CURSOR FOR
2999 SELECT serverhosts.service, machine.name FROM serverhosts, machine
3001 EXEC SQL OPEN csr124;
3003 EXEC SQL FETCH csr124 INTO :sname, :mname;
3004 if(sqlca.sqlcode != 0) break;
3006 (*action)(2, rargv, actarg);
3008 EXEC SQL CLOSE csr124;
3010 if (ingres_errno) return(mr_errcode);
3012 return(MR_NO_MATCH);
3017 /* register_user - change user's login name and allocate a pobox, group,
3018 * filesystem, and quota for them. The user's status must start out as 0,
3019 * and is left as 2. Arguments are: user's UID, new login name, and user's
3020 * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY,
3021 * MR_FS_STAFF, MR_FS_MISC).
3024 register_user(q, argv, cl)
3029 EXEC SQL BEGIN DECLARE SECTION;
3030 char *login, dir[65], *entity, *directory, machname[33];
3031 int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
3032 int size, alloc, pid, m_id, ostatus, nstatus, gidval, fsidval;
3033 EXEC SQL END DECLARE SECTION;
3034 char buffer[256], *aargv[3];
3037 entity = cl->entity;
3038 who = cl->client_id;
3040 uid = atoi(argv[0]);
3042 utype = atoi(argv[2]);
3045 EXEC SQL REPEATED SELECT users_id, status INTO :users_id, :ostatus
3047 WHERE uid = :uid AND (status=0 OR status=5 OR status=6);
3049 if (sqlca.sqlerrd[2] == 0)
3050 return(MR_NO_MATCH);
3051 if (sqlca.sqlerrd[2] > 1)
3052 return(MR_NOT_UNIQUE);
3054 /* check new login name */
3055 EXEC SQL REPEATED SELECT login INTO :cdummy FROM users
3056 WHERE login = :login AND users_id != :users_id;
3057 if (ingres_errno) return(mr_errcode);
3058 if (sqlca.sqlerrd[2] > 0) return(MR_IN_USE);
3059 EXEC SQL REPEATED SELECT name INTO :cdummy FROM list
3060 WHERE name = :login;
3061 if (ingres_errno) return(mr_errcode);
3062 if (sqlca.sqlerrd[2] > 0) return(MR_IN_USE);
3063 EXEC SQL REPEATED SELECT label INTO :cdummy FROM filesys
3064 WHERE label = :login;
3065 if (ingres_errno) return(mr_errcode);
3066 if (sqlca.sqlerrd[2] > 0) return(MR_IN_USE);
3067 com_err(whoami, 0, "login name OK");
3069 /* choose place for pobox, put in mid */
3070 EXEC SQL REPEATED SELECT sh.mach_id, m.name
3071 INTO :mid, :machname FROM serverhosts sh, machine m
3072 WHERE sh.service='POP' AND sh.value2 - sh.value1 =
3073 (SELECT MAX(value2 - value1) FROM serverhosts
3074 WHERE service = 'POP');
3075 if (ingres_errno) return(mr_errcode);
3076 if (sqlca.sqlerrd[2] == 0)
3077 return(MR_NO_POBOX);
3079 /* change login name, set pobox */
3080 sprintf(buffer, "users.users_id = %d", users_id);
3081 incremental_before("users", buffer, 0);
3083 if (ostatus == 5 || ostatus == 6)
3085 EXEC SQL REPEATED UPDATE users SET login = :login, status = :nstatus,
3086 modtime='now', modby = :who, modwith = :entity, potype='POP',
3087 pop_id = :mid, pmodtime='now', pmodby = :who, pmodwith = :entity
3088 WHERE users_id = :users_id;
3090 if (ingres_errno) return(mr_errcode);
3091 if (sqlca.sqlerrd[2] != 1)
3092 return(MR_INTERNAL);
3093 set_pop_usage(mid, 1);
3094 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
3096 incremental_after("users", buffer, 0);
3098 /* create group list */
3099 if (set_next_object_id("gid", "list", 1))
3101 if (set_next_object_id("list_id", "list", 0))
3103 EXEC SQL REPEATED SELECT value INTO :list_id FROM numvalues
3104 WHERE name='list_id';
3105 if (ingres_errno) return(mr_errcode);
3106 if (sqlca.sqlerrd[2] != 1)
3107 return(MR_INTERNAL);
3108 incremental_clear_before();
3109 EXEC SQL SELECT value INTO :gidval FROM numvalues WHERE name = 'gid';
3110 EXEC SQL REPEATED INSERT INTO list
3111 (name, list_id, active, publicflg, hidden, maillist, grouplist,
3112 gid, description, acl_type, acl_id,
3113 modtime, modby, modwith)
3114 VALUES (:login, :list_id, 1, 0, 0, 0, 1,
3115 :gidval, 'User Group', 'USER', :users_id,
3116 'now', :who, :entity);
3117 if (ingres_errno) return(mr_errcode);
3118 if (sqlca.sqlerrd[2] != 1)
3119 return(MR_INTERNAL);
3120 sprintf(buffer, "l.list_id = %d", list_id);
3121 incremental_after("list", buffer, 0);
3122 aargv[0] = (char *) list_id;
3124 aargv[2] = (char *) users_id;
3125 incremental_clear_before();
3126 EXEC SQL REPEATED INSERT INTO imembers
3127 (list_id, member_type, member_id, ref_count, direct)
3128 VALUES (:list_id, 'USER', :users_id, 1, 1);
3129 if (ingres_errno) return(mr_errcode);
3130 if (sqlca.sqlerrd[2] != 1)
3131 return(MR_INTERNAL);
3132 incremental_after("members", 0, aargv);
3134 /* decide where to put filesystem */
3137 EXEC SQL DECLARE csr125 CURSOR FOR
3138 SELECT mach_id, trim(nfsphys.dir), nfsphys_id, status, size, allocated
3140 EXEC SQL OPEN csr125;
3142 EXEC SQL FETCH csr125 INTO :mid, :dir, :nid, :flag, :size, :alloc;
3143 if(sqlca.sqlcode != 0) break;
3144 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
3145 maxsize = size - alloc;
3148 directory = strsave(dir);
3153 EXEC SQL CLOSE csr125;
3154 if (ingres_errno) return(mr_errcode);
3156 return(MR_NO_FILESYS);
3158 /* create filesystem */
3159 if (set_next_object_id("filsys_id", "filesys", 0))
3161 incremental_clear_before();
3162 EXEC SQL SELECT value INTO :fsidval FROM numvalues
3163 WHERE numvalues.name='filsys_id';
3164 EXEC SQL REPEATED INSERT INTO filesys
3165 (filsys_id, phys_id, label, type, mach_id, name,
3166 mount, access, comments, owner, owners, createflg,
3167 lockertype, modtime, modby, modwith)
3169 (:fsidval, :pid, :login, 'NFS', :m_id, :directory+'/'+:login,
3170 '/mit/'+:login, 'w', 'User Locker', :users_id, :list_id, 1,
3171 'HOMEDIR', 'now', :who, :entity) ;
3172 if (ingres_errno) return(mr_errcode);
3173 if (sqlca.sqlerrd[2] != 1)
3174 return(MR_INTERNAL);
3175 incremental_after("filesys",
3176 "fs.filsys_id = numvalues.value and numvalues.name = 'filsys_id'",
3178 com_err(whoami, 0, "filesys on mach %d in %s/%s", m_id,
3182 EXEC SQL REPEATED SELECT value INTO :quota FROM numvalues
3183 WHERE name='def_quota';
3184 if (ingres_errno) return(mr_errcode);
3185 if (sqlca.sqlerrd[2] != 1)
3186 return(MR_NO_QUOTA);
3187 incremental_clear_before();
3188 EXEC SQL SELECT value INTO :fsidval FROM numvalues
3189 WHERE numvalues.name = 'filsys_id';
3190 EXEC SQL REPEATED INSERT INTO quota
3191 (entity_id, filsys_id, type, quota, phys_id, modtime, modby, modwith)
3193 (:users_id, :fsidval, 'USER', :quota, :pid, 'now', :who, :entity);
3194 if (ingres_errno) return(mr_errcode);
3195 if (sqlca.sqlerrd[2] != 1)
3196 return(MR_INTERNAL);
3197 EXEC SQL REPEATED UPDATE nfsphys SET allocated=allocated + :quota
3198 WHERE nfsphys_id = filesys.phys_id
3199 AND filesys.filsys_id = numvalues.value
3200 AND numvalues.name = 'filsys_id';
3201 if (ingres_errno) return(mr_errcode);
3202 if (sqlca.sqlerrd[2] != 1)
3203 return(MR_INTERNAL);
3207 sprintf(buffer, "q.entity_id = %d and q.filsys_id = numvalues.value and q.type = 'USER' and numvalues.name = 'filsys_id'", users_id);
3208 incremental_after("quota", buffer, aargv);
3209 com_err(whoami, 0, "quota of %d assigned", quota);
3210 if (ingres_errno) return(mr_errcode);
3212 cache_entry(login, "USER", users_id);
3214 EXEC SQL REPEATED UPDATE tblstats SET updates=updates+1, modtime='now'
3215 WHERE table_name='users';
3216 EXEC SQL REPEATED UPDATE tblstats SET appends=appends+1, modtime='now'
3217 WHERE table_name='list' OR table_name='filesys' OR table_name='quota';
3218 if (ingres_errno) return(mr_errcode);
3224 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
3228 ** delta (will be +/- 1)
3231 ** - incr/decr value field in serverhosts table for pop/mach_id
3235 static int set_pop_usage(id, cnt)
3236 EXEC SQL BEGIN DECLARE SECTION;
3239 EXEC SQL END DECLARE SECTION;
3241 EXEC SQL REPEATED UPDATE serverhosts SET value1 = value1 + :cnt
3242 WHERE serverhosts.service = 'POP' AND serverhosts.mach_id = :id;
3244 if (ingres_errno) return(mr_errcode);
3250 /* Validation Routines */
3252 validate_row(q, argv, v)
3253 register struct query *q;
3255 register struct validate *v;
3257 EXEC SQL BEGIN DECLARE SECTION;
3261 EXEC SQL END DECLARE SECTION;
3263 /* build where clause */
3264 build_qual(v->qual, v->argc, argv, qual);
3267 /** I'm pretty sure we don't need this now */
3268 /* setup ingres variables */
3272 if (log_flags & LOG_VALID)
3273 /* tell the logfile what we're doing */
3274 com_err(whoami, 0, "validating row: %s", qual);
3276 /* look for the record */
3277 sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",q->rtable,qual);
3278 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3279 EXEC SQL DECLARE csr126 CURSOR FOR stmt;
3280 EXEC SQL OPEN csr126;
3281 EXEC SQL FETCH csr126 USING DESCRIPTOR :SQLDA;
3282 EXEC SQL CLOSE csr126;
3283 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3285 if (ingres_errno) return(mr_errcode);
3286 if (rowcount == 0) return(MR_NO_MATCH);
3287 if (rowcount > 1) return(MR_NOT_UNIQUE);
3291 validate_fields(q, argv, vo, n)
3293 register char *argv[];
3294 register struct valobj *vo;
3297 register int status;
3302 if (log_flags & LOG_VALID)
3303 com_err(whoami, 0, "validating %s in %s: %s",
3304 vo->namefield, vo->table, argv[vo->index]);
3305 status = validate_name(argv, vo);
3309 if (log_flags & LOG_VALID)
3310 com_err(whoami, 0, "validating %s in %s: %s",
3311 vo->idfield, vo->table, argv[vo->index]);
3312 status = validate_id(q, argv, vo);
3316 if (log_flags & LOG_VALID)
3317 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
3318 status = validate_date(argv, vo);
3322 if (log_flags & LOG_VALID)
3323 com_err(whoami, 0, "validating %s type: %s",
3324 vo->table, argv[vo->index]);
3325 status = validate_type(argv, vo);
3329 if (log_flags & LOG_VALID)
3330 com_err(whoami, 0, "validating typed data (%s): %s",
3331 argv[vo->index - 1], argv[vo->index]);
3332 status = validate_typedata(q, argv, vo);
3336 if (log_flags & LOG_VALID)
3337 com_err(whoami, 0, "validating rename %s in %s",
3338 argv[vo->index], vo->table);
3339 status = validate_rename(argv, vo);
3343 if (log_flags & LOG_VALID)
3344 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
3345 status = validate_chars(argv[vo->index]);
3353 status = lock_table(vo);
3357 if (status != MR_EXISTS) return(status);
3361 if (ingres_errno) return(mr_errcode);
3366 /* validate_chars: verify that there are no illegal characters in
3367 * the string. Legal characters are printing chars other than
3368 * ", *, ?, \, [ and ].
3370 static int illegalchars[] = {
3371 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
3372 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
3373 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
3374 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
3375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
3376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
3377 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
3378 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
3379 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3380 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3381 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3382 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3383 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3384 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3385 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3386 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3393 if (illegalchars[*s++])
3394 return(MR_BAD_CHAR);
3399 validate_id(q, argv, vo)
3402 register struct valobj *vo;
3404 EXEC SQL BEGIN DECLARE SECTION;
3405 char *name, *tbl, *namefield, *idfield;
3407 EXEC SQL END DECLARE SECTION;
3411 name = argv[vo->index];
3413 namefield = vo->namefield;
3414 idfield = vo->idfield;
3416 if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
3417 !strcmp(tbl, "machine") ||
3418 !strcmp(tbl, "filesys") ||
3419 !strcmp(tbl, "list") ||
3420 !strcmp(tbl, "cluster") ||
3421 !strcmp(tbl, "strings")) {
3422 if (!strcmp(tbl, "machine"))
3423 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3424 status = name_to_id(name, tbl, &id);
3426 *(int *)argv[vo->index] = id;
3428 } else if (status == MR_NO_MATCH && !strcmp(tbl, "strings") &&
3429 (q->type == APPEND || q->type == UPDATE)) {
3430 EXEC SQL SELECT value INTO :id FROM numvalues
3431 WHERE name = 'strings_id';
3433 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'string_id';
3434 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3435 cache_entry(name, "STRING", id);
3436 *(int *)argv[vo->index] = id;
3438 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
3444 if (!strcmp(namefield, "uid")) {
3445 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = %s",idfield,tbl,namefield,name);
3447 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",idfield,tbl,namefield,name);
3449 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3450 EXEC SQL DECLARE csr127 CURSOR FOR stmt;
3451 EXEC SQL OPEN csr127;
3453 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3454 if(sqlca.sqlcode == 0) {
3456 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3457 if(sqlca.sqlcode == 0) rowcount++;
3459 EXEC SQL CLOSE csr127;
3463 if (rowcount != 1) return(vo->error);
3464 *argv[vo->index] = *SQLDA->sqlvar[0].sqldata;
3468 validate_name(argv, vo)
3470 register struct valobj *vo;
3472 EXEC SQL BEGIN DECLARE SECTION;
3473 char *name, *tbl, *namefield;
3475 EXEC SQL END DECLARE SECTION;
3478 name = argv[vo->index];
3480 namefield = vo->namefield;
3481 if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
3482 for (c = name; *c; c++)
3486 sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
3487 tbl,tbl,namefield,name);
3488 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3489 EXEC SQL DECLARE csr128 CURSOR FOR stmt;
3490 EXEC SQL OPEN csr128;
3491 EXEC SQL FETCH csr128 USING DESCRIPTOR :SQLDA;
3492 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3493 EXEC SQL CLOSE csr128;
3495 if (ingres_errno) return(mr_errcode);
3496 return ((rowcount == 1) ? MR_EXISTS : vo->error);
3499 validate_date(argv, vo)
3503 EXEC SQL BEGIN DECLARE SECTION;
3507 EXEC SQL END DECLARE SECTION;
3509 idate = argv[vo->index];
3511 * retrieve (dd = interval("years", date(idate) - date("today")))
3513 EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
3515 if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
3520 validate_rename(argv, vo)
3524 EXEC SQL BEGIN DECLARE SECTION;
3525 char *name, *tbl, *namefield, *idfield;
3527 EXEC SQL END DECLARE SECTION;
3531 c = name = argv[vo->index];
3533 if (illegalchars[*c++])
3534 return(MR_BAD_CHAR);
3536 /* minor kludge to upcasify machine names */
3537 if (!strcmp(tbl, "machine"))
3538 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3539 namefield = vo->namefield;
3540 idfield = vo->idfield;
3543 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3546 * retrieve (id = any(table.namefield where table.namefield = name))
3548 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s.%s = '%s'",
3549 namefield,tbl,tbl,namefield,name);
3550 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3551 EXEC SQL DECLARE csr129 CURSOR FOR stmt;
3552 EXEC SQL OPEN csr129;
3553 EXEC SQL FETCH csr129 USING DESCRIPTOR :SQLDA;
3554 if(sqlca.sqlcode == 0) id=1; else id=0;
3555 EXEC SQL CLOSE csr129;
3557 if (ingres_errno) return(mr_errcode);
3563 status = name_to_id(name, tbl, &id);
3564 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3571 validate_type(argv, vo)
3573 register struct valobj *vo;
3575 EXEC SQL BEGIN DECLARE SECTION;
3578 EXEC SQL END DECLARE SECTION;
3581 typename = vo->table;
3582 c = val = argv[vo->index];
3584 if (illegalchars[*c++])
3585 return(MR_BAD_CHAR);
3588 /* uppercase type fields */
3589 for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
3591 EXEC SQL SELECT trans INTO :cdummy FROM alias
3592 WHERE name = :typename AND type='TYPE' AND trans = :val;
3593 if (ingres_errno) return(mr_errcode);
3594 return (sqlca.sqlerrd[2] ? MR_EXISTS : vo->error);
3597 /* validate member or type-specific data field */
3599 validate_typedata(q, argv, vo)
3600 register struct query *q;
3601 register char *argv[];
3602 register struct valobj *vo;
3604 EXEC SQL BEGIN DECLARE SECTION;
3607 char data_type[129];
3609 EXEC SQL END DECLARE SECTION;
3614 /* get named object */
3615 name = argv[vo->index];
3617 /* get field type string (known to be at index-1) */
3618 field_type = argv[vo->index-1];
3620 /* get corresponding data type associated with field type name */
3621 EXEC SQL SELECT trans INTO :data_type FROM alias
3622 WHERE name = :field_type AND type='TYPEDATA';
3623 if (ingres_errno) return(mr_errcode);
3624 if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
3626 /* now retrieve the record id corresponding to the named object */
3627 if (index(data_type, ' '))
3628 *index(data_type, ' ') = 0;
3629 if (!strcmp(data_type, "user")) {
3631 status = name_to_id(name, data_type, &id);
3632 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3634 if (status) return(status);
3635 } else if (!strcmp(data_type, "list")) {
3637 status = name_to_id(name, data_type, &id);
3638 if (status && status == MR_NOT_UNIQUE)
3640 if (status == MR_NO_MATCH) {
3641 /* if idfield is non-zero, then if argv[0] matches the string
3642 * that we're trying to resolve, we should get the value of
3643 * numvalues.[idfield] for the id.
3645 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3646 set_next_object_id(q->validate->object_id, q->rtable, 0);
3648 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
3650 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
3653 } else if (status) return(status);
3654 } else if (!strcmp(data_type, "machine")) {
3656 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3657 status = name_to_id(name, data_type, &id);
3658 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3660 if (status) return(status);
3661 } else if (!strcmp(data_type, "string")) {
3663 status = name_to_id(name, data_type, &id);
3664 if (status && status == MR_NOT_UNIQUE)
3666 if (status == MR_NO_MATCH) {
3667 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3668 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
3670 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3671 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3672 cache_entry(name, "STRING", id);
3673 } else if (status) return(status);
3674 } else if (!strcmp(data_type, "none")) {
3680 /* now set value in argv */
3681 *(int *)argv[vo->index] = id;
3687 /* Lock the table named by the validation object */
3692 sprintf(stmt_buf,"UPDATE %s SET modtime='now' WHERE %s.%s = 0",
3693 vo->table,vo->table,vo->idfield);
3694 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
3695 if (ingres_errno) return(mr_errcode);
3696 if (sqlca.sqlerrd[2] != 1)
3703 /* Check the database at startup time. For now this just resets the
3704 * inprogress flags that the DCM uses.
3707 sanity_check_database()
3712 /* Dynamic SQL support routines */
3713 MR_SQLDA_T *mr_alloc_SQLDA()
3716 short *null_indicators;
3719 if((it=(MR_SQLDA_T *)malloc(sizeof(MR_SQLDA_T)))==NULL) {
3720 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
3724 if((null_indicators=(short *)calloc(QMAXARGS,sizeof(short)))==NULL) {
3725 com_err(whoami, MR_NO_MEM, "setting up SQLDA null indicators");
3729 for(j=0; j<QMAXARGS; j++) {
3730 if((it->sqlvar[j].sqldata=malloc(sizeof(short)+QMAXARGSIZE))==NULL) {
3731 com_err(whoami, MR_NO_MEM, "setting up SQLDA variables");
3734 it->sqlvar[j].sqllen=QMAXARGSIZE;
3735 it->sqlvar[j].sqlind=null_indicators+j;
3736 null_indicators[j]=0;
3743 /* Use mr_check_SQLDA before OPEN CURSOR or EXECUTE */
3747 if(da->sqld > da->sqln) {
3748 com_err(whoami, MR_INTERNAL,
3749 "Internal arg count error preparing for dynamic query");
3750 return(MR_INTERNAL);
3756 /* Use this after FETCH USING DESCRIPTOR one or more
3757 * result columns may contain NULLs. This routine is
3758 * not currently needed, since db/schema creates all
3759 * columns with a NOT NULL WITH DEFAULT clause.
3761 mr_fix_nulls_in_SQLDA(da)
3764 register IISQLVAR *var;
3768 for(j=0, var=da->sqlvar; j<da->sqld; j++, var++) {
3769 switch(var->sqltype) {
3770 case -IISQ_CHA_TYPE:
3774 case -IISQ_INT_TYPE:
3776 intp=(int *)var->sqldata;
3784 /* prefetch_value():
3785 * This routine fetches an appropriate value from the numvalues table.
3786 * It is a little hack to get around the fact that SQL doesn't let you
3787 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
3789 * It is called from the query table as (*v->pre_rtn)(q,Argv,cl) or
3790 * from within a setup_...() routine with the appropriate arguments.
3792 * Correct functioning of this routine may depend on the assumption
3793 * that this query is an APPEND.
3796 prefetch_value(q,argv,cl)
3801 EXEC SQL BEGIN DECLARE SECTION;
3802 char *name = q->validate->object_id;
3804 EXEC SQL END DECLARE SECTION;
3805 int status, limit, argc;
3807 /* set next object id, limiting it if necessary */
3808 if(!strcmp(name, "uid") || !strcmp(name, "gid"))
3809 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
3812 if((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
3815 /* fetch object id */
3816 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name=:name;
3817 if(ingres_errno) return(mr_errcode);
3818 if(sqlca.sqlerrd[2] != 1) return(MR_INTERNAL);
3820 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
3821 sprintf(argv[argc],"%d",value);
3826 /* eof:qsupport.dc */