mirror of
https://salsa.debian.org/freeipa-team/freeipa.git
synced 2025-02-25 18:55:28 -06:00
ipa-kdb: add common utility ldap wrapper functions
This commit is contained in:
@@ -23,6 +23,7 @@ plugin_LTLIBRARIES = \
|
||||
|
||||
ipadb_la_SOURCES = \
|
||||
ipa_kdb.c \
|
||||
ipa_kdb_common.c \
|
||||
$(NULL)
|
||||
|
||||
ipadb_la_LDFLAGS = \
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
432
daemons/ipa-kdb/ipa_kdb_common.c
Normal file
432
daemons/ipa-kdb/ipa_kdb_common.c
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user