acl.c revision 72445
1124758Semax/*
2124758Semax * Copyright (c) 1997 - 2000 Kungliga Tekniska H�gskolan
3124758Semax * (Royal Institute of Technology, Stockholm, Sweden).
4124758Semax * All rights reserved.
5124758Semax *
6124758Semax * Redistribution and use in source and binary forms, with or without
7124758Semax * modification, are permitted provided that the following conditions
8124758Semax * are met:
9124758Semax *
10124758Semax * 1. Redistributions of source code must retain the above copyright
11124758Semax *    notice, this list of conditions and the following disclaimer.
12124758Semax *
13124758Semax * 2. Redistributions in binary form must reproduce the above copyright
14124758Semax *    notice, this list of conditions and the following disclaimer in the
15124758Semax *    documentation and/or other materials provided with the distribution.
16124758Semax *
17124758Semax * 3. Neither the name of the Institute nor the names of its contributors
18124758Semax *    may be used to endorse or promote products derived from this software
19124758Semax *    without specific prior written permission.
20124758Semax *
21124758Semax * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22124758Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23124758Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24124758Semax * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25124758Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26124758Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27124758Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28124758Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29124758Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30124758Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31124758Semax * SUCH DAMAGE.
32124758Semax */
33124758Semax
34124758Semax#include "kadm5_locl.h"
35124758Semax
36124758SemaxRCSID("$Id: acl.c,v 1.12 2000/08/10 19:24:08 assar Exp $");
37124758Semax
38124758Semaxstatic struct units acl_units[] = {
39124758Semax    { "all",		KADM5_PRIV_ALL },
40124758Semax    { "change-password",KADM5_PRIV_CPW },
41124758Semax    { "cpw",		KADM5_PRIV_CPW },
42124758Semax    { "list",		KADM5_PRIV_LIST },
43124758Semax    { "delete",		KADM5_PRIV_DELETE },
44139721Semax    { "modify",		KADM5_PRIV_MODIFY },
45124758Semax    { "add",		KADM5_PRIV_ADD },
46124758Semax    { "get", 		KADM5_PRIV_GET },
47124758Semax    { NULL }
48124758Semax};
49124758Semax
50124758Semaxkadm5_ret_t
51124758Semax_kadm5_string_to_privs(const char *s, u_int32_t* privs)
52124758Semax{
53124758Semax    int flags;
54124758Semax    flags = parse_flags(s, acl_units, 0);
55124758Semax    if(flags < 0)
56124758Semax	return KADM5_FAILURE;
57124758Semax    *privs = flags;
58124758Semax    return 0;
59124758Semax}
60139721Semax
61139721Semaxkadm5_ret_t
62124758Semax_kadm5_privs_to_string(u_int32_t privs, char *string, size_t len)
63124758Semax{
64124758Semax    if(privs == 0)
65124758Semax	strlcpy(string, "none", len);
66124758Semax    else
67124758Semax	unparse_flags(privs, acl_units + 1, string, len);
68124758Semax    return 0;
69124758Semax}
70124758Semax
71124758Semax/*
72124758Semax * retrieve the right for the current caller on `princ' (NULL means all)
73124758Semax * and store them in `ret_flags'
74124758Semax * return 0 or an error.
75124758Semax */
76124758Semax
77124758Semaxstatic kadm5_ret_t
78124758Semaxfetch_acl (kadm5_server_context *context,
79124758Semax	   krb5_const_principal princ,
80124758Semax	   unsigned *ret_flags)
81124758Semax{
82124758Semax    unsigned flags = -1;
83124758Semax    FILE *f = fopen(context->config.acl_file, "r");
84124758Semax    krb5_error_code ret = 0;
85124758Semax
86124758Semax    if(f != NULL) {
87124758Semax	char buf[256];
88124758Semax
89124758Semax	while(fgets(buf, sizeof(buf), f) != NULL){
90124758Semax	    char *foo = NULL, *p;
91124758Semax	    krb5_principal this_princ;
92124758Semax
93124758Semax	    flags = -1;
94124758Semax	    p = strtok_r(buf, " \t\n", &foo);
95124758Semax	    if(p == NULL)
96124758Semax		continue;
97124758Semax	    ret = krb5_parse_name(context->context, p, &this_princ);
98124758Semax	    if(ret)
99124758Semax		continue;
100124758Semax	    if(!krb5_principal_compare(context->context,
101124758Semax				       context->caller, this_princ)) {
102124758Semax		krb5_free_principal(context->context, this_princ);
103124758Semax		continue;
104124758Semax	    }
105124758Semax	    krb5_free_principal(context->context, this_princ);
106124758Semax	    p = strtok_r(NULL, " \t\n", &foo);
107124758Semax	    if(p == NULL)
108124758Semax		continue;
109124758Semax	    ret = _kadm5_string_to_privs(p, &flags);
110124758Semax	    if (ret)
111124758Semax		break;
112124758Semax	    p = strtok_r(NULL, "\n", &foo);
113124758Semax	    if (p == NULL) {
114124758Semax		ret = 0;
115124758Semax		break;
116124758Semax	    }
117124758Semax	    if (princ != NULL) {
118124758Semax		krb5_principal pattern_princ;
119124758Semax		krb5_boolean tmp;
120124758Semax
121124758Semax		ret = krb5_parse_name (context->context, p, &pattern_princ);
122124758Semax		if (ret)
123124758Semax		    break;
124124758Semax		tmp = krb5_principal_match (context->context,
125124758Semax					    princ, pattern_princ);
126124758Semax		krb5_free_principal (context->context, pattern_princ);
127124758Semax		if (tmp) {
128124758Semax		    ret = 0;
129124758Semax		    break;
130124758Semax		}
131124758Semax	    }
132124758Semax	}
133124758Semax	fclose(f);
134124758Semax    }
135124758Semax    if(flags == -1)
136124758Semax	flags = 0;
137124758Semax    if (ret == 0)
138124758Semax	*ret_flags = flags;
139124758Semax    return ret;
140124758Semax}
141124758Semax
142124758Semax/*
143124758Semax * set global acl flags in `context' for the current caller.
144124758Semax * return 0 on success or an error
145124758Semax */
146124758Semax
147124758Semaxkadm5_ret_t
148124758Semax_kadm5_acl_init(kadm5_server_context *context)
149124758Semax{
150139721Semax    krb5_principal princ;
151139721Semax    krb5_error_code ret;
152139721Semax
153124758Semax    ret = krb5_parse_name(context->context, KADM5_ADMIN_SERVICE, &princ);
154124758Semax    if (ret)
155124758Semax	return ret;
156139721Semax    ret = krb5_principal_compare(context->context, context->caller, princ);
157139721Semax    krb5_free_principal(context->context, princ);
158139721Semax    if(ret != 0) {
159139721Semax	context->acl_flags = KADM5_PRIV_ALL;
160139721Semax	return 0;
161139721Semax    }
162139721Semax
163139721Semax    return fetch_acl (context, NULL, &context->acl_flags);
164139721Semax}
165139721Semax
166139721Semax/*
167139721Semax * check if `flags' allows `op'
168139721Semax * return 0 if OK or an error
169139721Semax */
170139721Semax
171139721Semaxstatic kadm5_ret_t
172139721Semaxcheck_flags (unsigned op,
173139721Semax	     unsigned flags)
174139721Semax{
175139721Semax    unsigned res = ~flags & op;
176139721Semax
177124758Semax    if(res & KADM5_PRIV_GET)
178124758Semax	return KADM5_AUTH_GET;
179124758Semax    if(res & KADM5_PRIV_ADD)
180124758Semax	return KADM5_AUTH_ADD;
181124758Semax    if(res & KADM5_PRIV_MODIFY)
182124758Semax	return KADM5_AUTH_MODIFY;
183124758Semax    if(res & KADM5_PRIV_DELETE)
184124758Semax	return KADM5_AUTH_DELETE;
185124758Semax    if(res & KADM5_PRIV_CPW)
186124758Semax	return KADM5_AUTH_CHANGEPW;
187124758Semax    if(res & KADM5_PRIV_LIST)
188139721Semax	return KADM5_AUTH_LIST;
189139721Semax    if(res)
190139721Semax	return KADM5_AUTH_INSUFFICIENT;
191139721Semax    return 0;
192139721Semax}
193139721Semax
194124758Semax/*
195124758Semax * return 0 if the current caller in `context' is allowed to perform
196124758Semax * `op' on `princ' and otherwise an error
197124758Semax * princ == NULL if it's not relevant.
198124758Semax */
199124758Semax
200124758Semaxkadm5_ret_t
201124758Semax_kadm5_acl_check_permission(kadm5_server_context *context,
202124758Semax			    unsigned op,
203124758Semax			    krb5_const_principal princ)
204124758Semax{
205124758Semax    kadm5_ret_t ret;
206124758Semax    unsigned princ_flags;
207124758Semax
208124758Semax    ret = check_flags (op, context->acl_flags);
209124758Semax    if (ret == 0)
210124758Semax	return ret;
211124758Semax    ret = fetch_acl (context, princ, &princ_flags);
212124758Semax    if (ret)
213124758Semax	return ret;
214124758Semax    return check_flags (op, princ_flags);
215124758Semax}
216124758Semax