acl.c revision 303975
1116742Ssam/* 2116904Ssam * Copyright (c) 1997 - 2001 Kungliga Tekniska H��gskolan 3116742Ssam * (Royal Institute of Technology, Stockholm, Sweden). 4116742Ssam * All rights reserved. 5116742Ssam * 6116742Ssam * Redistribution and use in source and binary forms, with or without 7116742Ssam * modification, are permitted provided that the following conditions 8116742Ssam * are met: 9116742Ssam * 10116742Ssam * 1. Redistributions of source code must retain the above copyright 11116742Ssam * notice, this list of conditions and the following disclaimer. 12116742Ssam * 13116742Ssam * 2. Redistributions in binary form must reproduce the above copyright 14116904Ssam * notice, this list of conditions and the following disclaimer in the 15116904Ssam * documentation and/or other materials provided with the distribution. 16116742Ssam * 17116904Ssam * 3. Neither the name of the Institute nor the names of its contributors 18116904Ssam * may be used to endorse or promote products derived from this software 19116904Ssam * without specific prior written permission. 20116742Ssam * 21116904Ssam * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22116904Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23116904Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24116904Ssam * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25116904Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26116904Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27116904Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28116904Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29116904Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30116904Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31116904Ssam * SUCH DAMAGE. 32116742Ssam */ 33116742Ssam 34116742Ssam#include "kadm5_locl.h" 35116742Ssam 36116742SsamRCSID("$Id$"); 37116742Ssam 38116742Ssamstatic struct units acl_units[] = { 39116742Ssam { "all", KADM5_PRIV_ALL }, 40116742Ssam { "change-password",KADM5_PRIV_CPW }, 41116742Ssam { "cpw", KADM5_PRIV_CPW }, 42116742Ssam { "list", KADM5_PRIV_LIST }, 43116742Ssam { "delete", KADM5_PRIV_DELETE }, 44116742Ssam { "modify", KADM5_PRIV_MODIFY }, 45116742Ssam { "add", KADM5_PRIV_ADD }, 46116742Ssam { "get", KADM5_PRIV_GET }, 47116742Ssam { NULL, 0 } 48116742Ssam}; 49116742Ssam 50116742Ssamkadm5_ret_t 51116742Ssam_kadm5_string_to_privs(const char *s, uint32_t* privs) 52116742Ssam{ 53116742Ssam int flags; 54116742Ssam flags = parse_flags(s, acl_units, 0); 55116742Ssam if(flags < 0) 56116742Ssam return KADM5_FAILURE; 57116742Ssam *privs = flags; 58116742Ssam return 0; 59116742Ssam} 60116742Ssam 61116742Ssamkadm5_ret_t 62116742Ssam_kadm5_privs_to_string(uint32_t privs, char *string, size_t len) 63116742Ssam{ 64116742Ssam if(privs == 0) 65116742Ssam strlcpy(string, "none", len); 66116742Ssam else 67116742Ssam unparse_flags(privs, acl_units + 1, string, len); 68116742Ssam return 0; 69116742Ssam} 70116742Ssam 71116742Ssam/* 72116742Ssam * retrieve the right for the current caller on `princ' (NULL means all) 73117817Ssam * and store them in `ret_flags' 74117817Ssam * return 0 or an error. 75116742Ssam */ 76116742Ssam 77116742Ssamstatic kadm5_ret_t 78116742Ssamfetch_acl (kadm5_server_context *context, 79116742Ssam krb5_const_principal princ, 80116742Ssam unsigned *ret_flags) 81116742Ssam{ 82116742Ssam FILE *f; 83116742Ssam krb5_error_code ret = 0; 84116742Ssam char buf[256]; 85116742Ssam 86116742Ssam *ret_flags = 0; 87116742Ssam 88116742Ssam /* no acl file -> no rights */ 89116742Ssam f = fopen(context->config.acl_file, "r"); 90116742Ssam if (f == NULL) 91116742Ssam return 0; 92116742Ssam 93116742Ssam while(fgets(buf, sizeof(buf), f) != NULL) { 94116742Ssam char *foo = NULL, *p; 95116742Ssam krb5_principal this_princ; 96116742Ssam unsigned flags = 0; 97116742Ssam 98116742Ssam p = strtok_r(buf, " \t\n", &foo); 99116742Ssam if(p == NULL) 100116742Ssam continue; 101116742Ssam if (*p == '#') /* comment */ 102116742Ssam continue; 103116742Ssam ret = krb5_parse_name(context->context, p, &this_princ); 104116742Ssam if(ret) 105116742Ssam break; 106116742Ssam if(!krb5_principal_compare(context->context, 107116742Ssam context->caller, this_princ)) { 108116742Ssam krb5_free_principal(context->context, this_princ); 109116742Ssam continue; 110116742Ssam } 111116742Ssam krb5_free_principal(context->context, this_princ); 112116742Ssam p = strtok_r(NULL, " \t\n", &foo); 113116742Ssam if(p == NULL) 114116742Ssam continue; 115116742Ssam ret = _kadm5_string_to_privs(p, &flags); 116116742Ssam if (ret) 117116742Ssam break; 118116742Ssam p = strtok_r(NULL, " \t\n", &foo); 119116742Ssam if (p == NULL) { 120116742Ssam *ret_flags = flags; 121116742Ssam break; 122116742Ssam } 123116742Ssam if (princ != NULL) { 124116742Ssam krb5_principal pattern_princ; 125116742Ssam krb5_boolean match; 126116742Ssam 127116742Ssam ret = krb5_parse_name (context->context, p, &pattern_princ); 128116742Ssam if (ret) 129116742Ssam break; 130116742Ssam match = krb5_principal_match (context->context, 131116742Ssam princ, pattern_princ); 132116742Ssam krb5_free_principal (context->context, pattern_princ); 133116742Ssam if (match) { 134116742Ssam *ret_flags = flags; 135116742Ssam break; 136116742Ssam } 137116742Ssam } 138119150Ssam } 139119150Ssam fclose(f); 140116742Ssam return ret; 141116742Ssam} 142117811Ssam 143117811Ssam/* 144116742Ssam * set global acl flags in `context' for the current caller. 145116742Ssam * return 0 on success or an error 146116742Ssam */ 147116742Ssam 148116742Ssamkadm5_ret_t 149116742Ssam_kadm5_acl_init(kadm5_server_context *context) 150116742Ssam{ 151116742Ssam krb5_principal princ; 152116742Ssam krb5_error_code ret; 153116742Ssam 154116742Ssam ret = krb5_parse_name(context->context, KADM5_ADMIN_SERVICE, &princ); 155116742Ssam if (ret) 156116742Ssam return ret; 157116742Ssam ret = krb5_principal_compare(context->context, context->caller, princ); 158116742Ssam krb5_free_principal(context->context, princ); 159116742Ssam if(ret != 0) { 160116742Ssam context->acl_flags = KADM5_PRIV_ALL; 161116742Ssam return 0; 162116742Ssam } 163116742Ssam 164116742Ssam return fetch_acl (context, NULL, &context->acl_flags); 165116742Ssam} 166116742Ssam 167116742Ssam/* 168116742Ssam * check if `flags' allows `op' 169116742Ssam * return 0 if OK or an error 170116742Ssam */ 171116742Ssam 172116742Ssamstatic kadm5_ret_t 173116742Ssamcheck_flags (unsigned op, 174116742Ssam unsigned flags) 175116742Ssam{ 176116742Ssam unsigned res = ~flags & op; 177116742Ssam 178116742Ssam if(res & KADM5_PRIV_GET) 179116742Ssam return KADM5_AUTH_GET; 180116742Ssam if(res & KADM5_PRIV_ADD) 181116742Ssam return KADM5_AUTH_ADD; 182116742Ssam if(res & KADM5_PRIV_MODIFY) 183116742Ssam return KADM5_AUTH_MODIFY; 184116742Ssam if(res & KADM5_PRIV_DELETE) 185116742Ssam return KADM5_AUTH_DELETE; 186116742Ssam if(res & KADM5_PRIV_CPW) 187116742Ssam return KADM5_AUTH_CHANGEPW; 188116742Ssam if(res & KADM5_PRIV_LIST) 189116742Ssam return KADM5_AUTH_LIST; 190116742Ssam if(res) 191116742Ssam return KADM5_AUTH_INSUFFICIENT; 192116742Ssam return 0; 193116742Ssam} 194116742Ssam 195116742Ssam/* 196116742Ssam * return 0 if the current caller in `context' is allowed to perform 197116742Ssam * `op' on `princ' and otherwise an error 198116742Ssam * princ == NULL if it's not relevant. 199116742Ssam */ 200116742Ssam 201116742Ssamkadm5_ret_t 202116742Ssam_kadm5_acl_check_permission(kadm5_server_context *context, 203116742Ssam unsigned op, 204116742Ssam krb5_const_principal princ) 205116742Ssam{ 206116742Ssam kadm5_ret_t ret; 207116742Ssam unsigned princ_flags; 208116742Ssam 209116742Ssam ret = check_flags (op, context->acl_flags); 210116742Ssam if (ret == 0) 211116742Ssam return ret; 212116742Ssam ret = fetch_acl (context, princ, &princ_flags); 213116742Ssam if (ret) 214116742Ssam return ret; 215116742Ssam return check_flags (op, princ_flags); 216116742Ssam} 217116742Ssam