You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kamailio/modules/ldap/ldap_api_fn.c

494 lines
9.4 KiB

/*
* Kamailio LDAP Module
*
* Copyright (C) 2007 University of North Carolina
*
* Original author: Christian Schlatter, cs@unc.edu
*
*
* This file is part of Kamailio, a free SIP server.
*
* Kamailio 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 2 of the License, or
* (at your option) any later version
*
* Kamailio 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#include <unistd.h>
#include <stdarg.h>
#include "../../ut.h"
#include <ldap.h>
#include "ldap_api_fn.h"
#include "api.h"
#include "ldap_connect.h"
#include "ldap_escape.h"
#include "ld_session.h"
static LDAP* last_ldap_handle = NULL;
static LDAPMessage* last_ldap_result_holder = NULL;
static LDAPMessage* last_ldap_result = NULL;
int get_connected_ldap_session(
char* _lds_name,
struct ld_session** _lds);
int lds_search(char* _lds_name,
char* _dn,
int _scope,
char* _filter,
char** _attrs,
struct timeval* _search_timeout,
int* _ld_result_count,
int* _ld_error);
int load_ldap(ldap_api_t *api)
{
if (api == NULL)
{
return -1;
}
api->ldap_params_search = ldap_params_search;
api->ldap_url_search = ldap_url_search;
api->ldap_result_attr_vals = ldap_get_attr_vals;
api->ldap_value_free_len = ldap_value_free_len;
api->ldap_result_next = ldap_inc_result_pointer;
api->ldap_str2scope = ldap_str2scope;
api->ldap_rfc4515_escape = ldap_rfc4515_escape;
api->get_ldap_handle = get_ldap_handle;
api->get_last_ldap_result = get_last_ldap_result;
return 1;
}
int get_ldap_handle(char* _lds_name, LDAP** _ldap_handle)
{
int rc;
struct ld_session* lds;
rc = get_connected_ldap_session(_lds_name, &lds);
if (rc == 0)
{
*_ldap_handle = lds->handle;
}
return rc;
}
int get_connected_ldap_session(char* _lds_name, struct ld_session** _lds)
{
/*
* get ld session
*/
if ((*_lds = get_ld_session(_lds_name)) == NULL)
{
LM_ERR("[%s]: ldap_session not found\n", _lds_name);
return -1;
}
/* try to reconnect if ldap session handle is NULL */
if ((*_lds)->handle == NULL)
{
if (ldap_reconnect(_lds_name) == 0)
{
if ((*_lds = get_ld_session(_lds_name)) == NULL)
{
LM_ERR("[%s]: ldap_session not found\n", _lds_name);
return -1;
}
}
else
{
if (last_ldap_result_holder != NULL)
{
ldap_msgfree(last_ldap_result_holder);
last_ldap_result_holder = NULL;
last_ldap_result = NULL;
}
ldap_disconnect(_lds_name);
LM_ERR("[%s]: reconnect failed\n", _lds_name);
return -1;
}
}
/* free old last_ldap_result */
/*
* this is done now in lds_search
*
if (last_ldap_result != NULL) {
ldap_msgfree(last_ldap_result);
last_ldap_result = NULL;
}
*/
return 0;
}
void get_last_ldap_result(LDAP** _last_ldap_handle, LDAPMessage** _last_ldap_result)
{
*_last_ldap_handle = last_ldap_handle;
*_last_ldap_result = last_ldap_result;
}
int ldap_params_search(
int* _ld_result_count,
char* _lds_name,
char* _dn,
int _scope,
char** _attrs,
char* _filter,
...)
{
int rc;
static char filter_str[LDAP_MAX_FILTER_LEN];
char *filter_ptr = NULL;
va_list filter_vars;
/*
* check _scope
*/
switch (_scope)
{
case LDAP_SCOPE_ONELEVEL:
case LDAP_SCOPE_BASE:
case LDAP_SCOPE_SUBTREE:
break;
default:
LM_ERR("[%s]: invalid scope argument [%d]\n", _lds_name, _scope);
return -1;
}
if (_filter) {
/*
* vsnprintf
*/
va_start(filter_vars, _filter);
rc = vsnprintf(filter_str, (size_t)LDAP_MAX_FILTER_LEN, _filter,
filter_vars);
va_end(filter_vars);
if (rc >= LDAP_MAX_FILTER_LEN)
{
LM_ERR( "[%s]: filter string too long (len [%d], max len [%d])\n",
_lds_name,
rc,
LDAP_MAX_FILTER_LEN);
return -1;
}
else if (rc < 0)
{
LM_ERR("vsnprintf failed\n");
return -1;
}
filter_ptr = filter_str;
}
/*
* ldap search
*/
if (lds_search(_lds_name,
_dn,
_scope,
filter_ptr,
_attrs,
NULL,
_ld_result_count,
&rc)
!= 0)
{
/* try again if LDAP API ERROR */
if (LDAP_API_ERROR(rc) &&
(lds_search(_lds_name,
_dn,
_scope,
filter_str,
_attrs,
NULL,
_ld_result_count,
&rc) != 0))
{
LM_ERR( "[%s]: LDAP search (dn [%s], scope [%d],"
" filter [%s]) failed: %s\n",
_lds_name,
_dn,
_scope,
filter_str,
ldap_err2string(rc));
return -1;
}
}
LM_DBG( "[%s]: [%d] LDAP entries found\n",
_lds_name,
*_ld_result_count);
return 0;
}
int ldap_url_search(
char* _ldap_url,
int* _ld_result_count)
{
LDAPURLDesc *ludp;
int rc;
if (ldap_url_parse(_ldap_url, &ludp) != 0) {
LM_ERR("invalid LDAP URL [%s]\n", ZSW(_ldap_url));
if (ludp != NULL) {
ldap_free_urldesc(ludp);
}
return -2;
}
if (ludp->lud_host == NULL)
{
LM_ERR( "no ldap session name found in ldap URL [%s]\n",
ZSW(_ldap_url));
return -2;
}
LM_DBG( "LDAP URL parsed into session_name"
" [%s], base [%s], scope [%d], filter [%s]\n",
ZSW(ludp->lud_host),
ZSW(ludp->lud_dn),
ludp->lud_scope,
ZSW(ludp->lud_filter));
rc = ldap_params_search(_ld_result_count,
ludp->lud_host,
ludp->lud_dn,
ludp->lud_scope,
ludp->lud_attrs,
ludp->lud_filter);
ldap_free_urldesc(ludp);
return rc;
}
int ldap_inc_result_pointer(void)
{
LDAPMessage *next_result = NULL;
/*
* check for last_ldap_result
*/
if (last_ldap_result == NULL) {
LM_ERR("last_ldap_result == NULL\n");
return -1;
}
if (last_ldap_handle == NULL)
{
LM_ERR("last_ldap_handle == NULL\n");
return -1;
}
/*
* get next LDAP result pointer
*/
if ((next_result = ldap_next_entry(last_ldap_handle, last_ldap_result))
== NULL)
{
/* no more LDAP entries */
return 1;
}
last_ldap_result = next_result;
return 0;
}
int ldap_get_attr_vals(str *_attr_name, struct berval ***_vals)
{
BerElement *ber;
char *a;
/*
* check for last_ldap_result
*/
if (last_ldap_result == NULL) {
LM_ERR("last_ldap_result == NULL\n");
return -1;
}
if (last_ldap_handle == NULL)
{
LM_ERR("last_ldap_handle == NULL\n");
return -1;
}
/*
* search for attribute named _attr_name
*/
*_vals = NULL;
for (a = ldap_first_attribute(last_ldap_handle,
last_ldap_result,
&ber);
a != NULL;
a = ldap_next_attribute(last_ldap_handle,
last_ldap_result,
ber))
{
if (strncmp(a, _attr_name->s, _attr_name->len) == 0) {
*_vals = ldap_get_values_len(
last_ldap_handle,
last_ldap_result,
a);
ldap_memfree(a);
break;
}
ldap_memfree(a);
}
if (ber != NULL) {
ber_free(ber, 0);
}
if (*_vals != NULL)
{
return 0;
} else {
return 1;
}
}
int ldap_str2scope(char* scope_str)
{
if ( strcasecmp( scope_str, "one" ) == 0 ) {
return LDAP_SCOPE_ONELEVEL;
} else if ( strcasecmp( scope_str, "onelevel" ) == 0 ) {
return LDAP_SCOPE_ONELEVEL;
} else if ( strcasecmp( scope_str, "base" ) == 0 ) {
return LDAP_SCOPE_BASE;
} else if ( strcasecmp( scope_str, "sub" ) == 0 ) {
return LDAP_SCOPE_SUBTREE;
} else if ( strcasecmp( scope_str, "subtree" ) == 0 ) {
return LDAP_SCOPE_SUBTREE;
};
return( -1 );
}
/*
* sets last_ldap_result and last_ldap_handle
*/
int lds_search(
char* _lds_name,
char* _dn,
int _scope,
char* _filter,
char** _attrs,
struct timeval* _search_timeout,
int* _ld_result_count,
int* _ld_error)
{
struct ld_session* lds;
#ifdef LDAP_PERF
struct timeval before_search = { 0, 0 }, after_search = { 0, 0 };
#endif
/*
* get ld_handle
*/
if (get_connected_ldap_session(_lds_name, &lds) != 0)
{
LM_ERR("[%s]: couldn't get ldap session\n", _lds_name);
return -1;
}
/*
* free last_ldap_result
*/
if (last_ldap_result_holder != NULL) {
ldap_msgfree(last_ldap_result_holder);
last_ldap_result_holder = NULL;
last_ldap_result = NULL;
}
LM_DBG( "[%s]: performing LDAP search: dn [%s],"
" scope [%d], filter [%s], client_timeout [%d] usecs\n",
_lds_name,
_dn,
_scope,
_filter,
(int)(lds->client_search_timeout.tv_sec * 1000000
+ lds->client_search_timeout.tv_usec));
#ifdef LDAP_PERF
gettimeofday(&before_search, NULL);
#endif
/*
* perform ldap search
*/
*_ld_error = ldap_search_ext_s(
lds->handle,
_dn,
_scope,
_filter,
_attrs,
0,
NULL,
NULL,
&lds->client_search_timeout,
0,
&last_ldap_result_holder);
#ifdef LDAP_PERF
gettimeofday(&after_search, NULL);
LM_INFO("[%s]: LDAP search took [%d] usecs\n",
_lds_name,
(int)((after_search.tv_sec * 1000000 + after_search.tv_usec)
- (before_search.tv_sec * 1000000 + before_search.tv_usec)));
#endif
if (*_ld_error != LDAP_SUCCESS)
{
if (last_ldap_result_holder != NULL)
{
ldap_msgfree(last_ldap_result_holder);
last_ldap_result_holder = NULL;
}
if (LDAP_API_ERROR(*_ld_error))
{
ldap_disconnect(_lds_name);
}
LM_DBG( "[%s]: ldap_search_ext_st failed: %s\n",
_lds_name,
ldap_err2string(*_ld_error));
return -1;
}
last_ldap_handle = lds->handle;
*_ld_result_count = ldap_count_entries(lds->handle, last_ldap_result_holder);
if (*_ld_result_count < 0)
{
LM_DBG("[%s]: ldap_count_entries failed\n", _lds_name);
return -1;
}
last_ldap_result = last_ldap_result_holder;
return 0;
}