diff options
author | Simo Sorce <ssorce@redhat.com> | 2011-11-20 18:36:26 -0500 |
---|---|---|
committer | Simo Sorce <ssorce@redhat.com> | 2011-12-08 17:18:10 -0500 |
commit | 10264c9ea93fbecdc292643200d55274427ad3f7 (patch) | |
tree | f6bafdc6fef570aac43dc7ab53de8f81e7ffd67e /daemons/ipa-kdb/ipa_kdb_delegation.c | |
parent | 045c7c123eeb720173c19d5196b4fb5bb4cecbaa (diff) | |
download | freeipa-10264c9ea93fbecdc292643200d55274427ad3f7.tar.gz freeipa-10264c9ea93fbecdc292643200d55274427ad3f7.tar.xz freeipa-10264c9ea93fbecdc292643200d55274427ad3f7.zip |
ipa-kdb: Add delgation access control support
Diffstat (limited to 'daemons/ipa-kdb/ipa_kdb_delegation.c')
-rw-r--r-- | daemons/ipa-kdb/ipa_kdb_delegation.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/daemons/ipa-kdb/ipa_kdb_delegation.c b/daemons/ipa-kdb/ipa_kdb_delegation.c new file mode 100644 index 000000000..428e214b7 --- /dev/null +++ b/daemons/ipa-kdb/ipa_kdb_delegation.c @@ -0,0 +1,209 @@ +/* + * MIT Kerberos KDC database backend for FreeIPA + * + * Authors: Simo Sorce <ssorce@redhat.com> + * + * Copyright (C) 2011 Simo Sorce, Red Hat + * see file 'COPYING' for use and warranty information + * + * This program is free software you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "ipa_kdb.h" + +static char *acl_attrs[] = { + "objectClass", + "memberPrincipal", + NULL +}; + +static char *search_attrs[] = { + "ipaAllowToImpersonate", + "ipaAllowedTarget", + NULL +}; + +static krb5_error_code ipadb_get_delegation_acl(krb5_context kcontext, + char *srv_principal, + LDAPMessage **results) +{ + struct ipadb_context *ipactx; + krb5_error_code kerr; + char *filter = NULL; + int ret; + + ipactx = ipadb_get_context(kcontext); + if (!ipactx) { + return KRB5_KDB_DBNOTINITED; + } + + ret = asprintf(&filter, + "(&(objectclass=ipaKrb5DelegationACL)" + "(memberPrincipal=%s))", srv_principal); + if (ret == -1) { + kerr = ENOMEM; + goto done; + } + + /* == Search ACL info == */ + kerr = ipadb_deref_search(ipactx, ipactx->base, + LDAP_SCOPE_SUBTREE, filter, acl_attrs, + search_attrs, acl_attrs, results); + +done: + free(filter); + return kerr; +} + +static bool ipadb_match_member(char *princ, LDAPDerefRes *dres) +{ + LDAPDerefVal *dval; + int i; + + for (dval = dres->attrVals; dval; dval = dval->next) { + if (strcasecmp(dval->type, "memberPrincipal") != 0) { + continue; + } + + for (i = 0; dval->vals[i].bv_val != NULL; i++) { + /* FIXME: use utf8 aware comparison ? */ + /* FIXME: support wildcards ? */ + if (strncasecmp(princ, dval->vals[i].bv_val, + dval->vals[i].bv_len) == 0) { + return true; + } + } + } + + return false; +} + +static krb5_error_code ipadb_match_acl(krb5_context kcontext, + LDAPMessage *results, + krb5_const_principal client, + krb5_const_principal target) +{ + struct ipadb_context *ipactx; + krb5_error_code kerr = ENOENT; + LDAPMessage *lentry; + LDAPDerefRes *deref_results; + LDAPDerefRes *dres; + char *client_princ = NULL; + char *target_princ = NULL; + bool client_missing; + bool client_found; + bool target_found; + int ret; + + ipactx = ipadb_get_context(kcontext); + if (!ipactx) { + return KRB5_KDB_DBNOTINITED; + } + + kerr = krb5_unparse_name(kcontext, client, &client_princ); + if (kerr != 0) { + goto done; + } + kerr = krb5_unparse_name(kcontext, target, &target_princ); + if (kerr != 0) { + goto done; + } + + lentry = ldap_first_entry(ipactx->lcontext, results); + if (!lentry) { + kerr = ENOENT; + goto done; + } + + while (lentry) { + /* both client and target must be found in the same ACI */ + client_missing = true; + client_found = false; + target_found = false; + + ret = ipadb_ldap_deref_results(ipactx->lcontext, lentry, + &deref_results); + switch (ret) { + case 0: + for (dres = deref_results; dres; dres = dres->next) { + if (strcasecmp(dres->derefAttr, "ipaAllowToImpersonate") == 0) { + /* NOTE: client_missing is used to signal that the + * attribute was completely missing. This signals that + * ANY client is allowed to be impersonated. + * This logic is valid only for clients, not for targets */ + client_missing = false; + client_found = ipadb_match_member(client_princ, dres); + } + if (strcasecmp(dres->derefAttr, "ipaAllowedTarget") == 0) { + target_found = ipadb_match_member(target_princ, dres); + } + } + + ldap_derefresponse_free(deref_results); + break; + case ENOENT: + break; + default: + kerr = ret; + goto done; + } + + if ((client_found == true || client_missing == true) && + target_found == true) { + kerr = 0; + goto done; + } + + lentry = ldap_next_entry(ipactx->lcontext, lentry); + } + +done: + krb5_free_unparsed_name(kcontext, client_princ); + krb5_free_unparsed_name(kcontext, target_princ); + return kerr; +} + +/* Ok terminology is confusing here so read carefully: + * here 'proxy' is the service for which 'server' wants a ticket on behalf of + * 'client' */ + +krb5_error_code ipadb_check_allowed_to_delegate(krb5_context kcontext, + krb5_const_principal client, + const krb5_db_entry *server, + krb5_const_principal proxy) +{ + krb5_error_code kerr; + char *srv_principal = NULL; + LDAPMessage *res = NULL; + + kerr = krb5_unparse_name(kcontext, server->princ, &srv_principal); + if (kerr) { + goto done; + } + + kerr = ipadb_get_delegation_acl(kcontext, srv_principal, &res); + if (kerr) { + goto done; + } + + kerr = ipadb_match_acl(kcontext, res, client, proxy); + if (kerr) { + goto done; + } + +done: + krb5_free_unparsed_name(kcontext, srv_principal); + ldap_msgfree(res); + return kerr; +} |