/* $Id$ * * Check access to queries * * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology * For copying and distribution information, please see the file * . */ #include #include "mr_server.h" #include "qrtn.h" #include "query.h" #include #include EXEC SQL INCLUDE sqlca; RCSID("$Header$"); extern char *whoami; extern int dbms_errno, mr_errcode; EXEC SQL BEGIN DECLARE SECTION; extern char stmt_buf[]; EXEC SQL END DECLARE SECTION; EXEC SQL WHENEVER SQLERROR DO dbmserr(); /* Specialized Access Routines */ /* access_user - verify that client name equals specified login name * * - since field validation routines are called first, a users_id is * now in argv[0] instead of the login name. */ int access_user(struct query *q, char *argv[], client *cl) { if (cl->users_id != *(int *)argv[0]) return MR_PERM; else return MR_SUCCESS; } /* access_login - verify that client name equals specified login name * * argv[0...n] contain search info. q-> */ int access_login(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; int id; EXEC SQL END DECLARE SECTION; if (q->argc != 1) return MR_ARGS; if (!strcmp(q->shortname, "gual")) { EXEC SQL SELECT users_id INTO :id FROM users WHERE login LIKE :argv[0] AND users_id != 0; } else if (!strcmp(q->shortname, "gubl")) { EXEC SQL SELECT users_id INTO :id FROM users u WHERE u.login LIKE :argv[0] AND u.users_id != 0; } else if (!strcmp(q->shortname, "guau")) { EXEC SQL SELECT users_id INTO :id FROM users WHERE unix_uid = :argv[0] AND users_id != 0; } else if (!strcmp(q->shortname, "gubu")) { EXEC SQL SELECT users_id INTO :id FROM users u WHERE u.unix_uid = :argv[0] AND u.users_id != 0; } if (sqlca.sqlcode == SQL_NO_MATCH) return MR_NO_MATCH; /* ought to be MR_USER, but this is what gual returns, so we have to be consistent */ else if (sqlca.sqlerrd[2] != 1 || id != cl->users_id) return MR_PERM; else return MR_SUCCESS; } /* access_list - check access for most list operations * * Inputs: argv[0] - list_id * q - query name * argv[2] - member ID (only for queries "amtl" and "dmfl") * argv[7] - group IID (only for query "ulis") * cl - client name * * - check that client is a member of the access control list * - OR, if the query is add_member_to_list or delete_member_from_list * and the list is public, allow access if client = member */ int access_list(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; int list_id, acl_id, flags, gid, users_id; char acl_type[9], name[33], *newname; EXEC SQL END DECLARE SECTION; int status; list_id = *(int *)argv[0]; EXEC SQL SELECT acl_id, acl_type, gid, publicflg, name INTO :acl_id, :acl_type, :gid, :flags, :name FROM list WHERE list_id = :list_id; if (sqlca.sqlerrd[2] != 1) return MR_INTERNAL; /* if amtl or dmfl and list is public allow client to add or delete self */ if (((!strcmp("amtl", q->shortname) && flags) || (!strcmp("dmfl", q->shortname)))) { if (!strcmp("USER", argv[1]) && *(int *)argv[2] == cl->users_id) return MR_SUCCESS; if (!strcmp("KERBEROS", argv[1]) && *(int *)argv[2] == -cl->client_id) return MR_SUCCESS; } /* if update_list, don't allow them to change the GID or rename to a username other than their own */ else if (!strcmp("ulis", q->shortname)) { if (!strcmp(argv[7], UNIQUE_GID)) { if (gid != -1) return MR_PERM; } else { if (gid != atoi(argv[7])) return MR_PERM; } newname = argv[1]; EXEC SQL SELECT users_id INTO :users_id FROM users WHERE login = :newname; if ((sqlca.sqlcode != SQL_NO_MATCH) && strcmp(strtrim(name), newname) && (users_id != cl->users_id)) return MR_PERM; } /* check for client in access control list */ status = find_member(acl_type, acl_id, cl); if (!status) return MR_PERM; return MR_SUCCESS; } /* access_visible_list - allow access to list only if it is not hidden, * or if the client is on the ACL * * Inputs: argv[0] - list_id * cl - client identifier */ int access_visible_list(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; int list_id, acl_id, flags ; char acl_type[9]; EXEC SQL END DECLARE SECTION; int status; list_id = *(int *)argv[0]; EXEC SQL SELECT hidden, acl_id, acl_type INTO :flags, :acl_id, :acl_type FROM list WHERE list_id = :list_id; if (sqlca.sqlerrd[2] != 1) return MR_INTERNAL; if (!flags) return MR_SUCCESS; /* check for client in access control list */ status = find_member(acl_type, acl_id, cl); if (!status) return MR_PERM; return MR_SUCCESS; } /* access_vis_list_by_name - allow access to list only if it is not hidden, * or if the client is on the ACL * * Inputs: argv[0] - list name * cl - client identifier */ int access_vis_list_by_name(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; int acl_id, flags, rowcount; char acl_type[9], *listname; EXEC SQL END DECLARE SECTION; int status; listname = argv[0]; EXEC SQL SELECT hidden, acl_id, acl_type INTO :flags, :acl_id, :acl_type FROM list WHERE name = :listname; rowcount = sqlca.sqlerrd[2]; if (rowcount > 1) return MR_WILDCARD; if (rowcount == 0) return MR_NO_MATCH; if (!flags) return MR_SUCCESS; /* check for client in access control list */ status = find_member(acl_type, acl_id, cl); if (!status) return MR_PERM; return MR_SUCCESS; } /* access_member - allow user to access member of type "USER" and name matches * username, or to access member of type "KERBEROS" and the principal matches * the user, or to access member of type "LIST" and list is one that user is * on the acl of, or the list is visible. */ int access_member(struct query *q, char *argv[], client *cl) { if (!strcmp(argv[0], "LIST") || !strcmp(argv[0], "RLIST")) return access_visible_list(q, &argv[1], cl); if (!strcmp(argv[0], "USER") || !strcmp(argv[0], "RUSER")) { if (cl->users_id == *(int *)argv[1]) return MR_SUCCESS; } if (!strcmp(argv[0], "KERBEROS") || !strcmp(argv[0], "RKERBEROS")) { if (cl->client_id == -*(int *)argv[1]) return MR_SUCCESS; } return MR_PERM; } /* access_qgli - special access routine for Qualified_get_lists. Allows * access iff argv[0] == "TRUE" and argv[2] == "FALSE". */ int access_qgli(struct query *q, char *argv[], client *cl) { if (!strcmp(argv[0], "TRUE") && !strcmp(argv[2], "FALSE")) return MR_SUCCESS; return MR_PERM; } /* access_service - allow access if user is on ACL of service. Don't * allow access if a wildcard is used. */ int access_service(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; int acl_id; char *name, acl_type[9]; EXEC SQL END DECLARE SECTION; int status; char *c; name = argv[0]; for (c = name; *c; c++) { if (islower(*c)) *c = toupper(*c); } EXEC SQL SELECT acl_id, acl_type INTO :acl_id, :acl_type FROM servers WHERE name = :name; if (sqlca.sqlerrd[2] > 1) return MR_PERM; /* check for client in access control list */ status = find_member(acl_type, acl_id, cl); if (!status) return MR_PERM; return MR_SUCCESS; } /* access_filesys - verify that client is owner or on owners list of filesystem * named by argv[0] */ int access_filesys(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; int users_id, list_id; char *name; EXEC SQL END DECLARE SECTION; int status; name = argv[0]; EXEC SQL SELECT owner, owners INTO :users_id, :list_id FROM filesys WHERE label = :name; if (sqlca.sqlerrd[2] != 1) return MR_PERM; if (users_id == cl->users_id) return MR_SUCCESS; status = find_member("LIST", list_id, cl); if (status) return MR_SUCCESS; else return MR_PERM; } /* access_host - successful if owner of host, or subnet containing host */ int access_host(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; int mid, sid, id; char mtype[9], stype[9]; EXEC SQL END DECLARE SECTION; int status; if (q->type == RETRIEVE) { if (strcmp(argv[0], "*") || strcmp(argv[1], "*") || strcmp(argv[2], "*") || strcmp(argv[3], "*")) return MR_SUCCESS; else return MR_PERM; } if (q->type == APPEND) { /* Non-query owner must set use to zero */ if (atoi(argv[6]) != 0) return MR_PERM; id = *(int *)argv[8]; EXEC SQL SELECT s.owner_type, s.owner_id INTO :stype, :sid FROM subnet s WHERE s.snet_id = :id; mid = 0; if (find_member(stype, sid, cl)) return MR_SUCCESS; else return MR_PERM; } else /* q-type == UPDATE */ { EXEC SQL BEGIN DECLARE SECTION; int status, acomment, use, ocomment, snid; char contact[33], address[33]; EXEC SQL END DECLARE SECTION; id = *(int *)argv[0]; EXEC SQL SELECT m.use, m.contact, m.status, m.address, m.owner_type, m.owner_id, m.acomment, m.ocomment, m.snet_id, s.owner_type, s.owner_id INTO :use, :contact, :status, :address, :mtype, :mid, :acomment, :ocomment, :snid, :stype, :sid FROM machine m, subnet s WHERE m.mach_id = :id AND s.snet_id = m.snet_id; if (dbms_errno) return mr_errcode; /* non-query-owner cannot change use or ocomment */ if ((use != atoi(argv[7])) || (ocomment != *(int *)argv[14])) return MR_PERM; if (!find_member(stype, sid, cl)) { if (find_member(mtype, mid, cl)) { /* host owner also cannot change contact, status, address, owner, or acomment */ if (strcmp(argv[6], strtrim(contact)) || (status != atoi(argv[8])) || strcmp(argv[10], strtrim(address)) || strcmp(argv[11], strtrim(mtype)) || (mid != *(int *)argv[12]) || (acomment != *(int *)argv[13])) return MR_PERM; } else return MR_PERM; } /* If moving to a new subnet, make sure user is on acl there */ id = *(int *)argv[9]; if (id != snid) { EXEC SQL SELECT owner_type, owner_id INTO :stype, :sid FROM subnet WHERE snet_id=:id; if (!find_member(stype, sid, cl)) return MR_PERM; } return MR_SUCCESS; } } /* access_ahal - check for adding a host alias. * successful if host has less then 2 aliases and (client is owner of * host or subnet). * If deleting an alias, any owner will do. */ int access_ahal(struct query *q, char *argv[], client *cl) { EXEC SQL BEGIN DECLARE SECTION; int cnt, id, mid, sid; char mtype[256], stype[256]; EXEC SQL END DECLARE SECTION; int status; if (q->type == RETRIEVE) return MR_SUCCESS; id = *(int *)argv[1]; EXEC SQL SELECT count(name) INTO :cnt from hostalias WHERE mach_id = :id; if (dbms_errno) return mr_errcode; /* if the type is APPEND, this is ahal and we need to make sure there * will be no more than 2 aliases. If it's not, it must be dhal and * any owner will do. */ if (q->type == APPEND && cnt >= 2) return MR_PERM; EXEC SQL SELECT m.owner_type, m.owner_id, s.owner_type, s.owner_id INTO :mtype, :mid, :stype, :sid FROM machine m, subnet s WHERE m.mach_id = :id and s.snet_id = m.snet_id; status = find_member(mtype, mid, cl); if (status) return MR_SUCCESS; status = find_member(stype, sid, cl); if (status) return MR_SUCCESS; else return MR_PERM; } /* access_snt - check for retrieving network structure */ int access_snt(struct query *q, char *argv[], client *cl) { if (q->type == RETRIEVE) return MR_SUCCESS; return MR_PERM; }