/* $CoreSDI: resadmin.c,v 1.18 2001/10/05 19:38:29 claudio Exp $ */ /* * Copyright (c) 2000, 2001, Core SDI S.A., Argentina * All rights reserved * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither name of the Core SDI S.A. nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Resources administration commands * Author: Claudio Castiglia */ #include #include #ifdef __linux__ #include /* in_addr_t */ #endif #include #include #include #include #include #include #include "sysdep.h" #include "packet.h" #include "resource.h" #include "modtypes.h" #include "log.h" #include "commands.h" #define RESPERM_RNAME "ResPerm" #define RESADMIN_RNAME "ResAdmin" #define PERM_SET 0x01 #define PERM_FIND 0x02 #define PERM_REMOVE 0x04 #define CAN_SET(x) (x & PERM_SET) #define CAN_FIND(x) (x & PERM_FIND) #define CAN_REMOVE(x) (x & PERM_REMOVE) extern void send_error(PACKET *, const char *, ...); extern void internal_error(PACKET *); /* * _resperms(): * Return permissions for specific resource. */ static int _resperms(RESLIST *rlist, const char *rname) { char full_rname[MAXPATHLEN]; int i, perms; RESOURCE *r; /* Search 'RESPERM_RNAME_' resource */ snprintf(full_rname, sizeof(full_rname), "%s_%s", RESPERM_RNAME, rname); r = res_find(rlist, full_rname); if (r == NULL) { /* Search 'RESPERM_RNAME' resource */ r = res_find(rlist, RESPERM_RNAME); if (r == NULL) return (0); } /* Decode permissions */ perms = 0; for (i = 0; i < r->dsize; i++) switch (*(char *) (r->data + i)) { case 'S': /* Set perm */ case 's': perms |= PERM_SET; break; case 'F': /* Find perm */ case 'f': perms |= PERM_FIND; break; case 'R': /* Remove perm */ case 'r': perms |= PERM_REMOVE; break; default: ; } return (perms); } /* * _isadmin(): * Search for user administration permissions; * return 1 if current auditor has permissions * to administrate some given user; 0 otherwise. * XXX optimize */ static int _isadmin(RESLIST *rlist, const char *user) { RESOURCE *r; char *user_list, full_user[BUFSIZ]; int isadmin; /* Search for 'RESADMIN_RNAME' resource */ isadmin = 0; r = res_find(rlist, RESADMIN_RNAME); if (r != NULL) { /* Load managed users */ user_list = (char *) malloc(r->dsize + 1); if (user_list == NULL) fatal(EX_OSERR, "_is_admin(): %s.", strerror(errno)); memcpy(user_list, r->data, r->dsize); user_list[r->dsize] = '\0'; /* Is the user specified in the list ? */ snprintf(full_user, sizeof(full_user), "%s\n", user); if (!strcmp(user_list, "*") || strstr(user_list, full_user) != NULL) isadmin = 1; free(user_list); } return (isadmin); } /* * resadmin_adduser(): * Create a new user. */ void resadmin_adduser(SESSION *s) { char user[MAXPATHLEN]; char *errstr; RESLIST *newuser; /* Get username */ packet_get_string(s->s_packet, user, sizeof(user)); log_debug("Adding user '%s'.", user); /* Add user only if client is its administrator */ errstr = NULL; if (_isadmin(s->s_rlist, user)) { /* Do not create user resources file if it exists */ if (res_check_list(user)) errstr = "User exists"; else { /* This forces local resources file to be created */ /* XXX: We shouldn't depend on resource modules */ newuser = res_open_list(user, RES_NOTREAD); if (newuser == NULL) { log_cmd(s->s_peername, strerror(errno), "ADDUSER '%s'", user); internal_error(s->s_packet); return; } res_release_list(newuser); packet_put_int32(s->s_packet, CMD_OK); log_cmd(s->s_peername, "Ok", "ADDUSER '%s'", user); return; } } else errno = EACCES; if (errstr == NULL) errstr = strerror(errno); log_cmd(s->s_peername, errstr, "ADDUSER '%s'", user); send_error(s->s_packet, "Can't add user '%s': %s.", user, errstr); } /* * resadmin_rmuser(): * Remove an existing user. */ void resadmin_rmuser(SESSION *s) { char user[MAXPATHLEN]; char *errstr; /* Get username and remove if client is admin */ packet_get_string(s->s_packet, user, sizeof(user)); log_debug("Removing user '%s'.", user); errstr = NULL; if (_isadmin(s->s_rlist, user)) { if (!res_remove_list(user)) { packet_put_int32(s->s_packet, CMD_OK); log_cmd(s->s_peername, "Ok", "REMOVE '%s'", user); return; } if (errno == ENOENT) errstr = "User not found"; } else errno = EACCES; if (errstr == NULL) errstr = strerror(errno); log_cmd(s->s_peername, errstr, "REMOVE '%s'", user); send_error(s->s_packet, "Can't remove user '%s': %s.", user, errstr); } /* * resadmin_set(): * Crate/modify resource. */ void resadmin_set(SESSION *s) { char user[MAXPATHLEN], rname[MAXPATHLEN]; void *value; ssize_t vsize; int err, rperms; RESLIST *ulist; RESOURCE *r; /* Get user name, resource name, and resource value */ packet_get_string(s->s_packet, user, sizeof(user)); packet_get_string(s->s_packet, rname, sizeof(rname)); log_debug("Setting resource '%s' for user '%s'.", rname, user); packet_get_int32(s->s_packet, &vsize); if (vsize <= 0) { log_cmd(s->s_peername, strerror(EINVAL), "SET RESOURCE '%s' FOR '%s'", rname, user); send_error(s->s_packet, "Can't set resource '%s' " "for user '%s': %s.", rname, user, strerror(EINVAL)); return; } if ( (value = malloc(vsize)) == NULL) { log_cmd(s->s_peername, strerror(errno), "SET RESOURCE '%s' FOR '%s'", rname, user); internal_error(s->s_packet); return; } packet_get_raw(s->s_packet, value, vsize); /* Fail command if client isn't admin or hasn't SET permissions */ err = 0; rperms = _resperms(s->s_rlist, rname); if (_isadmin(s->s_rlist, user) || (!strcmp(user, s->s_peername) && CAN_SET(rperms))) { /* Load user resource list */ if (strcmp(user, s->s_peername)) ulist = res_open_list(user, RES_FORCEREAD); else ulist = s->s_rlist; /* Set resource */ r = res_find(ulist, rname); if (r == NULL) err = res_add(ulist, rname, value, vsize); else err = res_replace(ulist, r, value, vsize); if (!err) { res_save_list(ulist); packet_put_int32(s->s_packet, CMD_OK); } else err = errno; } else err = EACCES; free(value); if (err) { log_cmd(s->s_peername, strerror(err), "SET RESOURCE '%s' FOR '%s'", rname, user); send_error(s->s_packet, "Can't set resource '%s' for " "user '%s': %s.", rname, user, strerror(err)); } else log_cmd(s->s_peername, "Ok", "SET RESOURCE '%s' FOR '%s'", rname, user); } /* * resadmin_find(): * Find a resource. */ void resadmin_find(SESSION *s) { char user[MAXPATHLEN], rname[MAXPATHLEN]; int rperms; RESLIST *ulist; RESOURCE *r; /* Get user and resource names */ packet_get_string(s->s_packet, user, sizeof(user)); packet_get_string(s->s_packet, rname, sizeof(rname)); log_debug("Searching resource '%s' for user '%s'.", rname, user); /* Fail if client is not admin or has not FIND permissions */ rperms = _resperms(s->s_rlist, rname); if (_isadmin(s->s_rlist, user) || (!strcmp(user, s->s_peername) && CAN_FIND(rperms))) { /* Load user resource list */ if (strcmp(user, s->s_peername)) ulist = res_open_list(user, RES_FORCEREAD); else ulist = s->s_rlist; /* Find resource */ if ( (r = res_find(ulist, rname)) == NULL) { log_cmd(s->s_peername, "Not found", "FIND RESOURCE '%s'" " FOR '%s'", rname, user); send_error(s->s_packet, "Can't find resource '%s' for " "user '%s': Not found.", rname, user); } else { /* Send data */ log_cmd(s->s_peername, "Ok", "FIND RESOURCE '%s' " "FOR '%s'", rname, user); packet_put_int32(s->s_packet, CMD_OK); packet_put_int32(s->s_packet, r->dsize); packet_put_raw(s->s_packet, r->data, r->dsize); } } else { log_cmd(s->s_peername, strerror(EACCES), "FIND RESOURCE '%s' " "FOR '%s'", rname, user); send_error(s->s_packet, "Can't find resource '%s' for user " "'%s': %s.", rname, user, strerror(EACCES)); } } /* * resadmin_remove() * Remove a resource. */ void resadmin_remove(SESSION *s) { char user[MAXPATHLEN], rname[MAXPATHLEN]; int rperms; RESLIST *ulist; /* Get user and resource names */ packet_get_string(s->s_packet, user, sizeof(user)); packet_get_string(s->s_packet, rname, sizeof(rname)); log_debug("Removing resource '%s' for '%s'.", rname, user); /* Fail if client is not admin or has not REMOVE permissions */ rperms = _resperms(s->s_rlist, rname); if (_isadmin(s->s_rlist, user) || (!strcmp(user, s->s_peername) && CAN_REMOVE(rperms))) { /* Load user resource list */ if (strcmp(user, s->s_peername)) ulist = res_open_list(user, RES_FORCEREAD); else ulist = s->s_rlist; /* Remove resource */ res_remove(ulist, rname); res_save_list(ulist); log_cmd(s->s_peername, "Ok", "REMOVE '%s' FOR '%s'", rname, user); packet_put_int32(s->s_packet, CMD_OK); } else { log_cmd(s->s_peername, strerror(EACCES), "REMOVE '%s' FOR '%s'", rname, user); send_error(s->s_packet, "Can't remove resource '%s' for user " "'%s': %s.", rname, user, strerror(EACCES)); } }