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 z.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_aftg: needed only because using the query table would
918 * create an invalid SQL statement. *sigh* Basically just validates
919 * that the first argument has type 'FSGROUP' in table 'filesys'.
922 setup_aftg(q, argv, cl)
927 EXEC SQL SELECT filsys_id INTO :idummy FROM filesys
928 WHERE type='FSGROUP';
930 if (sqlca.sqlcode != 0)
931 return(MR_NO_MATCH); /* Is there a better error code to return? */
937 /* setup_dnfp: check to see that the nfs physical partition does not have
938 * any filesystems assigned to it before allowing it to be deleted.
941 setup_dnfp(q, argv, cl)
946 EXEC SQL BEGIN DECLARE SECTION;
949 EXEC SQL END DECLARE SECTION;
951 id = *(int *)argv[0];
953 EXEC SQL REPEATED SELECT label INTO :cdummy FROM filesys fs, nfsphys np
954 WHERE fs.mach_id = :id AND fs.phys_id = np.nfsphys_id
955 AND np.mach_id = :id AND np.dir = :dir;
956 if (sqlca.sqlerrd[2] > 0)
964 /* setup_dqot: Remove allocation from nfsphys before deleting quota.
965 * argv[0] = filsys_id
966 * argv[1] = type if "update_quota" or "delete_quota"
967 * argv[2 or 1] = users_id or list_id
970 setup_dqot(q, argv, cl)
975 EXEC SQL BEGIN DECLARE SECTION;
978 EXEC SQL END DECLARE SECTION;
980 fs = *(int *)argv[0];
981 if (!strcmp(q->name, "update_quota") || !strcmp(q->name, "delete_quota")) {
983 id = *(int *)argv[2];
986 id = *(int *)argv[1];
989 EXEC SQL REPEATED SELECT quota INTO :quota FROM quota
990 WHERE type = :qtype AND entity_id = :id AND filsys_id = :fs;
991 EXEC SQL REPEATED UPDATE nfsphys
992 SET allocated = nfsphys.allocated - :quota
993 WHERE nfsphys_id = filesys.physid AND filesys.filsys_id = :fs;
995 if (ingres_errno) return(mr_errcode);
1000 /* setup_sshi: don't exclusive lock the machine table during
1001 * set_server_host_internal.
1004 setup_sshi(q, argv, cl)
1010 EXEC SQL set lockmode session where readlock = system;
1015 /* setup add_kerberos_user_mapping: add the string to the string
1016 * table if necessary.
1019 setup_akum(q, argv, cl)
1024 EXEC SQL BEGIN DECLARE SECTION;
1027 EXEC SQL END DECLARE SECTION;
1030 if (name_to_id(name, "STRING", &id) != MR_SUCCESS) {
1031 if (q->type != APPEND) return(MR_STRING);
1032 EXEC SQL SELECT value INTO :id FROM numvalues
1033 WHERE name = 'strings_id';
1035 EXEC SQL UPDATE numvalues SET value = :id
1036 WHERE name = 'strings_id';
1037 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
1038 cache_entry(name, "STRING", id);
1040 if (ingres_errno) return(mr_errcode);
1041 *(int *)argv[1] = id;
1047 /* FOLLOWUP ROUTINES */
1049 /* generic set_modtime routine. This takes the table name from the query,
1050 * and will update the modtime, modby, and modwho fields in the entry in
1051 * the table whose name field matches argv[0].
1054 set_modtime(q, argv, cl)
1059 char *name, *entity, *table;
1062 entity = cl->entity;
1063 who = cl->client_id;
1067 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);
1068 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1073 /* generic set_modtime_by_id routine. This takes the table name from
1074 * the query, and the id name from the validate record,
1075 * and will update the modtime, modby, and modwho fields in the entry in
1076 * the table whose id matches argv[0].
1079 set_modtime_by_id(q, argv, cl)
1084 char *entity, *table, *id_name;
1087 entity = cl->entity;
1088 who = cl->client_id;
1090 id_name = q->validate->object_id;
1092 id = *(int *)argv[0];
1093 sprintf(stmt_buf,"UPDATE %s SET modtime = 'now', modby = %d, \
1094 modwith = '%s' WHERE %s.%s = %d",table,who,entity,table,id_name,id);
1095 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1100 /* Sets the finger modtime on a user record. The users_id will be in argv[0].
1103 set_finger_modtime(q, argv, cl)
1108 EXEC SQL BEGIN DECLARE SECTION;
1111 EXEC SQL END DECLARE SECTION;
1113 entity = cl->entity;
1114 who = cl->client_id;
1115 users_id = *(int *)argv[0];
1117 EXEC SQL UPDATE users SET fmodtime='now', fmodby = :who, fmodwith = :entity
1118 WHERE users.users_id = :users_id;
1124 /* Sets the pobox modtime on a user record. The users_id will be in argv[0].
1127 set_pobox_modtime(q, argv, cl)
1132 EXEC SQL BEGIN DECLARE SECTION;
1135 EXEC SQL END DECLARE SECTION;
1137 entity = cl->entity;
1138 who = cl->client_id;
1139 users_id = *(int *)argv[0];
1141 EXEC SQL UPDATE users SET pmodtime='now', pmodby = :who, pmodwith = :entity
1142 WHERE users.users_id = :users_id;
1148 /* Like set_modtime, but uppercases the name first.
1151 set_uppercase_modtime(q, argv, cl)
1156 char *name, *entity, *table;
1159 entity = cl->entity;
1160 who = cl->client_id;
1164 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);
1165 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
1171 /* Sets the modtime on the machine whose mach_id is in argv[0]. This routine
1172 * is necessary for add_machine_to_cluster becuase the table that query
1173 * operates on is "mcm", not "machine".
1176 set_mach_modtime_by_id(q, argv, cl)
1181 EXEC SQL BEGIN DECLARE SECTION;
1184 EXEC SQL END DECLARE SECTION;
1186 entity = cl->entity;
1187 who = cl->client_id;
1188 id = *(int *)argv[0];
1189 EXEC SQL UPDATE machine SET modtime='now', modby = :who, modwith = :entity
1190 WHERE machine.mach_id = :id;
1196 /* Sets the modtime on the cluster whose mach_id is in argv[0]. This routine
1197 * is necessary for add_cluster_data and delete_cluster_data becuase the
1198 * table that query operates on is "svc", not "cluster".
1201 set_cluster_modtime_by_id(q, argv, cl)
1206 EXEC SQL BEGIN DECLARE SECTION;
1209 EXEC SQL END DECLARE SECTION;
1211 entity = cl->entity;
1212 who = cl->client_id;
1214 id = *(int *)argv[0];
1215 EXEC SQL UPDATE cluster SET modtime='now', modby = :who, modwith = :entity
1216 WHERE cluster.clu_id = :id;
1221 /* sets the modtime on the serverhost where the service name is in argv[0]
1222 * and the mach_id is in argv[1].
1225 set_serverhost_modtime(q, argv, cl)
1230 EXEC SQL BEGIN DECLARE SECTION;
1231 char *entity, *serv;
1233 EXEC SQL END DECLARE SECTION;
1235 entity = cl->entity;
1236 who = cl->client_id;
1239 id = *(int *)argv[1];
1240 EXEC SQL UPDATE serverhosts
1241 SET modtime = 'now', modby = :who, modwith = :entity
1242 WHERE service = :serv AND mach_id = :id;
1247 /* sets the modtime on the nfsphys where the mach_id is in argv[0] and the
1248 * directory name is in argv[1].
1251 set_nfsphys_modtime(q, argv, cl)
1256 EXEC SQL BEGIN DECLARE SECTION;
1259 EXEC SQL END DECLARE SECTION;
1261 entity = cl->entity;
1262 who = cl->client_id;
1264 id = *(int *)argv[0];
1266 EXEC SQL UPDATE nfsphys SET modtime = 'now', modby = :who, modwith = :entity
1267 WHERE dir = :dir AND mach_id = :id;
1272 /* sets the modtime on a filesystem, where argv[0] contains the filesys
1276 set_filesys_modtime(q, argv, cl)
1281 EXEC SQL BEGIN DECLARE SECTION;
1282 char *label, *entity;
1284 EXEC SQL END DECLARE SECTION;
1286 entity = cl->entity;
1287 who = cl->client_id;
1290 if (!strcmp(q->shortname, "ufil"))
1293 EXEC SQL UPDATE filesys SET modtime = 'now', modby = :who,
1294 modwith = :entity, phys_id = :var_phys_id
1295 WHERE label = LEFT(:label,SIZE(label));
1300 /* sets the modtime on a zephyr class, where argv[0] contains the class
1304 set_zephyr_modtime(q, argv, cl)
1309 EXEC SQL BEGIN DECLARE SECTION;
1310 char *class, *entity;
1312 EXEC SQL END DECLARE SECTION;
1314 entity = cl->entity;
1315 who = cl->client_id;
1319 EXEC SQL UPDATE zephyr SET modtime = 'now', modby = :who, modwith = :entity
1320 WHERE class = LEFT(:class,SIZE(class));
1326 /* fixes the modby field. This will be the second to last thing in the
1327 * argv, the argv length is determined from the query structure. It is
1328 * passed as a pointer to an integer. This will either turn it into a
1329 * username, or # + the users_id.
1331 followup_fix_modby(q, sq, v, action, actarg, cl)
1333 register struct save_queue *sq;
1335 register int (*action)();
1336 register int actarg;
1340 char **argv, *malloc();
1344 while (sq_get_data(sq, &argv)) {
1347 status = id_to_name(id, "USER", &argv[i]);
1349 status = id_to_name(-id, "STRING", &argv[i]);
1350 if (status && status != MR_NO_MATCH)
1352 (*action)(q->vcnt, argv, actarg);
1353 for (j = 0; j < q->vcnt; j++)
1362 /* After retrieving a user account, fix the modby field and signature.
1363 * The modby field is the second to last thing in the
1364 * argv, the argv length is determined from the query structure. It is
1365 * passed as a pointer to an integer. This will either turn it into a
1366 * username, or # + the users_id. Only "gua*" queries have a signature,
1367 * these are ones with U_END return values. "gub*" queries also use this
1368 * routine but don't have a signature.
1370 followup_guax(q, sq, v, action, actarg, cl)
1372 register struct save_queue *sq;
1374 register int (*action)();
1375 register int actarg;
1379 char **argv, *malloc();
1381 char sigbuf[256], *rawsig, *kname;
1387 while (sq_get_data(sq, &argv)) {
1390 status = id_to_name(id, "USER", &argv[i]);
1392 status = id_to_name(-id, "STRING", &argv[i]);
1393 if (status && status != MR_NO_MATCH)
1396 if (q->vcnt == U_END) {
1397 com_err(whoami, 0, "compressing signature");
1398 rawsig = argv[U_SIGNATURE];
1399 bcopy(&rawsig[0], &id, sizeof(int));
1401 status = id_to_name(id, "STRING", &kname);
1402 bcopy(&rawsig[4], &si.timestamp, sizeof(int));
1403 si.timestamp = ntohl(si.timestamp);
1404 si.SigInfoVersion = 0; /* XXXXX this isn't used */
1405 kname_parse(si.pname, si.pinst, si.prealm, kname);
1406 si.rawsig = (unsigned char *)&rawsig[8];
1407 GDSS_Recompose(&si, sigbuf);
1408 argv[U_SIGNATURE] = strsave(sigbuf);
1411 (*action)(q->vcnt, argv, actarg);
1412 for (j = 0; j < q->vcnt; j++)
1422 ** followup_ausr - add finger and pobox entries, set_user_modtime
1425 ** argv[0] - login (add_user)
1426 ** argv[3] - last name
1427 ** argv[4] - first name
1428 ** argv[5] - middle name
1432 followup_ausr(q, argv, cl)
1437 EXEC SQL BEGIN DECLARE SECTION;
1438 int who, status, sigwho, id;
1439 char *login, *entity, *src, *dst, *name;
1441 EXEC SQL END DECLARE SECTION;
1443 char databuf[32], *kname_unparse();
1444 EXEC SQL BEGIN DECLARE SECTION;
1446 EXEC SQL END DECLARE SECTION;
1450 /* build fullname */
1451 if (strlen(argv[4]) && strlen(argv[5]))
1452 sprintf(fullname, "%s %s %s", argv[4], argv[5], argv[3]);
1453 else if (strlen(argv[4]))
1454 sprintf(fullname, "%s %s", argv[4], argv[3]);
1456 sprintf(fullname, "%s", argv[3]);
1459 sprintf(databuf, "%s:%s", argv[U_NAME], argv[U_MITID]);
1460 /* skip bytes for timestamp & kname */
1461 si.rawsig = (unsigned char *)&rawsig[8];
1462 status = GDSS_Verify(databuf, strlen(databuf), argv[U_SIGNATURE], &si);
1464 name = kname_unparse(si.pname, si.pinst, si.prealm);
1465 status = name_to_id(name, "STRING", &sigwho);
1466 if (status == MR_NO_MATCH) {
1467 EXEC SQL REPEATED SELECT value INTO :sigwho FROM numvalues
1468 WHERE name = 'strings_id';
1470 EXEC SQL REPEATED UPDATE numvalues SET value = :sigwho
1471 WHERE name = 'strings_id';
1472 EXEC SQL INSERT INTO strings (string_id, string)
1473 VALUES (:sigwho, :name);
1476 sigwho = htonl(sigwho);
1477 bcopy(&sigwho, &rawsig[0], sizeof(int));
1478 si.timestamp = htonl(si.timestamp);
1479 bcopy(&si.timestamp, &rawsig[4], sizeof(int));
1485 who = cl->client_id;
1486 entity = cl->entity;
1488 /* create finger entry, pobox & set modtime on user */
1490 EXEC SQL REPEATED UPDATE users
1491 SET modtime='now', modby=:who, modwith = :entity,
1492 fullname = :fullname, affiliation = type,
1493 signature = :rawsig,
1494 fmodtime='now', fmodby = :who, fmodwith = :entity,
1495 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1496 WHERE login = :login;
1498 EXEC SQL REPEATED UPDATE users
1499 SET modtime='now', modby=:who, modwith = :entity,
1500 fullname = :fullname, affiliation = type,
1501 fmodtime='now', fmodby = :who, fmodwith = :entity,
1502 potype='NONE', pmodtime='now', pmodby = :who, pmodwith = :entity
1503 WHERE login = :login;
1510 /* followup_gpob: fixes argv[2] based on the IDs currently there and the
1511 * type in argv[1]. Then completes the upcall to the user.
1513 * argv[2] is of the form "123:234" where the first integer is the machine
1514 * ID if it is a pop box, and the second is the string ID if it is an SMTP
1515 * box. argv[1] should be "POP", "SMTP", or "NONE". Boxes of type NONE
1519 followup_gpob(q, sq, v, action, actarg, cl)
1520 register struct query *q;
1521 register struct save_queue *sq;
1522 register struct validate *v;
1523 register int (*action)();
1527 char **argv, *index();
1529 int mid, sid, status, i;
1532 while (sq_get_data(sq, &argv)) {
1533 mr_trim_args(2, argv);
1535 p = index(argv[2], ':');
1537 mid = atoi(argv[2]);
1540 if (!strcmp(ptype, "POP")) {
1541 status = id_to_name(mid, "MACHINE", &argv[2]);
1542 if (status == MR_NO_MATCH)
1544 } else if (!strcmp(ptype, "SMTP")) {
1545 status = id_to_name(sid, "STRING", &argv[2]);
1546 if (status == MR_NO_MATCH)
1548 } else /* ptype == "NONE" */ {
1551 if (status) return(status);
1553 if (!strcmp(q->shortname, "gpob")) {
1554 sid = atoi(argv[4]);
1556 status = id_to_name(sid, "USER", &argv[4]);
1558 status = id_to_name(-sid, "STRING", &argv[4]);
1560 if (status && status != MR_NO_MATCH) return(status);
1562 (*action)(q->vcnt, argv, actarg);
1564 /* free saved data */
1565 for (i = 0; i < q->vcnt; i++)
1571 return (MR_SUCCESS);
1575 /* followup_glin: fix the ace_name in argv[8]. argv[7] will contain the
1576 * ace_type: "LIST", "USER", or "NONE". Decode the id in argv[8] into the
1577 * proper name based on the type, and repace that string in the argv.
1578 * Also fixes the modby field by called followup_fix_modby.
1581 followup_glin(q, sq, v, action, actarg, cl)
1582 register struct query *q;
1583 register struct save_queue *sq;
1584 register struct validate *v;
1585 register int (*action)();
1589 char **argv, *malloc(), *realloc(), *type;
1590 int id, i, idx, status;
1593 if (!strcmp(q->shortname, "gsin"))
1596 while (sq_get_data(sq, &argv)) {
1597 mr_trim_args(q->vcnt, argv);
1599 id = atoi(argv[i = q->vcnt - 2]);
1601 status = id_to_name(id, "USER", &argv[i]);
1603 status = id_to_name(-id, "STRING", &argv[i]);
1604 if (status && status != MR_NO_MATCH)
1607 id = atoi(argv[idx]);
1608 type = argv[idx - 1];
1610 if (!strcmp(type, "LIST")) {
1611 status = id_to_name(id, "LIST", &argv[idx]);
1612 } else if (!strcmp(type, "USER")) {
1613 status = id_to_name(id, "USER", &argv[idx]);
1614 } else if (!strcmp(type, "KERBEROS")) {
1615 status = id_to_name(id, "STRING", &argv[idx]);
1616 } else if (!strcmp(type, "NONE")) {
1619 argv[idx] = strsave("NONE");
1623 argv[idx] = strsave("???");
1625 if (status && status != MR_NO_MATCH)
1628 if (!strcmp(q->shortname, "glin") && atoi(argv[6]) == -1) {
1629 argv[6] = realloc(argv[6], strlen(UNIQUE_GID) + 1);
1630 strcpy(argv[6], UNIQUE_GID);
1634 (*action)(q->vcnt, argv, actarg);
1636 /* free saved data */
1637 for (i = 0; i < q->vcnt; i++)
1643 return (MR_SUCCESS);
1647 /* followup_gqot: Fix the entity name, directory name & modby fields
1648 * argv[0] = filsys_id
1650 * argv[2] = entity_id
1651 * argv[3] = ascii(quota)
1654 followup_gqot(q, sq, v, action, actarg, cl)
1656 register struct save_queue *sq;
1658 register int (*action)();
1659 register int actarg;
1663 char **argv, *malloc();
1664 EXEC SQL BEGIN DECLARE SECTION;
1667 EXEC SQL END DECLARE SECTION;
1670 if (!strcmp(q->name, "get_quota") ||
1671 !strcmp(q->name, "get_quota_by_filesys"))
1675 while (sq_get_data(sq, &argv)) {
1677 switch (argv[1][0]) {
1679 status = id_to_name(atoi(argv[2]), "USER", &argv[2]);
1683 status = id_to_name(atoi(argv[2]), "LIST", &argv[2]);
1687 argv[2] = strsave("system:anyuser");
1691 argv[2] = malloc(8);
1692 sprintf(argv[2], "%d", id);
1695 id = atoi(argv[idx]);
1697 argv[idx] = malloc(256);
1701 EXEC SQL REPEATED SELECT name INTO :name FROM filesys
1702 WHERE label = :label;
1704 EXEC SQL REPEATED SELECT dir INTO :name FROM nfsphys
1705 WHERE nfsphys_id = :id;
1707 if (sqlca.sqlerrd[2] != 1) {
1708 sprintf(argv[idx], "#%d", id);
1711 id = atoi(argv[idx+3]);
1713 status = id_to_name(id, "USER", &argv[idx+3]);
1715 status = id_to_name(-id, "STRING", &argv[idx+3]);
1716 if (status && status != MR_NO_MATCH)
1718 (*action)(q->vcnt, argv, actarg);
1719 for (j = 0; j < q->vcnt; j++)
1728 /* followup_aqot: Add allocation to nfsphys after creating quota.
1729 * argv[0] = filsys_id
1730 * argv[1] = type if "add_quota" or "update_quota"
1732 * argv[3 or 2] = ascii(quota)
1735 followup_aqot(q, argv, cl)
1740 EXEC SQL BEGIN DECLARE SECTION;
1741 int quota, id, fs, who;
1742 char *entity, *qtype;
1743 EXEC SQL END DECLARE SECTION;
1745 fs = *(int *)argv[0];
1746 if (!strcmp(q->name, "add_quota") || !strcmp(q->name, "update_quota")) {
1748 id = *(int *)argv[2];
1749 quota = atoi(argv[3]);
1752 id = *(int *)argv[1];
1753 quota = atoi(argv[2]);
1755 who = cl->client_id;
1756 entity = cl->entity;
1758 EXEC SQL REPEATED UPDATE quota
1759 SET modtime = 'now', modby = :who, modwith = :entity
1760 WHERE filsys_id = :fs and type = :qtype and entity_id = :id;
1761 EXEC SQL REPEATED UPDATE nfsphys
1762 SET allocated = allocated + :quota
1763 WHERE nfsphys_id = filesys.phys_id AND filesys.filsys_id = :fs;
1764 if (ingres_errno) return(mr_errcode);
1769 followup_gpce(q, sq, v, action, actarg, cl)
1771 register struct save_queue *sq;
1773 register int (*action)();
1774 register int actarg;
1778 char **argv, *malloc();
1782 while (sq_get_data(sq, &argv)) {
1783 id = atoi(argv[PCAP_QSERVER]);
1784 status = id_to_name(id, "MACHINE", &argv[PCAP_QSERVER]);
1785 if (status) return (status);
1788 status = id_to_name(id, "USER", &argv[i]);
1790 status = id_to_name(-id, "STRING", &argv[i]);
1791 if (status && status != MR_NO_MATCH)
1793 (*action)(q->vcnt, argv, actarg);
1794 for (j = 0; j < q->vcnt; j++)
1806 followup_gzcl(q, sq, v, action, actarg, cl)
1807 register struct query *q;
1808 register struct save_queue *sq;
1809 register struct validate *v;
1810 register int (*action)();
1817 while (sq_get_data(sq, &argv)) {
1818 mr_trim_args(q->vcnt, argv);
1820 id = atoi(argv[i = q->vcnt - 2]);
1822 status = id_to_name(id, "USER", &argv[i]);
1824 status = id_to_name(-id, "STRING", &argv[i]);
1825 if (status && status != MR_NO_MATCH)
1828 for (i = 1; i < 8; i+=2) {
1829 id = atoi(argv[i+1]);
1830 if (!strcmp(argv[i], "LIST")) {
1831 status = id_to_name(id, "LIST", &argv[i+1]);
1832 } else if (!strcmp(argv[i], "USER")) {
1833 status = id_to_name(id, "USER", &argv[i+1]);
1834 } else if (!strcmp(argv[i], "KERBEROS")) {
1835 status = id_to_name(id, "STRING", &argv[i+1]);
1836 } else if (!strcmp(argv[i], "NONE")) {
1839 argv[i+1] = strsave("NONE");
1843 argv[i+1] = strsave("???");
1845 if (status && status != MR_NO_MATCH)
1850 (*action)(q->vcnt, argv, actarg);
1852 /* free saved data */
1853 for (i = 0; i < q->vcnt; i++)
1865 followup_gsha(q, sq, v, action, actarg, cl)
1866 register struct query *q;
1867 register struct save_queue *sq;
1868 register struct validate *v;
1869 register int (*action)();
1876 while (sq_get_data(sq, &argv)) {
1877 mr_trim_args(q->vcnt, argv);
1881 status = id_to_name(id, "USER", &argv[4]);
1883 status = id_to_name(-id, "STRING", &argv[4]);
1884 if (status && status != MR_NO_MATCH)
1888 if (!strcmp(argv[1], "LIST")) {
1889 status = id_to_name(id, "LIST", &argv[2]);
1890 } else if (!strcmp(argv[1], "USER")) {
1891 status = id_to_name(id, "USER", &argv[2]);
1892 } else if (!strcmp(argv[1], "KERBEROS")) {
1893 status = id_to_name(id, "STRING", &argv[2]);
1894 } else if (!strcmp(argv[1], "NONE")) {
1897 argv[2] = strsave("NONE");
1901 argv[2] = strsave("???");
1903 if (status && status != MR_NO_MATCH)
1907 (*action)(q->vcnt, argv, actarg);
1909 /* free saved data */
1910 for (i = 0; i < q->vcnt; i++)
1920 /* Special query routines */
1922 /* set_pobox - this does all of the real work.
1923 * argv = user_id, type, box
1924 * if type is POP, then box should be a machine, and its ID should be put in
1925 * pop_id. If type is SMTP, then box should be a string and its ID should
1926 * be put in box_id. If type is NONE, then box doesn't matter.
1929 int set_pobox(q, argv, cl)
1934 EXEC SQL BEGIN DECLARE SECTION;
1936 char *box, potype[9];
1937 EXEC SQL END DECLARE SECTION;
1941 user = *(int *)argv[0];
1943 EXEC SQL REPEATED SELECT pop_id, potype INTO :id, :potype FROM users
1944 WHERE users_id = :user;
1945 if (ingres_errno) return(mr_errcode);
1946 if (!strcmp(strtrim(potype), "POP"))
1947 set_pop_usage(id, -1);
1949 if (!strcmp(argv[1], "POP")) {
1950 status = name_to_id(box, "MACHINE", &id);
1951 if (status == MR_NO_MATCH)
1955 EXEC SQL REPEATED UPDATE users SET potype = 'POP', pop_id = :id
1956 WHERE users_id = :user;
1957 set_pop_usage(id, 1);
1958 } else if (!strcmp(argv[1], "SMTP")) {
1959 if (index(box, '/') || index(box, '|'))
1960 return(MR_BAD_CHAR);
1961 status = name_to_id(box, "STRING", &id);
1962 if (status == MR_NO_MATCH) {
1963 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
1964 WHERE name='strings_id';
1966 EXEC SQL REPEATED UPDATE numvalues SET value = :id
1967 WHERE name='strings_id';
1968 EXEC SQL INSERT INTO strings (string_id, string)
1972 EXEC SQL REPEATED UPDATE users SET potype='SMTP', box_id = :id
1973 WHERE users_id = :user;
1974 } else /* argv[1] == "NONE" */ {
1975 EXEC SQL REPEATED UPDATE users SET potype='NONE'
1976 WHERE users_id = :user;
1979 set_pobox_modtime(q, argv, cl);
1980 EXEC SQL REPEATED UPDATE tblstats SET updates = updates+1, modtime='now'
1981 WHERE tblstats.table_name='users';
1982 if (ingres_errno) return(mr_errcode);
1987 /* get_list_info: passed a wildcard list name, returns lots of stuff about
1988 * each list. This is tricky: first build a queue of all requested
1989 * data. Rest of processing consists of fixing gid, ace_name, and modby.
1992 get_list_info(q, aargv, cl, action, actarg)
1993 register struct query *q;
1996 register int (*action)();
1999 char *argv[13], *malloc(), *realloc();
2000 EXEC SQL BEGIN DECLARE SECTION;
2001 char *name, acl_type[9], listname[33], active[5], public[5], hidden[5];
2002 char maillist[5], grouplist[5], gid_str[6], acl_name[256], desc[256];
2003 char modtime[27], modby[256], modwith[9];
2004 int id, rowcount, acl_id, hid, modby_id;
2005 EXEC SQL END DECLARE SECTION;
2006 int returned, status;
2007 struct save_queue *sq, *sq_create();
2009 returned = rowcount = 0;
2011 convert_wildcards(name);
2014 EXEC SQL DECLARE csr102 CURSOR FOR SELECT list_id FROM list
2015 WHERE name LIKE :name ESCAPE '*';
2016 EXEC SQL OPEN csr102;
2019 EXEC SQL FETCH csr102 INTO :id;
2020 if(sqlca.sqlcode!=0) break;
2021 sq_save_data(sq, id);
2024 EXEC SQL CLOSE csr102;
2026 if (ingres_errno) return(mr_errcode);
2028 return(MR_NO_MATCH);
2030 argv[0] = listname; argv[1] = active; argv[2] = public; argv[3] = hidden;
2031 argv[4] = maillist; argv[5] = grouplist; argv[6] = gid_str;
2032 argv[7] = acl_type; argv[9] = desc; argv[10] = modtime; argv[12] = modwith;
2034 while (sq_get_data(sq, &id)) {
2038 EXEC SQL REPEATED SELECT name, CHAR(active), CHAR(publicflg),
2039 CHAR(hidden), hidden, CHAR(maillist), CHAR(grouplist), CHAR(gid),
2040 TRIM(acl_type), acl_id, description, CHAR(modtime), modby, modwith
2041 INTO :listname, :active, :public, :hidden, :hid, :maillist,
2042 :grouplist, :gid_str, :acl_type, :acl_id, :desc,
2043 :modtime, :modby_id, :modwith
2044 FROM list WHERE list_id = :id;
2046 if (ingres_errno) return(mr_errcode);
2048 if (atoi(gid_str) == -1)
2049 argv[6] = UNIQUE_GID;
2051 argv[8] = malloc(0);
2052 if (!strcmp(acl_type, "LIST")) {
2053 status = id_to_name(acl_id, "LIST", &argv[8]);
2054 } else if (!strcmp(acl_type, "USER")) {
2055 status = id_to_name(acl_id, "USER", &argv[8]);
2056 } else if (!strcmp(acl_type, "KERBEROS")) {
2057 status = id_to_name(acl_id, "STRING", &argv[8]);
2058 } else if (!strcmp(acl_type, "NONE")) {
2061 argv[8] = strsave("NONE");
2065 argv[8] = strsave("???");
2067 if (status && status != MR_NO_MATCH) return(status);
2069 argv[11] = malloc(0);
2071 status = id_to_name(modby_id, "USER", &argv[11]);
2073 status = id_to_name(-modby_id, "STRING", &argv[11]);
2074 if (status && status != MR_NO_MATCH) return(status);
2076 mr_trim_args(q->vcnt, argv);
2078 (*action)(q->vcnt, argv, actarg);
2084 if (ingres_errno) return(mr_errcode);
2085 return (MR_SUCCESS);
2089 /* Add_member_to_list: do list flattening as we go! MAXLISTDEPTH is
2090 * how many different ancestors a member is allowed to have.
2093 #define MAXLISTDEPTH 1024
2095 int add_member_to_list(q, argv, cl)
2100 EXEC SQL BEGIN DECLARE SECTION;
2101 int id, lid, mid, error, who, ref;
2102 char *mtype, dtype[9], *entity;
2103 EXEC SQL END DECLARE SECTION;
2104 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2105 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2107 char *dtypes[MAXLISTDEPTH];
2108 char *iargv[3], *buf;
2110 lid = *(int *)argv[0];
2112 mid = *(int *)argv[2];
2113 /* if the member is already a direct member of the list, punt */
2114 EXEC SQL REPEATED SELECT list_id INTO :idummy FROM imembers
2115 WHERE list_id = :lid AND member_id = :mid
2116 AND member_type = :mtype AND direct = 1;
2117 if (sqlca.sqlerrd[2] > 0)
2119 if (!strcasecmp(mtype, "STRING")) {
2121 status = id_to_name(mid, "STRING", &buf);
2122 if (status) return(status);
2123 if (index(buf, '/') || index(buf, '|')) {
2125 return(MR_BAD_CHAR);
2133 EXEC SQL DECLARE csr103 CURSOR FOR
2134 SELECT list_id, ref_count FROM imembers
2135 WHERE member_id = :lid AND member_type='LIST';
2136 EXEC SQL OPEN csr103;
2138 EXEC SQL FETCH csr103 INTO :id, :ref;
2139 if(sqlca.sqlcode != 0) break;
2141 ancestors[acount++] = id;
2142 if (acount >= MAXLISTDEPTH) break;
2144 EXEC SQL CLOSE csr103;
2145 if (ingres_errno) return(mr_errcode);
2146 if (acount >= MAXLISTDEPTH) {
2147 return(MR_INTERNAL);
2149 descendants[0] = mid;
2154 if (!strcmp(mtype, "LIST")) {
2155 EXEC SQL DECLARE csr104 CURSOR FOR
2156 SELECT member_id, member_type, ref_count
2158 WHERE list_id = :mid;
2159 EXEC SQL OPEN csr104;
2161 EXEC SQL FETCH csr104 INTO :id, :dtype, :ref;
2162 if(sqlca.sqlcode != 0) break;
2165 dtypes[dcount] = "LIST";
2168 dtypes[dcount] = "USER";
2171 dtypes[dcount] = "STRING";
2174 dtypes[dcount] = "KERBEROS";
2181 descendants[dcount++] = id;
2182 if (dcount >= MAXLISTDEPTH) {
2187 EXEC SQL CLOSE csr104;
2188 if (ingres_errno) return(mr_errcode);
2190 return(MR_INTERNAL);
2192 for (a = 0; a < acount; a++) {
2194 for (d = 0; d < dcount; d++) {
2195 mid = descendants[d];
2197 if (mid == lid && !strcmp(mtype, "LIST")) {
2198 return(MR_LISTLOOP);
2200 EXEC SQL REPEATED SELECT ref_count INTO :idummy FROM imembers
2201 WHERE list_id = :lid AND member_id = :mid
2202 AND member_type = :mtype;
2203 ref = aref[a] * dref[d];
2204 if (sqlca.sqlerrd[2] > 0) {
2205 if (a == 0 && d == 0) {
2206 EXEC SQL UPDATE imembers
2207 SET ref_count = ref_count+ref, direct=1
2208 WHERE list_id = :lid AND member_id = :mid
2209 AND member_type = :mtype;
2211 EXEC SQL UPDATE imembers
2212 SET ref_count = ref_count+ref
2213 WHERE list_id = :lid AND member_id = :mid
2214 AND member_type = :mtype;
2217 incremental_clear_before();
2218 if (a == 0 && d == 0) {
2219 EXEC SQL INSERT INTO imembers
2220 (list_id, member_id, direct, member_type, ref_count)
2221 VALUES (:lid, :mid, 1, :mtype, 1);
2223 EXEC SQL INSERT INTO imembers
2224 (list_id, member_id, member_type, ref_count)
2225 VALUES (:lid, :mid, :mtype, 1);
2227 iargv[0] = (char *)lid;
2229 iargv[2] = (char *)mid;
2230 incremental_after("members", 0, iargv);
2234 lid = *(int *)argv[0];
2235 entity = cl->entity;
2236 who = cl->client_id;
2237 EXEC SQL REPEATED UPDATE list
2238 SET modtime='now', modby = :who, modwith = :entity
2239 WHERE list_id = :lid;
2240 if (ingres_errno) return(mr_errcode);
2245 /* Delete_member_from_list: do list flattening as we go!
2248 int delete_member_from_list(q, argv, cl)
2253 EXEC SQL BEGIN DECLARE SECTION;
2254 int id, lid, mid, cnt, error, who, ref;
2255 char *mtype, dtype[9], *entity;
2256 EXEC SQL END DECLARE SECTION;
2257 int ancestors[MAXLISTDEPTH], aref[MAXLISTDEPTH], acount, a;
2258 int descendants[MAXLISTDEPTH], dref[MAXLISTDEPTH], dcount, d;
2259 char *dtypes[MAXLISTDEPTH];
2262 lid = *(int *)argv[0];
2264 mid = *(int *)argv[2];
2265 /* if the member is not a direct member of the list, punt */
2266 EXEC SQL REPEATED SELECT list_id INTO :idummy FROM imembers
2267 WHERE list_id = :lid AND member_id = :mid
2268 AND member_type = :mtype AND direct = 1;
2269 if (ingres_errno) return(mr_errcode);
2270 if (sqlca.sqlcode == 100)
2271 return(MR_NO_MATCH);
2275 EXEC SQL DECLARE csr105 CURSOR FOR
2276 SELECT list_id, ref_count FROM imembers
2277 WHERE member_id = :lid AND member_type = 'LIST';
2278 EXEC SQL OPEN csr105;
2280 EXEC SQL FETCH csr105 INTO :id, :ref;
2281 if(sqlca.sqlcode!=0) break;
2283 ancestors[acount++] = id;
2284 if (acount >= MAXLISTDEPTH) break;
2286 EXEC SQL CLOSE csr105;
2289 if (acount >= MAXLISTDEPTH)
2290 return(MR_INTERNAL);
2291 descendants[0] = mid;
2296 if (!strcmp(mtype, "LIST")) {
2297 EXEC SQL DECLARE csr106 CURSOR FOR
2298 SELECT member_id, member_type, ref_count FROM imembers
2299 WHERE list_id = :mid;
2300 EXEC SQL OPEN csr106;
2302 EXEC SQL FETCH csr106 INTO :id, :dtype, :ref;
2303 if(sqlca.sqlcode!=0) break;
2306 dtypes[dcount] = "LIST";
2309 dtypes[dcount] = "USER";
2312 dtypes[dcount] = "STRING";
2315 dtypes[dcount] = "KERBEROS";
2322 descendants[dcount++] = id;
2323 if (dcount >= MAXLISTDEPTH) break;
2325 EXEC SQL CLOSE csr106;
2329 return(MR_INTERNAL);
2331 for (a = 0; a < acount; a++) {
2333 for (d = 0; d < dcount; d++) {
2334 mid = descendants[d];
2336 if (mid == lid && !strcmp(mtype, "LIST")) {
2337 return(MR_LISTLOOP);
2339 EXEC SQL REPEATED SELECT ref_count INTO :cnt FROM imembers
2340 WHERE list_id = :lid AND member_id = :mid AND member_type = :mtype;
2341 ref = aref[a] * dref[d];
2343 iargv[0] = (char *)lid;
2345 iargv[2] = (char *)mid;
2346 incremental_before("members", 0, iargv);
2347 EXEC SQL DELETE FROM imembers
2348 WHERE list_id = :lid AND member_id = :mid
2349 AND member_type= :mtype;
2350 incremental_clear_after();
2351 } else if (a == 0 && d == 0) {
2352 EXEC SQL UPDATE imembers
2353 SET ref_count = refcount - :ref, direct = 0
2354 WHERE list_id = :lid AND member_id = :mid
2355 AND member_type = :mtype;
2357 EXEC SQL UPDATE imembers
2358 SET ref_count=refcount-:ref
2359 WHERE list_id = :lid AND member_id = :mid
2360 AND member_type = :mtype;
2364 lid = *(int *)argv[0];
2365 entity = cl->entity;
2366 who = cl->client_id;
2367 EXEC SQL UPDATE list SET modtime = 'now', modby = :who, modwith = :entity
2368 WHERE list_id = :lid;
2369 if (ingres_errno) return(mr_errcode);
2374 /* get_ace_use - given a type and a name, return a type and a name.
2375 * The ace_type is one of "LIST", "USER", "RLIST", or "RUSER" in argv[0],
2376 * and argv[1] will contain the ID of the entity in question. The R*
2377 * types mean to recursively look at every containing list, not just
2378 * when the object in question is a direct member. On return, the
2379 * usage type will be one of LIST, SERVICE, FILESYS, QUOTA, QUERY, or ZEPHYR.
2382 int get_ace_use(q, argv, cl, action, actarg)
2390 EXEC SQL BEGIN DECLARE SECTION;
2392 int aid, listid, id;
2393 EXEC SQL END DECLARE SECTION;
2394 struct save_queue *sq, *sq_create();
2397 aid = *(int *)argv[1];
2398 if (!strcmp(atype, "LIST") || !strcmp(atype, "USER") ||
2399 !strcmp(atype, "KERBEROS")) {
2400 return(get_ace_internal(atype, aid, action, actarg));
2404 if (!strcmp(atype, "RLIST")) {
2405 sq_save_data(sq, aid);
2406 /* get all the list_id's of containing lists */
2407 EXEC SQL DECLARE csr107 CURSOR FOR
2408 SELECT list_id FROM imembers
2409 WHERE member_type='LIST' AND member_id = :aid;
2410 EXEC SQL OPEN csr107;
2412 EXEC SQL FETCH csr107 INTO :listid;
2413 if(sqlca.sqlcode != 0) break;
2414 sq_save_unique_data(sq, listid);
2416 EXEC SQL CLOSE csr107;
2417 /* now process each one */
2418 while (sq_get_data(sq, &id)) {
2419 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2424 if (!strcmp(atype, "RUSER")) {
2425 EXEC SQL DECLARE csr108 CURSOR FOR
2426 SELECT list_id FROM imembers
2427 WHERE member_type='USER' AND member_id = :aid;
2428 EXEC SQL OPEN csr108;
2430 EXEC SQL FETCH csr108 INTO :listid;
2431 if(sqlca.sqlcode != 0) break;
2432 sq_save_data(sq, listid);
2434 EXEC SQL CLOSE csr108;
2435 /* now process each one */
2436 while (sq_get_data(sq, &id)) {
2437 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2440 if (get_ace_internal("USER", aid, action, actarg) == MR_SUCCESS)
2444 if (!strcmp(atype, "RKERBERO")) {
2445 EXEC SQL DECLARE csr109 CURSOR FOR
2446 SELECT list_id FROM imembers
2447 WHERE member_type='KERBEROS' AND member_id = :aid;
2448 EXEC SQL OPEN csr109;
2450 EXEC SQL FETCH csr109 INTO :listid;
2451 if(sqlca.sqlcode != 0) break;
2452 sq_save_data(sq, listid);
2454 EXEC SQL CLOSE csr109;
2455 /* now process each one */
2456 while (sq_get_data(sq, &id)) {
2457 if (get_ace_internal("LIST", id, action, actarg) == MR_SUCCESS)
2460 if (get_ace_internal("KERBEROS", aid, action, actarg) == MR_SUCCESS)
2465 if (ingres_errno) return(mr_errcode);
2466 if (!found) return(MR_NO_MATCH);
2471 /* This looks up a single list or user for ace use. atype must be "USER"
2472 * or "LIST", and aid is the ID of the corresponding object. This is used
2473 * by get_ace_use above.
2476 get_ace_internal(atype, aid, action, actarg)
2477 EXEC SQL BEGIN DECLARE SECTION;
2480 EXEC SQL END DECLARE SECTION;
2486 EXEC SQL BEGIN DECLARE SECTION;
2488 EXEC SQL END DECLARE SECTION;
2491 if (!strcmp(atype, "LIST")) {
2492 rargv[0] = "FILESYS";
2493 EXEC SQL DECLARE csr110 CURSOR FOR
2494 SELECT label FROM filesys
2495 WHERE owners = :aid;
2496 EXEC SQL OPEN csr110;
2498 EXEC SQL FETCH csr110 INTO :name;
2499 if(sqlca.sqlcode != 0) break;
2500 (*action)(2, rargv, actarg);
2503 EXEC SQL CLOSE csr110;
2506 EXEC SQL DECLARE csr111 CURSOR FOR
2507 SELECT capability FROM capacls
2508 WHERE list_id = :aid ;
2509 EXEC SQL OPEN csr111;
2511 EXEC SQL FETCH csr111 INTO :name ;
2512 if(sqlca.sqlcode != 0) break;
2513 (*action)(2, rargv, actarg);
2516 EXEC SQL CLOSE csr111;
2517 } else if (!strcmp(atype, "USER")) {
2518 rargv[0] = "FILESYS";
2519 EXEC SQL DECLARE csr112 CURSOR FOR
2520 SELECT label FROM filesys
2522 EXEC SQL OPEN csr112;
2524 EXEC SQL FETCH csr112 INTO :name ;
2525 if(sqlca.sqlcode != 0) break;
2526 (*action)(2, rargv, actarg);
2529 EXEC SQL CLOSE csr112;
2533 EXEC SQL DECLARE csr113 CURSOR FOR
2534 SELECT name FROM list
2535 WHERE acl_type = :atype AND acl_id = :aid;
2536 EXEC SQL OPEN csr113;
2538 EXEC SQL FETCH csr113 INTO :name;
2539 if(sqlca.sqlcode != 0) break;
2540 (*action)(2, rargv, actarg);
2543 EXEC SQL CLOSE csr113;
2545 rargv[0] = "SERVICE";
2546 EXEC SQL DECLARE csr114 CURSOR FOR
2547 SELECT name FROM servers
2548 WHERE acl_type = :atype AND acl_id = :aid;
2549 EXEC SQL OPEN csr114;
2551 EXEC SQL FETCH csr114 INTO :name;
2552 if(sqlca.sqlcode != 0) break;
2553 (*action)(2, rargv, actarg);
2556 EXEC SQL CLOSE csr114;
2558 rargv[0] = "HOSTACCESS";
2559 EXEC SQL DECLARE csr115 CURSOR FOR
2560 SELECT name FROM machine, hostaccess
2561 WHERE mach_id = hostaccess.mach_id AND hostaccess.acl_type = :atype
2562 AND hostaccess.acl_id = :aid;
2563 EXEC SQL OPEN csr115;
2565 EXEC SQL FETCH csr115 INTO :name;
2566 if(sqlca.sqlcode != 0) break;
2567 (*action)(2, rargv, actarg);
2570 EXEC SQL CLOSE csr115;
2572 rargv[0] = "ZEPHYR";
2573 EXEC SQL DECLARE csr116 CURSOR FOR
2574 SELECT class FROM zephyr
2575 WHERE zephyr.xmt_type = :atype AND zephyr.xmt_id = :aid
2576 OR zephyr.sub_type = :atype AND zephyr.sub_id = :aid
2577 OR zephyr.iws_type = :atype AND zephyr.iws_id = :aid
2578 OR zephyr.iui_type = :atype AND zephyr.iui_id = :aid;
2579 EXEC SQL OPEN csr116;
2581 EXEC SQL FETCH csr116 INTO :name;
2582 if(sqlca.sqlcode != 0) break;
2583 (*action)(2, rargv, actarg);
2586 EXEC SQL CLOSE csr116;
2588 if (!found) return(MR_NO_MATCH);
2593 /* get_lists_of_member - given a type and a name, return the name and flags
2594 * of all of the lists of the given member. The member_type is one of
2595 * "LIST", "USER", "STRING", "RLIST", "RUSER", or "RSTRING" in argv[0],
2596 * and argv[1] will contain the ID of the entity in question. The R*
2597 * types mean to recursively look at every containing list, not just
2598 * when the object in question is a direct member.
2601 int get_lists_of_member(q, argv, cl, action, actarg)
2608 int found = 0, direct = 1;
2610 EXEC SQL BEGIN DECLARE SECTION;
2612 int aid, listid, id;
2613 char name[33], active[5], public[5], hidden[5], maillist[5], grouplist[5];
2614 EXEC SQL END DECLARE SECTION;
2617 aid = *(int *)argv[1];
2618 if (!strcmp(atype, "RLIST")) {
2622 if (!strcmp(atype, "RUSER")) {
2626 if (!strcmp(atype, "RSTRING")) {
2630 if (!strcmp(atype, "RKERBEROS")) {
2639 rargv[4] = maillist;
2640 rargv[5] = grouplist;
2642 EXEC SQL DECLARE csr117a CURSOR FOR
2643 SELECT name, CHAR(active), CHAR(publicflg), CHAR(hidden),
2644 CHAR(maillist), CHAR(grouplist)
2645 FROM list l, imembers m
2646 WHERE l.list_id = m.list_id AND m.direct = 1
2647 AND m.member_type = :atype AND m.member_id = :aid;
2648 EXEC SQL OPEN csr117a;
2650 EXEC SQL FETCH csr117a
2651 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2652 if(sqlca.sqlcode != 0) break;
2653 (*action)(6, rargv, actarg);
2656 EXEC SQL CLOSE csr117a;
2658 EXEC SQL DECLARE csr117b 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
2663 AND m.member_type = :atype AND m.member_id = :aid;
2664 EXEC SQL OPEN csr117b;
2666 EXEC SQL FETCH csr117b
2667 INTO :name, :active, :public, :hidden, :maillist, :grouplist;
2668 if(sqlca.sqlcode != 0) break;
2669 (*action)(6, rargv, actarg);
2672 EXEC SQL CLOSE csr117b;
2675 if (ingres_errno) return(mr_errcode);
2676 if (!found) return(MR_NO_MATCH);
2681 /* qualified_get_lists: passed "TRUE", "FALSE", or "DONTCARE" for each of
2682 * the five flags associated with each list. It will return the name of
2683 * each list that meets the quailifications. It does this by building a
2684 * where clause based on the arguments, then doing a retrieve.
2687 static char *lflags[5] = { "active", "publicflg", "hidden", "maillist", "group" };
2689 int qualified_get_lists(q, argv, cl, action, actarg)
2696 return(qualified_get(q, argv, action, actarg, "l.list_id != 0",
2697 "l", "name", lflags));
2701 /** get_members_of_list - optimized query for retrieval of list members
2704 ** argv[0] - list_id
2707 ** - retrieve USER members, then LIST members, then STRING members
2710 get_members_of_list(q, argv, cl, action, actarg)
2717 EXEC SQL BEGIN DECLARE SECTION;
2718 int list_id, member_id;
2719 char member_name[129], member_type[9];
2720 EXEC SQL END DECLARE SECTION;
2723 struct save_queue *sq;
2725 list_id = *(int *)argv[0];
2729 EXEC SQL DECLARE csr118 CURSOR FOR
2730 SELECT member_type, member_id FROM imembers
2731 WHERE list_id = :list_id AND direct=1;
2732 EXEC SQL OPEN csr118;
2734 EXEC SQL FETCH csr118 INTO :member_type, :member_id;
2735 if (sqlca.sqlcode != 0) break;
2738 sq_save_data(sq, ((int)member_type[0] << 24) | (member_id & 0xffffff));
2740 EXEC SQL CLOSE csr118;
2742 if (members <= 49) {
2743 targv[1] = malloc(0);
2744 while (sq_remove_data(sq, &member_id)) {
2745 switch (member_id >> 24) {
2748 id_to_name(member_id & 0xffffff, "USER", &targv[1]);
2749 (*action)(2, targv, actarg);
2753 id_to_name(member_id & 0xffffff, "LIST", &targv[1]);
2754 (*action)(2, targv, actarg);
2757 targv[0] = "STRING";
2758 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2759 (*action)(2, targv, actarg);
2762 targv[0] = "KERBEROS";
2763 id_to_name(member_id & 0xffffff, "STRING", &targv[1]);
2764 (*action)(2, targv, actarg);
2768 return(MR_INTERNAL);
2777 targv[1] = member_name;
2779 EXEC SQL DECLARE csr119 CURSOR FOR
2780 SELECT users.login FROM users, imembers
2781 WHERE imembers.list_id = :list_id AND imembers.member_type = 'USER'
2782 AND imembers.member_id = users.users_id AND imembers.direct=1
2784 EXEC SQL OPEN csr119;
2786 EXEC SQL FETCH csr119 INTO :member_name;
2787 if(sqlca.sqlcode != 0) break;
2788 (*action)(2, targv, actarg);
2790 EXEC SQL CLOSE csr119;
2791 if (ingres_errno) return(mr_errcode);
2794 EXEC SQL DECLARE csr120 CURSOR FOR
2795 SELECT list.name FROM list, imembers
2796 WHERE imembers.list_id = :list_id AND imembers.member_type='LIST'
2797 AND imembers.member_id = list.list_id AND imembers.direct=1
2799 EXEC SQL OPEN csr120;
2801 EXEC SQL FETCH csr120 INTO :member_name;
2802 if(sqlca.sqlcode != 0) break;
2803 (*action)(2, targv, actarg);
2805 EXEC SQL CLOSE csr120;
2806 if (ingres_errno) return(mr_errcode);
2808 targv[0] = "STRING";
2809 EXEC SQL DECLARE csr121 CURSOR FOR
2810 SELECT strings.string FROM strings, imembers
2811 WHERE imembers.list_id = :list_id AND imembers.member_type='STRING'
2812 AND imembers.member_id = strings.string_id AND imembers.direct=1
2814 EXEC SQL OPEN csr121;
2816 EXEC SQL FETCH csr121 INTO :member_name;
2817 if(sqlca.sqlcode != 0) break;
2818 (*action)(2, targv, actarg);
2820 EXEC SQL CLOSE csr121;
2821 if (ingres_errno) return(mr_errcode);
2823 targv[0] = "KERBEROS";
2824 EXEC SQL DECLARE csr122 CURSOR FOR
2825 SELECT strings.string FROM strings, imembers
2826 WHERE imembers.list_id = :list_id AND imembers.member_type='KERBEROS'
2827 AND imembers.member_id = strings.string_id AND imembers.direct=1
2829 EXEC SQL OPEN csr122;
2831 EXEC SQL FETCH csr122 INTO :member_name;
2832 if(sqlca.sqlcode != 0) break;
2833 (*action)(2, targv, actarg);
2835 EXEC SQL CLOSE csr122;
2836 if (ingres_errno) return(mr_errcode);
2842 /* count_members_of_list: this is a simple query, but it cannot be done
2843 * through the dispatch table.
2846 int count_members_of_list(q, argv, cl, action, actarg)
2853 EXEC SQL BEGIN DECLARE SECTION;
2855 EXEC SQL END DECLARE SECTION;
2856 char *rargv[1], countbuf[5];
2858 list = *(int *)argv[0];
2859 rargv[0] = countbuf;
2860 EXEC SQL REPEATED SELECT count (*) INTO :ct FROM imembers
2861 WHERE list_id = :list AND direct=1;
2862 if (ingres_errno) return(mr_errcode);
2863 sprintf(countbuf, "%d", ct);
2864 (*action)(1, rargv, actarg);
2869 /* qualified_get_server: passed "TRUE", "FALSE", or "DONTCARE" for each of
2870 * the three flags associated with each service. It will return the name of
2871 * each service that meets the quailifications. It does this by building a
2872 * where clause based on the arguments, then doing a retrieve.
2875 static char *sflags[3] = { "enable", "inprogress", "harderror" };
2877 int qualified_get_server(q, argv, cl, action, actarg)
2884 return(qualified_get(q, argv, action, actarg, "s.name != ''",
2885 "s", "name", sflags));
2889 /* generic qualified get routine, used by qualified_get_lists,
2890 * qualified_get_server, and qualified_get_serverhost.
2892 * start - a simple where clause, must not be empty
2893 * range - the name of the range variable
2894 * field - the field to return
2895 * flags - an array of strings, names of the flag variables
2898 int qualified_get(q, argv, action, actarg, start, range, field, flags)
2908 char name[33], qual[256];
2910 char *rargv[1], buf[32];
2912 strcpy(qual, start);
2913 for (i = 0; i < q->argc; i++) {
2914 if (!strcmp(argv[i], "TRUE")) {
2915 sprintf(buf, " and %s.%s != 0", range, flags[i]);
2916 (void) strcat(qual, buf);
2917 } else if (!strcmp(argv[i], "FALSE")) {
2918 sprintf(buf, " and %s.%s = 0", range, flags[i]);
2919 (void) strcat(qual, buf);
2923 rargv[0] = SQLDA->sqlvar[0].sqldata;
2924 sprintf(stmt_buf,"SELECT %s.%s FROM %s %s WHERE %s",q->rtable,field,q->rtable,q->rvar,qual);
2925 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
2927 return(MR_INTERNAL);
2928 EXEC SQL DECLARE csr123 CURSOR FOR stmt;
2929 EXEC SQL OPEN csr123;
2931 EXEC SQL FETCH csr123 USING DESCRIPTOR :SQLDA;
2932 if(sqlca.sqlcode != 0) break;
2934 (*action)(1, rargv, actarg);
2936 EXEC SQL CLOSE csr123;
2937 if (ingres_errno) return(mr_errcode);
2939 return(MR_NO_MATCH);
2944 /* qualified_get_serverhost: passed "TRUE", "FALSE", or "DONTCARE" for each of
2945 * the five flags associated with each serverhost. It will return the name of
2946 * each service and host that meets the quailifications. It does this by
2947 * building a where clause based on the arguments, then doing a retrieve.
2950 static char *shflags[6] = { "service", "enable", "override", "success",
2951 "inprogress", "hosterror" };
2953 int qualified_get_serverhost(q, argv, cl, action, actarg)
2960 EXEC SQL BEGIN DECLARE SECTION;
2961 char sname[33], mname[33], qual[256];
2962 EXEC SQL END DECLARE SECTION;
2963 char *rargv[2], buf[32];
2966 /** the uppercase() function is INGRES-specific */
2967 sprintf(qual, "machine.mach_id = serverhosts.mach_id AND \
2968 serverhosts.service = uppercase('%s')",
2970 for (i = 1; i < q->argc; i++) {
2971 if (!strcmp(argv[i], "TRUE")) {
2972 sprintf(buf, " AND serverhosts.%s != 0", shflags[i]);
2974 } else if (!strcmp(argv[i], "FALSE")) {
2975 sprintf(buf, " AND serverhosts.%s = 0", shflags[i]);
2982 EXEC SQL DECLARE csr124 CURSOR FOR
2983 SELECT serverhosts.service, machine.name FROM serverhosts, machine
2985 EXEC SQL OPEN csr124;
2987 EXEC SQL FETCH csr124 INTO :sname, :mname;
2988 if(sqlca.sqlcode != 0) break;
2990 (*action)(2, rargv, actarg);
2992 EXEC SQL CLOSE csr124;
2994 if (ingres_errno) return(mr_errcode);
2996 return(MR_NO_MATCH);
3001 /* register_user - change user's login name and allocate a pobox, group,
3002 * filesystem, and quota for them. The user's status must start out as 0,
3003 * and is left as 2. Arguments are: user's UID, new login name, and user's
3004 * type for filesystem allocation (MR_FS_STUDENT, MR_FS_FACULTY,
3005 * MR_FS_STAFF, MR_FS_MISC).
3008 register_user(q, argv, cl)
3013 EXEC SQL BEGIN DECLARE SECTION;
3014 char *login, dir[65], *entity, *directory, machname[33];
3015 int who, rowcount, mid, uid, users_id, flag, utype, nid, list_id, quota;
3016 int size, alloc, pid, m_id, ostatus, nstatus, gidval, fsidval, npidval;
3017 EXEC SQL END DECLARE SECTION;
3018 char buffer[256], *aargv[3];
3021 entity = cl->entity;
3022 who = cl->client_id;
3024 uid = atoi(argv[0]);
3026 utype = atoi(argv[2]);
3029 EXEC SQL REPEATED SELECT users_id, status INTO :users_id, :ostatus
3031 WHERE uid = :uid AND (status=0 OR status=5 OR status=6);
3033 if (sqlca.sqlerrd[2] == 0)
3034 return(MR_NO_MATCH);
3035 if (sqlca.sqlerrd[2] > 1)
3036 return(MR_NOT_UNIQUE);
3038 /* check new login name */
3039 EXEC SQL REPEATED SELECT login INTO :cdummy FROM users
3040 WHERE login = LEFT(:login,SIZE(login)) AND users_id != :users_id;
3041 if (ingres_errno) return(mr_errcode);
3042 if (sqlca.sqlerrd[2] > 0) return(MR_IN_USE);
3043 EXEC SQL REPEATED SELECT name INTO :cdummy FROM list
3044 WHERE name = LEFT(:login,SIZE(name));
3045 if (ingres_errno) return(mr_errcode);
3046 if (sqlca.sqlerrd[2] > 0) return(MR_IN_USE);
3047 EXEC SQL REPEATED SELECT label INTO :cdummy FROM filesys
3048 WHERE label = LEFT(:login,SIZE(label));
3049 if (ingres_errno) return(mr_errcode);
3050 if (sqlca.sqlerrd[2] > 0) return(MR_IN_USE);
3051 com_err(whoami, 0, "login name OK");
3053 /* choose place for pobox, put in mid */
3054 EXEC SQL DECLARE csr130 CURSOR FOR
3055 SELECT sh.mach_id, m.name FROM serverhosts sh, machine m
3056 WHERE sh.service='POP' AND sh.mach_id=m.mach_id
3057 AND sh.value2 - sh.value1 =
3058 (SELECT MAX(value2 - value1) FROM serverhosts
3059 WHERE service = 'POP');
3060 EXEC SQL OPEN csr130;
3061 EXEC SQL FETCH csr130 INTO :mid, :machname;
3062 if (sqlca.sqlerrd[2] == 0) {
3063 EXEC SQL CLOSE csr130;
3064 if (ingres_errno) return(mr_errcode);
3065 return(MR_NO_POBOX);
3067 EXEC SQL CLOSE csr130;
3068 if (ingres_errno) return(mr_errcode);
3071 /* change login name, set pobox */
3072 sprintf(buffer, "users.users_id = %d", users_id);
3073 incremental_before("users", buffer, 0);
3075 if (ostatus == 5 || ostatus == 6)
3077 EXEC SQL REPEATED UPDATE users SET login = :login, status = :nstatus,
3078 modtime='now', modby = :who, modwith = :entity, potype='POP',
3079 pop_id = :mid, pmodtime='now', pmodby = :who, pmodwith = :entity
3080 WHERE users_id = :users_id;
3082 if (ingres_errno) return(mr_errcode);
3083 if (sqlca.sqlerrd[2] != 1)
3084 return(MR_INTERNAL);
3085 set_pop_usage(mid, 1);
3086 com_err(whoami, 0, "set login name to %s and pobox to %s", login,
3088 incremental_after("users", buffer, 0);
3090 /* create group list */
3091 if (set_next_object_id("gid", "list", 1))
3093 if (set_next_object_id("list_id", "list", 0))
3095 EXEC SQL REPEATED SELECT value INTO :list_id FROM numvalues
3096 WHERE name='list_id';
3097 if (ingres_errno) return(mr_errcode);
3098 if (sqlca.sqlerrd[2] != 1)
3099 return(MR_INTERNAL);
3100 incremental_clear_before();
3101 EXEC SQL SELECT value INTO :gidval FROM numvalues WHERE name = 'gid';
3102 EXEC SQL REPEATED INSERT INTO list
3103 (name, list_id, active, publicflg, hidden, maillist, grouplist,
3104 gid, description, acl_type, acl_id,
3105 modtime, modby, modwith)
3106 VALUES (:login, :list_id, 1, 0, 0, 0, 1,
3107 :gidval, 'User Group', 'USER', :users_id,
3108 'now', :who, :entity);
3109 if (ingres_errno) return(mr_errcode);
3110 if (sqlca.sqlerrd[2] != 1)
3111 return(MR_INTERNAL);
3112 sprintf(buffer, "list_id = %d", list_id);
3113 incremental_after("list", buffer, 0);
3114 aargv[0] = (char *) list_id;
3116 aargv[2] = (char *) users_id;
3117 incremental_clear_before();
3118 EXEC SQL REPEATED INSERT INTO imembers
3119 (list_id, member_type, member_id, ref_count, direct)
3120 VALUES (:list_id, 'USER', :users_id, 1, 1);
3121 if (ingres_errno) return(mr_errcode);
3122 if (sqlca.sqlerrd[2] != 1)
3123 return(MR_INTERNAL);
3124 incremental_after("members", 0, aargv);
3126 /* decide where to put filesystem */
3129 EXEC SQL DECLARE csr125 CURSOR FOR
3130 SELECT mach_id, trim(dir), nfsphys_id, status, partsize, allocated
3132 EXEC SQL OPEN csr125;
3134 EXEC SQL FETCH csr125 INTO :mid, :dir, :nid, :flag, :size, :alloc;
3137 if ((flag & utype) && (size != 0) && (size - alloc > maxsize)) {
3138 maxsize = size - alloc;
3141 directory = strsave(dir);
3146 EXEC SQL CLOSE csr125;
3147 if (ingres_errno) return(mr_errcode);
3149 return(MR_NO_FILESYS);
3151 /* create filesystem */
3152 if (set_next_object_id("filsys_id", "filesys", 0))
3154 incremental_clear_before();
3155 EXEC SQL SELECT value INTO :fsidval FROM numvalues
3156 WHERE numvalues.name='filsys_id';
3157 EXEC SQL REPEATED INSERT INTO filesys
3158 (filsys_id, phys_id, label, type, mach_id, name,
3159 mount, access, comments, owner, owners, createflg,
3160 lockertype, modtime, modby, modwith)
3162 (:fsidval, :pid, :login, 'NFS', :m_id, :directory+'/'+:login,
3163 '/mit/'+:login, 'w', 'User Locker', :users_id, :list_id, 1,
3164 'HOMEDIR', 'now', :who, :entity) ;
3165 if (ingres_errno) return(mr_errcode);
3166 if (sqlca.sqlerrd[2] != 1)
3167 return(MR_INTERNAL);
3168 sprintf(buffer,"fs.filsys_id = %d",fsidval);
3169 incremental_after("filesys", buffer, 0);
3170 com_err(whoami, 0, "filesys on mach %d in %s/%s", m_id,
3174 EXEC SQL REPEATED SELECT value INTO :quota FROM numvalues
3175 WHERE name='def_quota';
3176 if (ingres_errno) return(mr_errcode);
3177 if (sqlca.sqlerrd[2] != 1)
3178 return(MR_NO_QUOTA);
3179 incremental_clear_before();
3180 EXEC SQL REPEATED INSERT INTO quota
3181 (entity_id, filsys_id, type, quota, phys_id, modtime, modby, modwith)
3183 (:users_id, :fsidval, 'USER', :quota, :pid, 'now', :who, :entity);
3184 if (ingres_errno) return(mr_errcode);
3185 if (sqlca.sqlerrd[2] != 1)
3186 return(MR_INTERNAL);
3187 EXEC SQL SELECT phys_id INTO :npidval FROM filesys
3188 WHERE filsys_id=:fsidval;
3189 EXEC SQL REPEATED UPDATE nfsphys SET allocated=allocated + :quota
3190 WHERE nfsphys.nfsphys_id = :npidval;
3191 if (ingres_errno) return(mr_errcode);
3192 if (sqlca.sqlerrd[2] != 1)
3193 return(MR_INTERNAL);
3197 sprintf(buffer, "q.entity_id = %d and q.filsys_id = %d and q.type = 'USER'", users_id, fsidval);
3198 incremental_after("quota", buffer, aargv);
3199 com_err(whoami, 0, "quota of %d assigned", quota);
3200 if (ingres_errno) return(mr_errcode);
3202 cache_entry(login, "USER", users_id);
3204 EXEC SQL REPEATED UPDATE tblstats SET updates=updates+1, modtime='now'
3205 WHERE table_name='users';
3206 EXEC SQL REPEATED UPDATE tblstats SET appends=appends+1, modtime='now'
3207 WHERE table_name='list' OR table_name='filesys' OR table_name='quota';
3208 if (ingres_errno) return(mr_errcode);
3214 /** set_pop_usage - incr/decr usage count for pop server in serverhosts talbe
3218 ** delta (will be +/- 1)
3221 ** - incr/decr value field in serverhosts table for pop/mach_id
3225 static int set_pop_usage(id, cnt)
3226 EXEC SQL BEGIN DECLARE SECTION;
3229 EXEC SQL END DECLARE SECTION;
3231 EXEC SQL REPEATED UPDATE serverhosts SET value1 = value1 + :cnt
3232 WHERE serverhosts.service = 'POP' AND serverhosts.mach_id = :id;
3234 if (ingres_errno) return(mr_errcode);
3240 /* Validation Routines */
3242 validate_row(q, argv, v)
3243 register struct query *q;
3245 register struct validate *v;
3247 EXEC SQL BEGIN DECLARE SECTION;
3251 EXEC SQL END DECLARE SECTION;
3253 /* build where clause */
3254 build_qual(v->qual, v->argc, argv, qual);
3256 if (log_flags & LOG_VALID)
3257 /* tell the logfile what we're doing */
3258 com_err(whoami, 0, "validating row: %s", qual);
3260 /* look for the record */
3261 sprintf(stmt_buf,"SELECT COUNT (*) FROM %s WHERE %s",q->rtable,qual);
3262 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3264 return(MR_INTERNAL);
3265 EXEC SQL DECLARE csr126 CURSOR FOR stmt;
3266 EXEC SQL OPEN csr126;
3267 EXEC SQL FETCH csr126 USING DESCRIPTOR :SQLDA;
3268 EXEC SQL CLOSE csr126;
3269 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3271 if (ingres_errno) return(mr_errcode);
3272 if (rowcount == 0) return(MR_NO_MATCH);
3273 if (rowcount > 1) return(MR_NOT_UNIQUE);
3277 validate_fields(q, argv, vo, n)
3279 register char *argv[];
3280 register struct valobj *vo;
3283 register int status;
3288 if (log_flags & LOG_VALID)
3289 com_err(whoami, 0, "validating %s in %s: %s",
3290 vo->namefield, vo->table, argv[vo->index]);
3291 status = validate_name(argv, vo);
3295 if (log_flags & LOG_VALID)
3296 com_err(whoami, 0, "validating %s in %s: %s",
3297 vo->idfield, vo->table, argv[vo->index]);
3298 status = validate_id(q, argv, vo);
3302 if (log_flags & LOG_VALID)
3303 com_err(whoami, 0, "validating date: %s", argv[vo->index]);
3304 status = validate_date(argv, vo);
3308 if (log_flags & LOG_VALID)
3309 com_err(whoami, 0, "validating %s type: %s",
3310 vo->table, argv[vo->index]);
3311 status = validate_type(argv, vo);
3315 if (log_flags & LOG_VALID)
3316 com_err(whoami, 0, "validating typed data (%s): %s",
3317 argv[vo->index - 1], argv[vo->index]);
3318 status = validate_typedata(q, argv, vo);
3322 if (log_flags & LOG_VALID)
3323 com_err(whoami, 0, "validating rename %s in %s",
3324 argv[vo->index], vo->table);
3325 status = validate_rename(argv, vo);
3329 if (log_flags & LOG_VALID)
3330 com_err(whoami, 0, "validating chars: %s", argv[vo->index]);
3331 status = validate_chars(argv[vo->index]);
3339 status = lock_table(vo);
3343 status = convert_wildcards(argv[vo->index]);
3347 status = convert_wildcards_uppercase(argv[vo->index]);
3352 if (status != MR_EXISTS) return(status);
3356 if (ingres_errno) return(mr_errcode);
3361 /* validate_chars: verify that there are no illegal characters in
3362 * the string. Legal characters are printing chars other than
3363 * ", *, ?, \, [ and ].
3365 static int illegalchars[] = {
3366 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^@ - ^O */
3367 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* ^P - ^_ */
3368 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, /* SPACE - / */
3369 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* 0 - ? */
3370 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* : - O */
3371 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* P - _ */
3372 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ` - o */
3373 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /* p - ^? */
3374 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3375 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3376 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3377 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3378 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
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,
3388 if (illegalchars[*s++])
3389 return(MR_BAD_CHAR);
3394 validate_id(q, argv, vo)
3397 register struct valobj *vo;
3399 EXEC SQL BEGIN DECLARE SECTION;
3400 char *name, *tbl, *namefield, *idfield;
3402 EXEC SQL END DECLARE SECTION;
3406 name = argv[vo->index];
3408 namefield = vo->namefield;
3409 idfield = vo->idfield;
3411 if ((!strcmp(tbl, "users") && !strcmp(namefield, "login")) ||
3412 !strcmp(tbl, "machine") ||
3413 !strcmp(tbl, "filesys") ||
3414 !strcmp(tbl, "list") ||
3415 !strcmp(tbl, "cluster") ||
3416 !strcmp(tbl, "strings")) {
3417 if (!strcmp(tbl, "machine"))
3418 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3419 status = name_to_id(name, tbl, &id);
3421 *(int *)argv[vo->index] = id;
3423 } else if (status == MR_NO_MATCH && !strcmp(tbl, "strings") &&
3424 (q->type == APPEND || q->type == UPDATE)) {
3425 EXEC SQL SELECT value INTO :id FROM numvalues
3426 WHERE name = 'strings_id';
3428 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'string_id';
3429 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3430 cache_entry(name, "STRING", id);
3431 *(int *)argv[vo->index] = id;
3433 } else if (status == MR_NO_MATCH || status == MR_NOT_UNIQUE)
3439 if (!strcmp(namefield, "uid")) {
3440 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = %s",idfield,tbl,namefield,name);
3442 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = '%s'",idfield,tbl,namefield,name);
3444 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3446 return(MR_INTERNAL);
3447 EXEC SQL DECLARE csr127 CURSOR FOR stmt;
3448 EXEC SQL OPEN csr127;
3450 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3451 if(sqlca.sqlcode == 0) {
3453 EXEC SQL FETCH csr127 USING DESCRIPTOR :SQLDA;
3454 if(sqlca.sqlcode == 0) rowcount++;
3456 EXEC SQL CLOSE csr127;
3460 if (rowcount != 1) return(vo->error);
3461 bcopy(SQLDA->sqlvar[0].sqldata,argv[vo->index],sizeof(int));
3465 validate_name(argv, vo)
3467 register struct valobj *vo;
3469 EXEC SQL BEGIN DECLARE SECTION;
3470 char *name, *tbl, *namefield;
3472 EXEC SQL END DECLARE SECTION;
3475 name = argv[vo->index];
3477 namefield = vo->namefield;
3478 if (!strcmp(tbl, "servers") && !strcmp(namefield, "name")) {
3479 for (c = name; *c; c++)
3483 sprintf(stmt_buf,"SELECT DISTINCT COUNT(*) FROM %s WHERE %s.%s = '%s'",
3484 tbl,tbl,namefield,name);
3485 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3487 return(MR_INTERNAL);
3488 EXEC SQL DECLARE csr128 CURSOR FOR stmt;
3489 EXEC SQL OPEN csr128;
3490 EXEC SQL FETCH csr128 USING DESCRIPTOR :SQLDA;
3491 rowcount = *(int *)SQLDA->sqlvar[0].sqldata;
3492 EXEC SQL CLOSE csr128;
3494 if (ingres_errno) return(mr_errcode);
3495 return ((rowcount == 1) ? MR_EXISTS : vo->error);
3498 validate_date(argv, vo)
3502 EXEC SQL BEGIN DECLARE SECTION;
3506 EXEC SQL END DECLARE SECTION;
3508 idate = argv[vo->index];
3509 EXEC SQL SELECT interval('years',date(:idate)-date('today')) INTO :dd;
3511 if (sqlca.sqlcode != 0 || dd > 5.0) return(MR_DATE);
3516 validate_rename(argv, vo)
3520 EXEC SQL BEGIN DECLARE SECTION;
3521 char *name, *tbl, *namefield, *idfield;
3523 EXEC SQL END DECLARE SECTION;
3527 c = name = argv[vo->index];
3529 if (illegalchars[*c++])
3530 return(MR_BAD_CHAR);
3532 /* minor kludge to upcasify machine names */
3533 if (!strcmp(tbl, "machine"))
3534 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3535 namefield = vo->namefield;
3536 idfield = vo->idfield;
3539 if (!strcmp(argv[vo->index], argv[vo->index - 1]))
3541 sprintf(stmt_buf,"SELECT %s FROM %s WHERE %s = LEFT('%s',SIZE(%s))",
3542 namefield,tbl,namefield,name,namefield);
3543 EXEC SQL PREPARE stmt INTO :SQLDA USING NAMES FROM :stmt_buf;
3545 return(MR_INTERNAL);
3546 EXEC SQL DECLARE csr129 CURSOR FOR stmt;
3547 EXEC SQL OPEN csr129;
3548 EXEC SQL FETCH csr129 USING DESCRIPTOR :SQLDA;
3549 if(sqlca.sqlcode == 0) id=1; else id=0;
3550 EXEC SQL CLOSE csr129;
3552 if (ingres_errno) return(mr_errcode);
3558 status = name_to_id(name, tbl, &id);
3559 if (status == MR_NO_MATCH || id == *(int *)argv[vo->index - 1])
3566 validate_type(argv, vo)
3568 register struct valobj *vo;
3570 EXEC SQL BEGIN DECLARE SECTION;
3573 EXEC SQL END DECLARE SECTION;
3576 typename = vo->table;
3577 c = val = argv[vo->index];
3579 if (illegalchars[*c++])
3580 return(MR_BAD_CHAR);
3583 /* uppercase type fields */
3584 for (c = val; *c; c++) if (islower(*c)) *c = toupper(*c);
3586 EXEC SQL SELECT trans INTO :cdummy FROM alias
3587 WHERE name = :typename AND type='TYPE' AND trans = :val;
3588 if (ingres_errno) return(mr_errcode);
3589 return (sqlca.sqlerrd[2] ? MR_EXISTS : vo->error);
3592 /* validate member or type-specific data field */
3594 validate_typedata(q, argv, vo)
3595 register struct query *q;
3596 register char *argv[];
3597 register struct valobj *vo;
3599 EXEC SQL BEGIN DECLARE SECTION;
3602 char data_type[129];
3604 EXEC SQL END DECLARE SECTION;
3609 /* get named object */
3610 name = argv[vo->index];
3612 /* get field type string (known to be at index-1) */
3613 field_type = argv[vo->index-1];
3615 /* get corresponding data type associated with field type name */
3616 EXEC SQL SELECT trans INTO :data_type FROM alias
3617 WHERE name = :field_type AND type='TYPEDATA';
3618 if (ingres_errno) return(mr_errcode);
3619 if (sqlca.sqlerrd[2] != 1) return(MR_TYPE);
3621 /* now retrieve the record id corresponding to the named object */
3622 if (index(data_type, ' '))
3623 *index(data_type, ' ') = 0;
3624 if (!strcmp(data_type, "user")) {
3626 status = name_to_id(name, data_type, &id);
3627 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3629 if (status) return(status);
3630 } else if (!strcmp(data_type, "list")) {
3632 status = name_to_id(name, data_type, &id);
3633 if (status && status == MR_NOT_UNIQUE)
3635 if (status == MR_NO_MATCH) {
3636 /* if idfield is non-zero, then if argv[0] matches the string
3637 * that we're trying to resolve, we should get the value of
3638 * numvalues.[idfield] for the id.
3640 if (vo->idfield && !strcmp(argv[0], argv[vo->index])) {
3641 set_next_object_id(q->validate->object_id, q->rtable, 0);
3643 EXEC SQL REPEATED SELECT value INTO :id FROM numvalues
3645 if (sqlca.sqlerrd[2] != 1) return(MR_LIST);
3648 } else if (status) return(status);
3649 } else if (!strcmp(data_type, "machine")) {
3651 for (c = name; *c; c++) if (islower(*c)) *c = toupper(*c);
3652 status = name_to_id(name, data_type, &id);
3653 if (status && (status == MR_NO_MATCH || status == MR_NOT_UNIQUE))
3655 if (status) return(status);
3656 } else if (!strcmp(data_type, "string")) {
3658 status = name_to_id(name, data_type, &id);
3659 if (status && status == MR_NOT_UNIQUE)
3661 if (status == MR_NO_MATCH) {
3662 if (q->type != APPEND && q->type != UPDATE) return(MR_STRING);
3663 EXEC SQL SELECT value INTO :id FROM numvalues WHERE name = 'strings_id';
3665 EXEC SQL UPDATE numvalues SET value = :id WHERE name = 'strings_id';
3666 EXEC SQL INSERT INTO strings (string_id, string) VALUES (:id, :name);
3667 cache_entry(name, "STRING", id);
3668 } else if (status) return(status);
3669 } else if (!strcmp(data_type, "none")) {
3675 /* now set value in argv */
3676 *(int *)argv[vo->index] = id;
3682 /* Lock the table named by the validation object */
3687 sprintf(stmt_buf,"UPDATE %s SET modtime='now' WHERE %s.%s = 0",
3688 vo->table,vo->table,vo->idfield);
3689 EXEC SQL EXECUTE IMMEDIATE :stmt_buf;
3690 if (ingres_errno) return(mr_errcode);
3691 if (sqlca.sqlerrd[2] != 1)
3698 /* Check the database at startup time. For now this just resets the
3699 * inprogress flags that the DCM uses.
3702 sanity_check_database()
3707 /* Dynamic SQL support routines */
3708 MR_SQLDA_T *mr_alloc_SQLDA()
3711 short *null_indicators;
3714 if((it=(MR_SQLDA_T *)malloc(sizeof(MR_SQLDA_T)))==NULL) {
3715 com_err(whoami, MR_NO_MEM, "setting up SQLDA");
3719 if((null_indicators=(short *)calloc(QMAXARGS,sizeof(short)))==NULL) {
3720 com_err(whoami, MR_NO_MEM, "setting up SQLDA null indicators");
3724 for(j=0; j<QMAXARGS; j++) {
3725 if((it->sqlvar[j].sqldata=malloc(sizeof(short)+QMAXARGSIZE))==NULL) {
3726 com_err(whoami, MR_NO_MEM, "setting up SQLDA variables");
3729 it->sqlvar[j].sqllen=QMAXARGSIZE;
3730 it->sqlvar[j].sqlind=null_indicators+j;
3731 null_indicators[j]=0;
3738 /* Use this after FETCH USING DESCRIPTOR one or more
3739 * result columns may contain NULLs. This routine is
3740 * not currently needed, since db/schema creates all
3741 * columns with a NOT NULL WITH DEFAULT clause.
3743 * This is currently dead flesh, since no Moira columns
3744 * allow null values; all use default values.
3746 mr_fix_nulls_in_SQLDA(da)
3749 register IISQLVAR *var;
3753 for(j=0, var=da->sqlvar; j<da->sqld; j++, var++) {
3754 switch(var->sqltype) {
3755 case -IISQ_CHA_TYPE:
3759 case -IISQ_INT_TYPE:
3761 intp=(int *)var->sqldata;
3769 /* prefetch_value():
3770 * This routine fetches an appropriate value from the numvalues table.
3771 * It is a little hack to get around the fact that SQL doesn't let you
3772 * do something like INSERT INTO table (foo) VALUES (other_table.bar).
3774 * It is called from the query table as (*v->pre_rtn)(q,Argv,cl) or
3775 * from within a setup_...() routine with the appropriate arguments.
3777 * Correct functioning of this routine may depend on the assumption
3778 * that this query is an APPEND.
3781 prefetch_value(q,argv,cl)
3786 EXEC SQL BEGIN DECLARE SECTION;
3787 char *name = q->validate->object_id;
3789 EXEC SQL END DECLARE SECTION;
3790 int status, limit, argc;
3792 /* set next object id, limiting it if necessary */
3793 if(!strcmp(name, "uid") || !strcmp(name, "gid"))
3794 limit = 1; /* So far as I know, this isn't needed. Just CMA. */
3797 if((status = set_next_object_id(name, q->rtable, limit)) != MR_SUCCESS)
3800 /* fetch object id */
3801 EXEC SQL SELECT value INTO :value FROM numvalues WHERE name=:name;
3802 if(ingres_errno) return(mr_errcode);
3803 if(sqlca.sqlerrd[2] != 1) return(MR_INTERNAL);
3805 argc = q->argc + q->vcnt; /* end of Argv for APPENDs */
3806 sprintf(argv[argc],"%d",value);
3811 /* prefetch_filesys():
3812 * Fetches the phys_id from filesys based on the filsys_id in argv[0].
3813 * Appends the filsys_id and the phys_id to the argv so they can be
3814 * referenced in an INSERT into a table other than filesys. Also
3815 * see comments at prefetch_value().
3817 * Assumes the existence of a row where filsys_id = argv[0], since a
3818 * filesys label has already been resolved to a filsys_id.
3820 prefetch_filesys(q,argv,cl)
3825 EXEC SQL BEGIN DECLARE SECTION;
3827 EXEC SQL END DECLARE SECTION;
3830 fid = *(int *)argv[0];
3831 EXEC SQL SELECT phys_id INTO :phid FROM filesys WHERE filsys_id = :fid;
3832 if(ingres_errno) return(mr_errcode);
3834 argc=q->argc+q->vcnt;
3835 sprintf(argv[argc++],"%d",fid);
3836 sprintf(argv[argc],"%d",phid);
3841 /* Convert normal Unix-style wildcards to SQL voodoo */
3842 convert_wildcards(arg)
3845 static char buffer[QMAXARGSIZE];
3846 register char *s, *d;
3848 for(d=buffer,s=arg;*s;s++) {
3850 case '*': *d++='%'; *d++='%'; break;
3851 case '?': *d++='_'; break;
3854 case ']': *d++='*'; *d++ = *s; break;
3855 case '%': *d++='*'; *d++='%'; *d++='%'; break;
3856 default: *d++ = *s; break;
3861 /* Copy back into argv */
3867 /* This version includes uppercase conversion, for things like gmac.
3868 * This is necessary because "LIKE" doesn't work with "uppercase()".
3869 * Including it in a wildcard routine saves making two passes over
3870 * the argument string.
3872 convert_wildcards_uppercase(arg)
3875 static char buffer[QMAXARGSIZE];
3876 register char *s, *d;
3878 for(d=buffer,s=arg;*s;s++) {
3880 case '*': *d++='%'; *d++='%'; break;
3881 case '?': *d++='_'; break;
3884 case ']': *d++='*'; *d++ = *s; break;
3885 case '%': *d++='*'; *d++='%'; *d++='%'; break;
3886 default: *d++=toupper(*s); break; /* This is the only diff. */
3891 /* Copy back into argv */
3897 /* eof:qsupport.dc */