xref: /freebsd/crypto/heimdal/lib/kadm5/acl.c (revision 6a068746777241722b2b32c5d0bc443a2a64d80b)
1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov  * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
19b528cefcSMark Murray  *    without specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray  * SUCH DAMAGE.
32b528cefcSMark Murray  */
33b528cefcSMark Murray 
34b528cefcSMark Murray #include "kadm5_locl.h"
35b528cefcSMark Murray 
36*ae771770SStanislav Sedov RCSID("$Id$");
37b528cefcSMark Murray 
38b528cefcSMark Murray static struct units acl_units[] = {
39b528cefcSMark Murray     { "all",		KADM5_PRIV_ALL },
40b528cefcSMark Murray     { "change-password",KADM5_PRIV_CPW },
41b528cefcSMark Murray     { "cpw",		KADM5_PRIV_CPW },
42b528cefcSMark Murray     { "list",		KADM5_PRIV_LIST },
43b528cefcSMark Murray     { "delete",		KADM5_PRIV_DELETE },
44b528cefcSMark Murray     { "modify",		KADM5_PRIV_MODIFY },
45b528cefcSMark Murray     { "add",		KADM5_PRIV_ADD },
46b528cefcSMark Murray     { "get", 		KADM5_PRIV_GET },
47*ae771770SStanislav Sedov     { NULL,		0 }
48b528cefcSMark Murray };
49b528cefcSMark Murray 
50b528cefcSMark Murray kadm5_ret_t
_kadm5_string_to_privs(const char * s,uint32_t * privs)51c19800e8SDoug Rabson _kadm5_string_to_privs(const char *s, uint32_t* privs)
52b528cefcSMark Murray {
53b528cefcSMark Murray     int flags;
54b528cefcSMark Murray     flags = parse_flags(s, acl_units, 0);
55b528cefcSMark Murray     if(flags < 0)
56b528cefcSMark Murray 	return KADM5_FAILURE;
57b528cefcSMark Murray     *privs = flags;
58b528cefcSMark Murray     return 0;
59b528cefcSMark Murray }
60b528cefcSMark Murray 
61b528cefcSMark Murray kadm5_ret_t
_kadm5_privs_to_string(uint32_t privs,char * string,size_t len)62c19800e8SDoug Rabson _kadm5_privs_to_string(uint32_t privs, char *string, size_t len)
63b528cefcSMark Murray {
64b528cefcSMark Murray     if(privs == 0)
65b528cefcSMark Murray 	strlcpy(string, "none", len);
66b528cefcSMark Murray     else
67b528cefcSMark Murray 	unparse_flags(privs, acl_units + 1, string, len);
68b528cefcSMark Murray     return 0;
69b528cefcSMark Murray }
70b528cefcSMark Murray 
715e9cd1aeSAssar Westerlund /*
725e9cd1aeSAssar Westerlund  * retrieve the right for the current caller on `princ' (NULL means all)
735e9cd1aeSAssar Westerlund  * and store them in `ret_flags'
745e9cd1aeSAssar Westerlund  * return 0 or an error.
755e9cd1aeSAssar Westerlund  */
765e9cd1aeSAssar Westerlund 
775e9cd1aeSAssar Westerlund static kadm5_ret_t
fetch_acl(kadm5_server_context * context,krb5_const_principal princ,unsigned * ret_flags)785e9cd1aeSAssar Westerlund fetch_acl (kadm5_server_context *context,
795e9cd1aeSAssar Westerlund 	   krb5_const_principal princ,
805e9cd1aeSAssar Westerlund 	   unsigned *ret_flags)
815e9cd1aeSAssar Westerlund {
824137ff4cSJacques Vidrine     FILE *f;
835e9cd1aeSAssar Westerlund     krb5_error_code ret = 0;
845e9cd1aeSAssar Westerlund     char buf[256];
855e9cd1aeSAssar Westerlund 
864137ff4cSJacques Vidrine     *ret_flags = 0;
874137ff4cSJacques Vidrine 
884137ff4cSJacques Vidrine     /* no acl file -> no rights */
894137ff4cSJacques Vidrine     f = fopen(context->config.acl_file, "r");
904137ff4cSJacques Vidrine     if (f == NULL)
914137ff4cSJacques Vidrine 	return 0;
924137ff4cSJacques Vidrine 
935e9cd1aeSAssar Westerlund     while(fgets(buf, sizeof(buf), f) != NULL) {
945e9cd1aeSAssar Westerlund 	char *foo = NULL, *p;
955e9cd1aeSAssar Westerlund 	krb5_principal this_princ;
964137ff4cSJacques Vidrine 	unsigned flags = 0;
975e9cd1aeSAssar Westerlund 
985e9cd1aeSAssar Westerlund 	p = strtok_r(buf, " \t\n", &foo);
995e9cd1aeSAssar Westerlund 	if(p == NULL)
1005e9cd1aeSAssar Westerlund 	    continue;
1014137ff4cSJacques Vidrine 	if (*p == '#')		/* comment */
1024137ff4cSJacques Vidrine 	    continue;
1035e9cd1aeSAssar Westerlund 	ret = krb5_parse_name(context->context, p, &this_princ);
1045e9cd1aeSAssar Westerlund 	if(ret)
1054137ff4cSJacques Vidrine 	    break;
1065e9cd1aeSAssar Westerlund 	if(!krb5_principal_compare(context->context,
1075e9cd1aeSAssar Westerlund 				   context->caller, this_princ)) {
1085e9cd1aeSAssar Westerlund 	    krb5_free_principal(context->context, this_princ);
1095e9cd1aeSAssar Westerlund 	    continue;
1105e9cd1aeSAssar Westerlund 	}
1115e9cd1aeSAssar Westerlund 	krb5_free_principal(context->context, this_princ);
1125e9cd1aeSAssar Westerlund 	p = strtok_r(NULL, " \t\n", &foo);
1135e9cd1aeSAssar Westerlund 	if(p == NULL)
1145e9cd1aeSAssar Westerlund 	    continue;
1155e9cd1aeSAssar Westerlund 	ret = _kadm5_string_to_privs(p, &flags);
1165e9cd1aeSAssar Westerlund 	if (ret)
1175e9cd1aeSAssar Westerlund 	    break;
118c19800e8SDoug Rabson 	p = strtok_r(NULL, " \t\n", &foo);
1195e9cd1aeSAssar Westerlund 	if (p == NULL) {
1204137ff4cSJacques Vidrine 	    *ret_flags = flags;
1215e9cd1aeSAssar Westerlund 	    break;
1225e9cd1aeSAssar Westerlund 	}
1235e9cd1aeSAssar Westerlund 	if (princ != NULL) {
1245e9cd1aeSAssar Westerlund 	    krb5_principal pattern_princ;
1254137ff4cSJacques Vidrine 	    krb5_boolean match;
1265e9cd1aeSAssar Westerlund 
1275e9cd1aeSAssar Westerlund 	    ret = krb5_parse_name (context->context, p, &pattern_princ);
1285e9cd1aeSAssar Westerlund 	    if (ret)
1295e9cd1aeSAssar Westerlund 		break;
1304137ff4cSJacques Vidrine 	    match = krb5_principal_match (context->context,
1315e9cd1aeSAssar Westerlund 					  princ, pattern_princ);
1325e9cd1aeSAssar Westerlund 	    krb5_free_principal (context->context, pattern_princ);
1334137ff4cSJacques Vidrine 	    if (match) {
1344137ff4cSJacques Vidrine 		*ret_flags = flags;
1355e9cd1aeSAssar Westerlund 		break;
1365e9cd1aeSAssar Westerlund 	    }
1375e9cd1aeSAssar Westerlund 	}
1385e9cd1aeSAssar Westerlund     }
1395e9cd1aeSAssar Westerlund     fclose(f);
1405e9cd1aeSAssar Westerlund     return ret;
1415e9cd1aeSAssar Westerlund }
1425e9cd1aeSAssar Westerlund 
1435e9cd1aeSAssar Westerlund /*
1445e9cd1aeSAssar Westerlund  * set global acl flags in `context' for the current caller.
1455e9cd1aeSAssar Westerlund  * return 0 on success or an error
1465e9cd1aeSAssar Westerlund  */
1475e9cd1aeSAssar Westerlund 
148b528cefcSMark Murray kadm5_ret_t
_kadm5_acl_init(kadm5_server_context * context)149b528cefcSMark Murray _kadm5_acl_init(kadm5_server_context *context)
150b528cefcSMark Murray {
151b528cefcSMark Murray     krb5_principal princ;
152b528cefcSMark Murray     krb5_error_code ret;
153b528cefcSMark Murray 
1545e9cd1aeSAssar Westerlund     ret = krb5_parse_name(context->context, KADM5_ADMIN_SERVICE, &princ);
1555e9cd1aeSAssar Westerlund     if (ret)
1565e9cd1aeSAssar Westerlund 	return ret;
157b528cefcSMark Murray     ret = krb5_principal_compare(context->context, context->caller, princ);
158b528cefcSMark Murray     krb5_free_principal(context->context, princ);
159b528cefcSMark Murray     if(ret != 0) {
160b528cefcSMark Murray 	context->acl_flags = KADM5_PRIV_ALL;
161b528cefcSMark Murray 	return 0;
162b528cefcSMark Murray     }
163b528cefcSMark Murray 
1645e9cd1aeSAssar Westerlund     return fetch_acl (context, NULL, &context->acl_flags);
165b528cefcSMark Murray }
166b528cefcSMark Murray 
1675e9cd1aeSAssar Westerlund /*
1685e9cd1aeSAssar Westerlund  * check if `flags' allows `op'
1695e9cd1aeSAssar Westerlund  * return 0 if OK or an error
1705e9cd1aeSAssar Westerlund  */
1715e9cd1aeSAssar Westerlund 
1725e9cd1aeSAssar Westerlund static kadm5_ret_t
check_flags(unsigned op,unsigned flags)1735e9cd1aeSAssar Westerlund check_flags (unsigned op,
1745e9cd1aeSAssar Westerlund 	     unsigned flags)
175b528cefcSMark Murray {
1765e9cd1aeSAssar Westerlund     unsigned res = ~flags & op;
1775e9cd1aeSAssar Westerlund 
178b528cefcSMark Murray     if(res & KADM5_PRIV_GET)
179b528cefcSMark Murray 	return KADM5_AUTH_GET;
180b528cefcSMark Murray     if(res & KADM5_PRIV_ADD)
181b528cefcSMark Murray 	return KADM5_AUTH_ADD;
182b528cefcSMark Murray     if(res & KADM5_PRIV_MODIFY)
183b528cefcSMark Murray 	return KADM5_AUTH_MODIFY;
184b528cefcSMark Murray     if(res & KADM5_PRIV_DELETE)
185b528cefcSMark Murray 	return KADM5_AUTH_DELETE;
186b528cefcSMark Murray     if(res & KADM5_PRIV_CPW)
187b528cefcSMark Murray 	return KADM5_AUTH_CHANGEPW;
188b528cefcSMark Murray     if(res & KADM5_PRIV_LIST)
189b528cefcSMark Murray 	return KADM5_AUTH_LIST;
190b528cefcSMark Murray     if(res)
191b528cefcSMark Murray 	return KADM5_AUTH_INSUFFICIENT;
192b528cefcSMark Murray     return 0;
193b528cefcSMark Murray }
1945e9cd1aeSAssar Westerlund 
1955e9cd1aeSAssar Westerlund /*
1965e9cd1aeSAssar Westerlund  * return 0 if the current caller in `context' is allowed to perform
1975e9cd1aeSAssar Westerlund  * `op' on `princ' and otherwise an error
1985e9cd1aeSAssar Westerlund  * princ == NULL if it's not relevant.
1995e9cd1aeSAssar Westerlund  */
2005e9cd1aeSAssar Westerlund 
2015e9cd1aeSAssar Westerlund kadm5_ret_t
_kadm5_acl_check_permission(kadm5_server_context * context,unsigned op,krb5_const_principal princ)2025e9cd1aeSAssar Westerlund _kadm5_acl_check_permission(kadm5_server_context *context,
2035e9cd1aeSAssar Westerlund 			    unsigned op,
2045e9cd1aeSAssar Westerlund 			    krb5_const_principal princ)
2055e9cd1aeSAssar Westerlund {
2065e9cd1aeSAssar Westerlund     kadm5_ret_t ret;
2075e9cd1aeSAssar Westerlund     unsigned princ_flags;
2085e9cd1aeSAssar Westerlund 
2095e9cd1aeSAssar Westerlund     ret = check_flags (op, context->acl_flags);
2105e9cd1aeSAssar Westerlund     if (ret == 0)
2115e9cd1aeSAssar Westerlund 	return ret;
2125e9cd1aeSAssar Westerlund     ret = fetch_acl (context, princ, &princ_flags);
2135e9cd1aeSAssar Westerlund     if (ret)
2145e9cd1aeSAssar Westerlund 	return ret;
2155e9cd1aeSAssar Westerlund     return check_flags (op, princ_flags);
2165e9cd1aeSAssar Westerlund }
217