summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2011-06-10 14:35:46 -0400
committerSimo Sorce <ssorce@redhat.com>2011-08-26 08:24:49 -0400
commit46c803a08d691c067d985791f2c98467219a8adc (patch)
tree30fc7957331e543aa67592d597f4a87026aaed78
parentb5ba0f7f4879d9312aa76a2097f614d1d3271467 (diff)
downloadfreeipa-46c803a08d691c067d985791f2c98467219a8adc.tar.gz
freeipa-46c803a08d691c067d985791f2c98467219a8adc.tar.xz
freeipa-46c803a08d691c067d985791f2c98467219a8adc.zip
ipa-kdb: add common utility ldap wrapper functions
-rw-r--r--daemons/ipa-kdb/Makefile.am1
-rw-r--r--daemons/ipa-kdb/ipa_kdb.h31
-rw-r--r--daemons/ipa-kdb/ipa_kdb_common.c432
3 files changed, 464 insertions, 0 deletions
diff --git a/daemons/ipa-kdb/Makefile.am b/daemons/ipa-kdb/Makefile.am
index 309618a29..0d35ea973 100644
--- a/daemons/ipa-kdb/Makefile.am
+++ b/daemons/ipa-kdb/Makefile.am
@@ -23,6 +23,7 @@ plugin_LTLIBRARIES = \
ipadb_la_SOURCES = \
ipa_kdb.c \
+ ipa_kdb_common.c \
$(NULL)
ipadb_la_LDFLAGS = \
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index 008779f7c..760508d6d 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -42,3 +42,34 @@ struct ipadb_context {
struct ipadb_context *ipadb_get_context(krb5_context kcontext);
int ipadb_get_connection(struct ipadb_context *ipactx);
+
+/* COMMON LDAP FUNCTIONS */
+char *ipadb_filter_escape(const char *input, bool star);
+krb5_error_code ipadb_simple_search(struct ipadb_context *ipactx,
+ char *basedn, int scope,
+ char *filter, char **attrs,
+ LDAPMessage **res);
+krb5_error_code ipadb_simple_delete(struct ipadb_context *ipactx, char *dn);
+krb5_error_code ipadb_simple_add(struct ipadb_context *ipactx,
+ char *dn, LDAPMod **mods);
+krb5_error_code ipadb_simple_modify(struct ipadb_context *ipactx,
+ char *dn, LDAPMod **mods);
+krb5_error_code ipadb_simple_delete_val(struct ipadb_context *ipactx,
+ char *dn, char *attr, char *value);
+
+int ipadb_ldap_attr_to_int(LDAP *lcontext, LDAPMessage *le,
+ char *attrname, int *result);
+int ipadb_ldap_attr_to_uint32(LDAP *lcontext, LDAPMessage *le,
+ char *attrname, uint32_t *result);
+int ipadb_ldap_attr_to_str(LDAP *lcontext, LDAPMessage *le,
+ char *attrname, char **result);
+int ipadb_ldap_attr_to_strlist(LDAP *lcontext, LDAPMessage *le,
+ char *attrname, char ***result);
+int ipadb_ldap_attr_to_bool(LDAP *lcontext, LDAPMessage *le,
+ char *attrname, bool *result);
+int ipadb_ldap_attr_to_time_t(LDAP *lcontext, LDAPMessage *le,
+ char *attrname, time_t *result);
+
+int ipadb_ldap_attr_has_value(LDAP *lcontext, LDAPMessage *le,
+ char *attrname, char *value);
+
diff --git a/daemons/ipa-kdb/ipa_kdb_common.c b/daemons/ipa-kdb/ipa_kdb_common.c
new file mode 100644
index 000000000..21b7a4df4
--- /dev/null
+++ b/daemons/ipa-kdb/ipa_kdb_common.c
@@ -0,0 +1,432 @@
+/*
+ * 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;
+}
+
+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 (strcmp("TRUE", vals[0]->bv_val) == 0) {
+ *result = true;
+ ret = 0;
+ } else if (strcmp("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;
+}