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_connect.c

312 lines
6.0 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 <string.h>
#include <unistd.h>
#include <stdio.h>
#include <ldap.h>
#include "ldap_connect.h"
#include "ld_session.h"
#include "../../mem/mem.h"
#include "../../ut.h"
int ldap_connect_ex(char* _ld_name, int llevel)
{
int rc;
int ldap_bind_result_code;
char *ldap_err_str;
int ldap_proto_version;
int msgid;
LDAPMessage *result;
struct ld_session* lds;
struct berval ldap_cred;
/*
* get ld session and session config parameters
*/
if ((lds = get_ld_session(_ld_name)) == NULL)
{
LM_ERR("ld_session [%s] not found\n", _ld_name);
return -1;
}
/*
* ldap_initialize
*/
rc = ldap_initialize(&lds->handle, lds->host_name);
if (rc != LDAP_SUCCESS)
{
LM_ERR( "[%s]: ldap_initialize (%s) failed: %s\n",
_ld_name,
lds->host_name,
ldap_err2string(rc));
return -1;
}
/*
* set LDAP OPTIONS
*/
/* LDAP_OPT_PROTOCOL_VERSION */
switch (lds->version) {
case 2:
ldap_proto_version = LDAP_VERSION2;
break;
case 3:
ldap_proto_version = LDAP_VERSION3;
break;
default:
LM_ERR( "[%s]: Invalid LDAP protocol version [%d]\n",
_ld_name,
lds->version);
return -1;
}
if (ldap_set_option(lds->handle,
LDAP_OPT_PROTOCOL_VERSION,
&ldap_proto_version)
!= LDAP_OPT_SUCCESS)
{
LM_ERR( "[%s]: Could not set LDAP_OPT_PROTOCOL_VERSION [%d]\n",
_ld_name,
ldap_proto_version);
return -1;
}
/* LDAP_OPT_RESTART */
if (ldap_set_option(lds->handle,
LDAP_OPT_RESTART,
LDAP_OPT_ON)
!= LDAP_OPT_SUCCESS) {
LM_ERR("[%s]: Could not set LDAP_OPT_RESTART to ON\n", _ld_name);
return -1;
}
/* LDAP_OPT_TIMELIMIT */
/*
if (lds->server_search_timeout > 0) {
if (ldap_set_option(lds->handle,
LDAP_OPT_TIMELIMIT,
&lds->server_search_timeout)
!= LDAP_OPT_SUCCESS) {
LM_ERR("[%s]: Could not set LDAP_OPT_TIMELIMIT to [%d]\n",
_ld_name, lds->server_search_timeout);
return -1;
}
}
*/
/* LDAP_OPT_NETWORK_TIMEOUT */
if ((lds->network_timeout.tv_sec > 0) || (lds->network_timeout.tv_usec > 0))
{
if (ldap_set_option(lds->handle,
LDAP_OPT_NETWORK_TIMEOUT,
(const void *)&lds->network_timeout)
!= LDAP_OPT_SUCCESS)
{
LM_ERR( "[%s]: Could not set"
" LDAP_NETWORK_TIMEOUT to [%d.%d]\n",
_ld_name,
(int)lds->network_timeout.tv_sec,
(int)lds->network_timeout.tv_usec);
}
}
/*
* ldap_sasl_bind (LDAP_SASL_SIMPLE)
*/
ldap_cred.bv_val = lds->bind_pwd;
ldap_cred.bv_len = strlen(lds->bind_pwd);
rc = ldap_sasl_bind(
lds->handle,
lds->bind_dn,
LDAP_SASL_SIMPLE,
&ldap_cred,
NULL,
NULL,
&msgid);
if (rc != LDAP_SUCCESS)
{
LM_ERR( "[%s]: ldap bind failed: %s\n",
_ld_name,
ldap_err2string(rc));
return -1;
}
if ((lds->client_bind_timeout.tv_sec == 0)
&& (lds->client_bind_timeout.tv_usec == 0))
{
rc = ldap_result(lds->handle, msgid, 1, NULL, &result);
} else
{
rc = ldap_result(lds->handle, msgid, 1, &lds->client_bind_timeout,
&result);
}
if (rc == -1)
{
ldap_get_option(lds->handle, LDAP_OPT_ERROR_NUMBER, &rc);
ldap_err_str = ldap_err2string(rc);
LM_ERR( "[%s]: ldap_result failed: %s\n",
_ld_name,
ldap_err_str);
return -1;
}
else if (rc == 0)
{
LM_ERR("[%s]: bind operation timed out\n", _ld_name);
return -1;
}
rc = ldap_parse_result(
lds->handle,
result,
&ldap_bind_result_code,
NULL,
NULL,
NULL,
NULL,
1);
if (rc != LDAP_SUCCESS)
{
LM_ERR( "[%s]: ldap_parse_result failed: %s\n",
_ld_name,
ldap_err2string(rc));
return -1;
}
if (ldap_bind_result_code != LDAP_SUCCESS)
{
LM_ERR( "[%s]: ldap bind failed: %s\n",
_ld_name,
ldap_err2string(ldap_bind_result_code));
return -1;
}
/* freeing result leads to segfault ... bind result is probably used by openldap lib */
/* ldap_msgfree(result); */
LOG(llevel, "[%s]: LDAP bind successful (ldap_host [%s])\n",
_ld_name,
lds->host_name);
return 0;
}
int ldap_connect(char* _ld_name)
{
return ldap_connect_ex(_ld_name, L_DBG);
}
int ldap_disconnect(char* _ld_name)
{
struct ld_session* lds;
/*
* get ld session
*/
if ((lds = get_ld_session(_ld_name)) == NULL)
{
LM_ERR("ld_session [%s] not found\n", _ld_name);
return -1;
}
if (lds->handle == NULL) {
return 0;
}
ldap_unbind_ext(lds->handle, NULL, NULL);
lds->handle = NULL;
return 0;
}
int ldap_reconnect(char* _ld_name)
{
int rc;
if (ldap_disconnect(_ld_name) != 0)
{
LM_ERR("[%s]: disconnect failed\n", _ld_name);
return -1;
}
if ((rc = ldap_connect_ex(_ld_name, L_INFO)) != 0)
{
LM_ERR("[%s]: reconnect failed\n",
_ld_name);
}
else
{
LM_NOTICE("[%s]: LDAP reconnect successful\n",
_ld_name);
}
return rc;
}
int ldap_get_vendor_version(char** _version)
{
static char version[128];
LDAPAPIInfo api;
int rc;
#ifdef LDAP_API_INFO_VERSION
api.ldapai_info_version = LDAP_API_INFO_VERSION;
#else
api.ldapai_info_version = 1;
#endif
if (ldap_get_option(NULL, LDAP_OPT_API_INFO, &api) != LDAP_SUCCESS)
{
LM_ERR("ldap_get_option(API_INFO) failed\n");
return -1;
}
rc = snprintf(version, 128, "%s - %d", api.ldapai_vendor_name,
api.ldapai_vendor_version);
if ((rc >= 128) || (rc < 0))
{
LM_ERR("snprintf failed\n");
return -1;
}
*_version = version;
return 0;
}