1/* $NetBSD: acl.c,v 1.2 2017/01/28 21:31:49 christos Exp $ */ 2 3/* 4 * Copyright (c) 1997 - 2001 Kungliga Tekniska H��gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include "kadm5_locl.h" 37 38__RCSID("$NetBSD: acl.c,v 1.2 2017/01/28 21:31:49 christos Exp $"); 39 40static struct units acl_units[] = { 41 { "all", KADM5_PRIV_ALL }, 42 { "change-password",KADM5_PRIV_CPW }, 43 { "cpw", KADM5_PRIV_CPW }, 44 { "list", KADM5_PRIV_LIST }, 45 { "delete", KADM5_PRIV_DELETE }, 46 { "modify", KADM5_PRIV_MODIFY }, 47 { "add", KADM5_PRIV_ADD }, 48 { "get", KADM5_PRIV_GET }, 49 { "get-keys", KADM5_PRIV_GET_KEYS }, 50 { NULL, 0 } 51}; 52 53kadm5_ret_t 54_kadm5_string_to_privs(const char *s, uint32_t* privs) 55{ 56 int flags; 57 flags = parse_flags(s, acl_units, 0); 58 if(flags < 0) 59 return KADM5_FAILURE; 60 *privs = flags; 61 return 0; 62} 63 64kadm5_ret_t 65_kadm5_privs_to_string(uint32_t privs, char *string, size_t len) 66{ 67 if(privs == 0) 68 strlcpy(string, "none", len); 69 else 70 unparse_flags(privs, acl_units + 1, string, len); 71 return 0; 72} 73 74/* 75 * retrieve the right for the current caller on `princ' (NULL means all) 76 * and store them in `ret_flags' 77 * return 0 or an error. 78 */ 79 80static kadm5_ret_t 81fetch_acl (kadm5_server_context *context, 82 krb5_const_principal princ, 83 unsigned *ret_flags) 84{ 85 FILE *f; 86 krb5_error_code ret = 0; 87 char buf[256]; 88 89 *ret_flags = 0; 90 91 /* no acl file -> no rights */ 92 f = fopen(context->config.acl_file, "r"); 93 if (f == NULL) 94 return 0; 95 96 while(fgets(buf, sizeof(buf), f) != NULL) { 97 char *foo = NULL, *p; 98 krb5_principal this_princ; 99 unsigned flags = 0; 100 101 p = strtok_r(buf, " \t\n", &foo); 102 if(p == NULL) 103 continue; 104 if (*p == '#') /* comment */ 105 continue; 106 ret = krb5_parse_name(context->context, p, &this_princ); 107 if(ret) 108 break; 109 if(!krb5_principal_compare(context->context, 110 context->caller, this_princ)) { 111 krb5_free_principal(context->context, this_princ); 112 continue; 113 } 114 krb5_free_principal(context->context, this_princ); 115 p = strtok_r(NULL, " \t\n", &foo); 116 if(p == NULL) 117 continue; 118 ret = _kadm5_string_to_privs(p, &flags); 119 if (ret) 120 break; 121 p = strtok_r(NULL, " \t\n", &foo); 122 if (p == NULL) { 123 *ret_flags = flags; 124 break; 125 } 126 if (princ != NULL) { 127 krb5_principal pattern_princ; 128 krb5_boolean match; 129 130 ret = krb5_parse_name (context->context, p, &pattern_princ); 131 if (ret) 132 break; 133 match = krb5_principal_match (context->context, 134 princ, pattern_princ); 135 krb5_free_principal (context->context, pattern_princ); 136 if (match) { 137 *ret_flags = flags; 138 break; 139 } 140 } 141 } 142 fclose(f); 143 return ret; 144} 145 146/* 147 * set global acl flags in `context' for the current caller. 148 * return 0 on success or an error 149 */ 150 151kadm5_ret_t 152_kadm5_acl_init(kadm5_server_context *context) 153{ 154 krb5_principal princ; 155 krb5_error_code ret; 156 157 ret = krb5_parse_name(context->context, KADM5_ADMIN_SERVICE, &princ); 158 if (ret) 159 return ret; 160 ret = krb5_principal_compare(context->context, context->caller, princ); 161 krb5_free_principal(context->context, princ); 162 if(ret != 0) { 163 context->acl_flags = KADM5_PRIV_ALL; 164 return 0; 165 } 166 167 return fetch_acl (context, NULL, &context->acl_flags); 168} 169 170/* 171 * check if `flags' allows `op' 172 * return 0 if OK or an error 173 */ 174 175static kadm5_ret_t 176check_flags (unsigned op, 177 unsigned flags) 178{ 179 unsigned res = ~flags & op; 180 181 if(res & KADM5_PRIV_GET) 182 return KADM5_AUTH_GET; 183 if(res & KADM5_PRIV_GET_KEYS) 184 return KADM5_AUTH_GET_KEYS; 185 if(res & KADM5_PRIV_ADD) 186 return KADM5_AUTH_ADD; 187 if(res & KADM5_PRIV_MODIFY) 188 return KADM5_AUTH_MODIFY; 189 if(res & KADM5_PRIV_DELETE) 190 return KADM5_AUTH_DELETE; 191 if(res & KADM5_PRIV_CPW) 192 return KADM5_AUTH_CHANGEPW; 193 if(res & KADM5_PRIV_LIST) 194 return KADM5_AUTH_LIST; 195 if(res) 196 return KADM5_AUTH_INSUFFICIENT; 197 return 0; 198} 199 200/* 201 * return 0 if the current caller in `context' is allowed to perform 202 * `op' on `princ' and otherwise an error 203 * princ == NULL if it's not relevant. 204 */ 205 206kadm5_ret_t 207_kadm5_acl_check_permission(kadm5_server_context *context, 208 unsigned op, 209 krb5_const_principal princ) 210{ 211 kadm5_ret_t ret; 212 unsigned princ_flags; 213 214 ret = check_flags (op, context->acl_flags); 215 if (ret == 0) 216 return ret; 217 ret = fetch_acl (context, princ, &princ_flags); 218 if (ret) 219 return ret; 220 return check_flags (op, princ_flags); 221} 222