/* * 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 #include #include "../../ut.h" #include #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; }