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