/freeipa-3.0.0.pre1/daemons/ipa-kdb/ipa_kdb_common.c
C | 533 lines | 418 code | 83 blank | 32 comment | 64 complexity | b80ede3b7ddc477ea49ff27d8b0e14c3 MD5 | raw file
Possible License(s): GPL-3.0
- /*
- * 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 struct timeval std_timeout = {300, 0};
- char *ipadb_filter_escape(const char *input, bool star)
- {
- char *output;
- size_t i = 0;
- size_t j = 0;
- /* Assume the worst-case. */
- output = malloc(strlen(input) * 3 + 1);
- if (!output) {
- return NULL;
- }
- while (input[i]) {
- switch(input[i]) {
- case '*':
- if (star) {
- output[j++] = '\\';
- output[j++] = '2';
- output[j++] = 'a';
- } else {
- output[j++] = '*';
- }
- break;
- case '(':
- output[j++] = '\\';
- output[j++] = '2';
- output[j++] = '8';
- break;
- case ')':
- output[j++] = '\\';
- output[j++] = '2';
- output[j++] = '9';
- break;
- case '\\':
- output[j++] = '\\';
- output[j++] = '5';
- output[j++] = 'c';
- break;
- default:
- output[j++] = input[i];
- }
- i++;
- }
- output[j] = '\0';
- return output;
- }
- static krb5_error_code ipadb_simple_ldap_to_kerr(int ldap_error)
- {
- switch (ldap_error) {
- case LDAP_SUCCESS:
- return 0;
- case LDAP_NO_SUCH_OBJECT:
- case LDAP_NO_SUCH_ATTRIBUTE:
- return KRB5_KDB_NOENTRY;
- case LDAP_ALIAS_PROBLEM:
- case LDAP_INVALID_DN_SYNTAX:
- case LDAP_ALIAS_DEREF_PROBLEM:
- case LDAP_UNDEFINED_TYPE:
- case LDAP_INAPPROPRIATE_MATCHING:
- case LDAP_INVALID_SYNTAX:
- case LDAP_NAMING_VIOLATION:
- case LDAP_OBJECT_CLASS_VIOLATION:
- case LDAP_NO_OBJECT_CLASS_MODS:
- return KRB5_KDB_INTERNAL_ERROR;
- case LDAP_ALREADY_EXISTS:
- case LDAP_NOT_ALLOWED_ON_NONLEAF:
- case LDAP_NOT_ALLOWED_ON_RDN:
- case LDAP_TIMELIMIT_EXCEEDED:
- case LDAP_SIZELIMIT_EXCEEDED:
- case LDAP_ADMINLIMIT_EXCEEDED:
- case LDAP_STRONG_AUTH_REQUIRED:
- case LDAP_CONFIDENTIALITY_REQUIRED:
- case LDAP_INAPPROPRIATE_AUTH:
- case LDAP_INVALID_CREDENTIALS:
- case LDAP_INSUFFICIENT_ACCESS:
- case LDAP_BUSY:
- case LDAP_UNAVAILABLE:
- case LDAP_UNWILLING_TO_PERFORM:
- case LDAP_CONSTRAINT_VIOLATION:
- case LDAP_TYPE_OR_VALUE_EXISTS:
- return KRB5_KDB_CONSTRAINT_VIOLATION;
- }
- return KRB5_KDB_SERVER_INTERNAL_ERR;
- }
- static bool ipadb_need_retry(struct ipadb_context *ipactx, int error)
- {
- switch(error) {
- /* connection errors */
- case LDAP_SERVER_DOWN:
- case LDAP_LOCAL_ERROR:
- case LDAP_ENCODING_ERROR:
- case LDAP_DECODING_ERROR:
- case LDAP_TIMEOUT:
- case LDAP_USER_CANCELLED:
- case LDAP_PARAM_ERROR:
- case LDAP_NO_MEMORY:
- case LDAP_CONNECT_ERROR:
- case LDAP_NOT_SUPPORTED:
- case LDAP_CLIENT_LOOP:
- case LDAP_X_CONNECTING:
- /* server returned errors */
- case LDAP_PROTOCOL_ERROR:
- case LDAP_BUSY:
- case LDAP_UNAVAILABLE:
- case LDAP_UNWILLING_TO_PERFORM:
- case LDAP_LOOP_DETECT:
- /* prob connection error, try to reconnect */
- error = ipadb_get_connection(ipactx);
- if (error == 0) {
- return true;
- }
- /* fall through */
- default:
- break;
- }
- return false;
- }
- krb5_error_code ipadb_simple_search(struct ipadb_context *ipactx,
- char *basedn, int scope,
- char *filter, char **attrs,
- LDAPMessage **res)
- {
- int ret;
- ret = ldap_search_ext_s(ipactx->lcontext, basedn, scope,
- filter, attrs, 0, NULL, NULL,
- &std_timeout, LDAP_NO_LIMIT,
- res);
- /* first test if we need to retry to connect */
- if (ret != 0 &&
- ipadb_need_retry(ipactx, ret)) {
- ret = ldap_search_ext_s(ipactx->lcontext, basedn, scope,
- filter, attrs, 0, NULL, NULL,
- &std_timeout, LDAP_NO_LIMIT,
- res);
- }
- return ipadb_simple_ldap_to_kerr(ret);
- }
- krb5_error_code ipadb_simple_delete(struct ipadb_context *ipactx, char *dn)
- {
- int ret;
- ret = ldap_delete_ext_s(ipactx->lcontext, dn, NULL, NULL);
- /* first test if we need to retry to connect */
- if (ret != 0 &&
- ipadb_need_retry(ipactx, ret)) {
- ret = ldap_delete_ext_s(ipactx->lcontext, dn, NULL, NULL);
- }
- return ipadb_simple_ldap_to_kerr(ret);
- }
- krb5_error_code ipadb_simple_add(struct ipadb_context *ipactx,
- char *dn, LDAPMod **mods)
- {
- int ret;
- ret = ldap_add_ext_s(ipactx->lcontext, dn, mods, NULL, NULL);
- /* first test if we need to retry to connect */
- if (ret != 0 &&
- ipadb_need_retry(ipactx, ret)) {
- ret = ldap_add_ext_s(ipactx->lcontext, dn, mods, NULL, NULL);
- }
- return ipadb_simple_ldap_to_kerr(ret);
- }
- krb5_error_code ipadb_simple_modify(struct ipadb_context *ipactx,
- char *dn, LDAPMod **mods)
- {
- int ret;
- ret = ldap_modify_ext_s(ipactx->lcontext, dn, mods, NULL, NULL);
- /* first test if we need to retry to connect */
- if (ret != 0 &&
- ipadb_need_retry(ipactx, ret)) {
- ret = ldap_modify_ext_s(ipactx->lcontext, dn, mods, NULL, NULL);
- }
- return ipadb_simple_ldap_to_kerr(ret);
- }
- krb5_error_code ipadb_simple_delete_val(struct ipadb_context *ipactx,
- char *dn, char *attr, char *value)
- {
- krb5_error_code kerr;
- LDAPMod *mods[2];
- mods[0] = calloc(1, sizeof(LDAPMod));
- if (!mods[0]) {
- return ENOMEM;
- }
- mods[1] = NULL;
- mods[0]->mod_op = LDAP_MOD_DELETE;
- mods[0]->mod_type = strdup(attr);
- if (!mods[0]->mod_type) {
- kerr = ENOMEM;
- goto done;
- }
- mods[0]->mod_values = calloc(2, sizeof(char *));
- if (!mods[0]->mod_values) {
- kerr = ENOMEM;
- goto done;
- }
- mods[0]->mod_values[0] = strdup(value);
- if (!mods[0]->mod_values[0]) {
- kerr = ENOMEM;
- goto done;
- }
- kerr = ipadb_simple_modify(ipactx, dn, mods);
- done:
- ldap_mods_free(mods, 0);
- return kerr;
- }
- krb5_error_code ipadb_deref_search(struct ipadb_context *ipactx,
- char *base_dn, int scope,
- char *filter,
- char **entry_attrs,
- char **deref_attr_names,
- char **deref_attrs,
- LDAPMessage **res)
- {
- struct berval derefval = { 0, NULL };
- LDAPControl *ctrl[2] = { NULL, NULL };
- LDAPDerefSpec *ds;
- krb5_error_code kerr;
- int times;
- int ret;
- int c;
- for (c = 0; deref_attr_names[c]; c++) {
- /* count */ ;
- }
- ds = calloc(c, sizeof(LDAPDerefSpec));
- if (!ds) {
- return ENOMEM;
- }
- for (c = 0; deref_attr_names[c]; c++) {
- ds[c].derefAttr = deref_attr_names[c];
- ds[c].attributes = deref_attrs;
- }
- ret = ldap_create_deref_control_value(ipactx->lcontext, ds, &derefval);
- if (ret != LDAP_SUCCESS) {
- kerr = ENOMEM;
- goto done;
- }
- ret = ldap_control_create(LDAP_CONTROL_X_DEREF,
- 1, &derefval, 1, &ctrl[0]);
- if (ret != LDAP_SUCCESS) {
- kerr = ENOMEM;
- goto done;
- }
- /* retry once if connection errors (tot. max. 2 tries) */
- times = 2;
- ret = LDAP_SUCCESS;
- while (!ipadb_need_retry(ipactx, ret) && times > 0) {
- times--;
- ret = ldap_search_ext_s(ipactx->lcontext, base_dn,
- scope, filter,
- entry_attrs, 0,
- ctrl, NULL,
- &std_timeout, LDAP_NO_LIMIT,
- res);
- }
- kerr = ipadb_simple_ldap_to_kerr(ret);
- done:
- ldap_memfree(derefval.bv_val);
- free(ds);
- return kerr;
- }
- /* result extraction */
- int ipadb_ldap_attr_to_int(LDAP *lcontext, LDAPMessage *le,
- char *attrname, int *result)
- {
- struct berval **vals;
- int ret = ENOENT;
- vals = ldap_get_values_len(lcontext, le, attrname);
- if (vals) {
- *result = atoi(vals[0]->bv_val);
- ret = 0;
- ldap_value_free_len(vals);
- }
- return ret;
- }
- int ipadb_ldap_attr_to_uint32(LDAP *lcontext, LDAPMessage *le,
- char *attrname, uint32_t *result)
- {
- struct berval **vals;
- long r;
- int ret = ENOENT;
- vals = ldap_get_values_len(lcontext, le, attrname);
- if (vals) {
- r = atol(vals[0]->bv_val);
- if (r < 0 || r > (uint32_t)-1) {
- ret = EINVAL;
- } else {
- *result = r;
- ret = 0;
- }
- ldap_value_free_len(vals);
- }
- return ret;
- }
- int ipadb_ldap_attr_to_str(LDAP *lcontext, LDAPMessage *le,
- char *attrname, char **result)
- {
- struct berval **vals;
- int ret = ENOENT;
- vals = ldap_get_values_len(lcontext, le, attrname);
- if (vals) {
- *result = strndup(vals[0]->bv_val, vals[0]->bv_len);
- if (!*result) {
- ret = ENOMEM;
- } else {
- ret = 0;
- }
- ldap_value_free_len(vals);
- }
- return ret;
- }
- int ipadb_ldap_attr_to_strlist(LDAP *lcontext, LDAPMessage *le,
- char *attrname, char ***result)
- {
- struct berval **vals = NULL;
- char **strlist = NULL;
- int ret;
- int i;
- vals = ldap_get_values_len(lcontext, le, attrname);
- if (!vals) {
- return ENOENT;
- }
- for (i = 0; vals[i]; i++) /* count */ ;
- strlist = calloc(i + 1, sizeof(char *));
- if (!strlist) {
- ret = ENOMEM;
- goto fail;
- }
- for (i = 0; vals[i]; i++) {
- strlist[i] = strndup(vals[i]->bv_val, vals[i]->bv_len);
- if (!strlist[i]) {
- ret = ENOMEM;
- goto fail;
- }
- }
- ldap_value_free_len(vals);
- *result = strlist;
- return 0;
- fail:
- ldap_value_free_len(vals);
- for (i = 0; strlist && strlist[i]; i++) {
- free(strlist[i]);
- }
- free(strlist);
- return ret;
- }
- int ipadb_ldap_attr_to_bool(LDAP *lcontext, LDAPMessage *le,
- char *attrname, bool *result)
- {
- struct berval **vals;
- int ret = ENOENT;
- vals = ldap_get_values_len(lcontext, le, attrname);
- if (vals) {
- if (strcasecmp("TRUE", vals[0]->bv_val) == 0) {
- *result = true;
- ret = 0;
- } else if (strcasecmp("FALSE", vals[0]->bv_val) == 0) {
- *result = false;
- ret = 0;
- } else {
- ret = EINVAL;
- }
- ldap_value_free_len(vals);
- }
- return ret;
- }
- int ipadb_ldap_attr_to_time_t(LDAP *lcontext, LDAPMessage *le,
- char *attrname, time_t *result)
- {
- struct berval **vals;
- char *p;
- struct tm stm = { 0 };
- int ret = ENOENT;
- vals = ldap_get_values_len(lcontext, le, attrname);
- if (vals) {
- p = strptime(vals[0]->bv_val, "%Y%m%d%H%M%SZ", &stm);
- if (p && *p == '\0') {
- *result = timegm(&stm);
- ret = 0;
- } else {
- ret = EINVAL;
- }
- ldap_value_free_len(vals);
- }
- return ret;
- }
- int ipadb_ldap_attr_has_value(LDAP *lcontext, LDAPMessage *le,
- char *attrname, char *value)
- {
- struct berval **vals;
- int ret = ENOENT;
- int i;
- vals = ldap_get_values_len(lcontext, le, attrname);
- if (vals) {
- for (i = 0; vals[i]; i++) {
- if (strcasecmp(vals[i]->bv_val, value) == 0) {
- ret = 0;
- break;
- }
- }
- ldap_value_free_len(vals);
- }
- return ret;
- }
- int ipadb_ldap_deref_results(LDAP *lcontext, LDAPMessage *le,
- LDAPDerefRes **results)
- {
- LDAPControl **ctrls = NULL;
- LDAPControl *derefctrl = NULL;
- int ret;
- ret = ldap_get_entry_controls(lcontext, le, &ctrls);
- if (ret != LDAP_SUCCESS) {
- return EINVAL;
- }
- if (!ctrls) {
- return ENOENT;
- }
- derefctrl = ldap_control_find(LDAP_CONTROL_X_DEREF, ctrls, NULL);
- if (!derefctrl) {
- ret = ENOENT;
- goto done;
- }
- ret = ldap_parse_derefresponse_control(lcontext, derefctrl, results);
- if (ret) {
- ret = EINVAL;
- goto done;
- }
- ret = 0;
- done:
- ldap_controls_free(ctrls);
- return ret;
- }