155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2001 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "kadm5_locl.h" 3555682Smarkm 36233294SstasRCSID("$Id$"); 3755682Smarkm 3855682Smarkmstatic struct units acl_units[] = { 3955682Smarkm { "all", KADM5_PRIV_ALL }, 4055682Smarkm { "change-password",KADM5_PRIV_CPW }, 4155682Smarkm { "cpw", KADM5_PRIV_CPW }, 4255682Smarkm { "list", KADM5_PRIV_LIST }, 4355682Smarkm { "delete", KADM5_PRIV_DELETE }, 4455682Smarkm { "modify", KADM5_PRIV_MODIFY }, 4555682Smarkm { "add", KADM5_PRIV_ADD }, 4655682Smarkm { "get", KADM5_PRIV_GET }, 47233294Sstas { NULL, 0 } 4855682Smarkm}; 4955682Smarkm 5055682Smarkmkadm5_ret_t 51178825Sdfr_kadm5_string_to_privs(const char *s, uint32_t* privs) 5255682Smarkm{ 5355682Smarkm int flags; 5455682Smarkm flags = parse_flags(s, acl_units, 0); 5555682Smarkm if(flags < 0) 5655682Smarkm return KADM5_FAILURE; 5755682Smarkm *privs = flags; 5855682Smarkm return 0; 5955682Smarkm} 6055682Smarkm 6155682Smarkmkadm5_ret_t 62178825Sdfr_kadm5_privs_to_string(uint32_t privs, char *string, size_t len) 6355682Smarkm{ 6455682Smarkm if(privs == 0) 6555682Smarkm strlcpy(string, "none", len); 6655682Smarkm else 6755682Smarkm unparse_flags(privs, acl_units + 1, string, len); 6855682Smarkm return 0; 6955682Smarkm} 7055682Smarkm 7172445Sassar/* 7272445Sassar * retrieve the right for the current caller on `princ' (NULL means all) 7372445Sassar * and store them in `ret_flags' 7472445Sassar * return 0 or an error. 7572445Sassar */ 7672445Sassar 7772445Sassarstatic kadm5_ret_t 7872445Sassarfetch_acl (kadm5_server_context *context, 7972445Sassar krb5_const_principal princ, 8072445Sassar unsigned *ret_flags) 8155682Smarkm{ 8290926Snectar FILE *f; 8372445Sassar krb5_error_code ret = 0; 8490926Snectar char buf[256]; 8555682Smarkm 8690926Snectar *ret_flags = 0; 8772445Sassar 8890926Snectar /* no acl file -> no rights */ 8990926Snectar f = fopen(context->config.acl_file, "r"); 9090926Snectar if (f == NULL) 9190926Snectar return 0; 9272445Sassar 9390926Snectar while(fgets(buf, sizeof(buf), f) != NULL) { 9490926Snectar char *foo = NULL, *p; 9590926Snectar krb5_principal this_princ; 9690926Snectar unsigned flags = 0; 9790926Snectar 9890926Snectar p = strtok_r(buf, " \t\n", &foo); 9990926Snectar if(p == NULL) 10090926Snectar continue; 10190926Snectar if (*p == '#') /* comment */ 10290926Snectar continue; 10390926Snectar ret = krb5_parse_name(context->context, p, &this_princ); 10490926Snectar if(ret) 10590926Snectar break; 106233294Sstas if(!krb5_principal_compare(context->context, 10790926Snectar context->caller, this_princ)) { 10872445Sassar krb5_free_principal(context->context, this_princ); 10990926Snectar continue; 11090926Snectar } 11190926Snectar krb5_free_principal(context->context, this_princ); 11290926Snectar p = strtok_r(NULL, " \t\n", &foo); 11390926Snectar if(p == NULL) 11490926Snectar continue; 11590926Snectar ret = _kadm5_string_to_privs(p, &flags); 11690926Snectar if (ret) 11790926Snectar break; 118178825Sdfr p = strtok_r(NULL, " \t\n", &foo); 11990926Snectar if (p == NULL) { 12090926Snectar *ret_flags = flags; 12190926Snectar break; 12290926Snectar } 12390926Snectar if (princ != NULL) { 12490926Snectar krb5_principal pattern_princ; 12590926Snectar krb5_boolean match; 12690926Snectar 12790926Snectar ret = krb5_parse_name (context->context, p, &pattern_princ); 12872445Sassar if (ret) 12972445Sassar break; 13090926Snectar match = krb5_principal_match (context->context, 13190926Snectar princ, pattern_princ); 13290926Snectar krb5_free_principal (context->context, pattern_princ); 13390926Snectar if (match) { 13490926Snectar *ret_flags = flags; 13572445Sassar break; 13672445Sassar } 13755682Smarkm } 13855682Smarkm } 13990926Snectar fclose(f); 14072445Sassar return ret; 14155682Smarkm} 14255682Smarkm 14372445Sassar/* 14472445Sassar * set global acl flags in `context' for the current caller. 14572445Sassar * return 0 on success or an error 14672445Sassar */ 14772445Sassar 14855682Smarkmkadm5_ret_t 14972445Sassar_kadm5_acl_init(kadm5_server_context *context) 15055682Smarkm{ 15172445Sassar krb5_principal princ; 15272445Sassar krb5_error_code ret; 153233294Sstas 15472445Sassar ret = krb5_parse_name(context->context, KADM5_ADMIN_SERVICE, &princ); 15572445Sassar if (ret) 15672445Sassar return ret; 15772445Sassar ret = krb5_principal_compare(context->context, context->caller, princ); 15872445Sassar krb5_free_principal(context->context, princ); 15972445Sassar if(ret != 0) { 16072445Sassar context->acl_flags = KADM5_PRIV_ALL; 16172445Sassar return 0; 16272445Sassar } 16372445Sassar 16472445Sassar return fetch_acl (context, NULL, &context->acl_flags); 16572445Sassar} 16672445Sassar 16772445Sassar/* 16872445Sassar * check if `flags' allows `op' 16972445Sassar * return 0 if OK or an error 17072445Sassar */ 17172445Sassar 17272445Sassarstatic kadm5_ret_t 17372445Sassarcheck_flags (unsigned op, 17472445Sassar unsigned flags) 17572445Sassar{ 17672445Sassar unsigned res = ~flags & op; 17772445Sassar 17855682Smarkm if(res & KADM5_PRIV_GET) 17955682Smarkm return KADM5_AUTH_GET; 18055682Smarkm if(res & KADM5_PRIV_ADD) 18155682Smarkm return KADM5_AUTH_ADD; 18255682Smarkm if(res & KADM5_PRIV_MODIFY) 18355682Smarkm return KADM5_AUTH_MODIFY; 18455682Smarkm if(res & KADM5_PRIV_DELETE) 18555682Smarkm return KADM5_AUTH_DELETE; 18655682Smarkm if(res & KADM5_PRIV_CPW) 18755682Smarkm return KADM5_AUTH_CHANGEPW; 18855682Smarkm if(res & KADM5_PRIV_LIST) 18955682Smarkm return KADM5_AUTH_LIST; 19055682Smarkm if(res) 19155682Smarkm return KADM5_AUTH_INSUFFICIENT; 19255682Smarkm return 0; 19355682Smarkm} 19472445Sassar 19572445Sassar/* 19672445Sassar * return 0 if the current caller in `context' is allowed to perform 19772445Sassar * `op' on `princ' and otherwise an error 19872445Sassar * princ == NULL if it's not relevant. 19972445Sassar */ 20072445Sassar 20172445Sassarkadm5_ret_t 20272445Sassar_kadm5_acl_check_permission(kadm5_server_context *context, 20372445Sassar unsigned op, 20472445Sassar krb5_const_principal princ) 20572445Sassar{ 20672445Sassar kadm5_ret_t ret; 20772445Sassar unsigned princ_flags; 20872445Sassar 20972445Sassar ret = check_flags (op, context->acl_flags); 21072445Sassar if (ret == 0) 21172445Sassar return ret; 21272445Sassar ret = fetch_acl (context, princ, &princ_flags); 21372445Sassar if (ret) 21472445Sassar return ret; 21572445Sassar return check_flags (op, princ_flags); 21672445Sassar} 217