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