ld_con.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * LDAP Database Driver for SER
00005  *
00006  * Copyright (C) 2008 iptelorg GmbH
00007  *
00008  * This file is part of SER, a free SIP server.
00009  *
00010  * SER is free software; you can redistribute it and/or modify it under the
00011  * terms of the GNU General Public License as published by the Free Software
00012  * Foundation; either version 2 of the License, or (at your option) any later
00013  * version.
00014  *
00015  * SER is distributed in the hope that it will be useful, but WITHOUT ANY
00016  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
00018  * details.
00019  *
00020  * You should have received a copy of the GNU General Public License along
00021  * with this program; if not, write to the Free Software Foundation, Inc.,
00022  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
00023  */
00024 
00033 #include "ld_con.h"
00034 #include "ld_uri.h"
00035 
00036 #include "../../mem/mem.h"
00037 #include "../../dprint.h"
00038 #include "../../ut.h"
00039 
00040 #include <ldap.h>
00041 #include <stdlib.h>
00042 #include <string.h>
00043 #include <sasl/sasl.h>
00044 
00051 static void ld_con_free(db_con_t* con, struct ld_con* payload)
00052 {
00053         struct ld_uri* luri;
00054         int ret;
00055         if (!payload) return;
00056 
00057         luri = DB_GET_PAYLOAD(con->uri);
00058 
00059         /* Delete the structure only if there are no more references
00060          * to it in the connection pool
00061          */
00062         if (db_pool_remove((db_pool_entry_t*)payload) == 0) return;
00063 
00064         db_pool_entry_free(&payload->gen);
00065         if (payload->con) {
00066                 ret = ldap_unbind_ext_s(payload->con, NULL, NULL);
00067                 if (ret != LDAP_SUCCESS) {
00068                         ERR("ldap: Error while unbinding from %s: %s\n",
00069                                 luri->uri, ldap_err2string(ret));
00070                 }
00071         }
00072         pkg_free(payload);
00073 }
00074 
00075 
00076 int ld_con(db_con_t* con)
00077 {
00078         struct ld_con* lcon;
00079         struct ld_uri* luri;
00080 
00081         luri = DB_GET_PAYLOAD(con->uri);
00082 
00083         /* First try to lookup the connection in the connection pool and
00084          * re-use it if a match is found
00085          */
00086         lcon = (struct ld_con*)db_pool_get(con->uri);
00087         if (lcon) {
00088                 DBG("ldap: Connection to %s found in connection pool\n",
00089                         luri->uri);
00090                 goto found;
00091         }
00092 
00093         lcon = (struct ld_con*)pkg_malloc(sizeof(struct ld_con));
00094         if (!lcon) {
00095                 ERR("ldap: No memory left\n");
00096                 goto error;
00097         }
00098         memset(lcon, '\0', sizeof(struct ld_con));
00099         if (db_pool_entry_init(&lcon->gen, ld_con_free, con->uri) < 0) goto error;
00100 
00101         DBG("ldap: Preparing new connection to %s\n", luri->uri);
00102 
00103         /* Put the newly created LDAP connection into the pool */
00104         db_pool_put((struct db_pool_entry*)lcon);
00105         DBG("ldap: Connection stored in connection pool\n");
00106 
00107  found:
00108         /* Attach driver payload to the db_con structure and set connect and
00109          * disconnect functions
00110          */
00111         DB_SET_PAYLOAD(con, lcon);
00112         con->connect = ld_con_connect;
00113         con->disconnect = ld_con_disconnect;
00114         return 0;
00115 
00116  error:
00117         if (lcon) {
00118                 db_pool_entry_free(&lcon->gen);
00119                 pkg_free(lcon);
00120         }
00121         return -1;
00122 }
00123 
00124 
00125 int lutil_sasl_interact(
00126         LDAP *ld,
00127         unsigned flags,
00128         void *defaults,
00129         void *in )
00130 {
00131         sasl_interact_t *interact = in;
00132         const char *dflt = interact->defresult;
00133 
00134 
00135         if (ld == NULL)
00136                 return LDAP_PARAM_ERROR;
00137 
00138         while (interact->id != SASL_CB_LIST_END) {
00139                 switch( interact->id ) {
00140                         // the username to authenticate
00141                         case SASL_CB_AUTHNAME:
00142                                 if (defaults)
00143                                         dflt = ((struct ld_uri*)defaults)->username;
00144                                 break;
00145                         // the password for the provided username
00146                         case SASL_CB_PASS:
00147                                 if (defaults)
00148                                         dflt = ((struct ld_uri*)defaults)->password;
00149                                 break;
00150                         // the realm for the authentication attempt
00151                         case SASL_CB_GETREALM:
00152                         // the username to use for proxy authorization
00153                         case SASL_CB_USER:
00154                         // generic prompt for input with input echoing disabled
00155                         case SASL_CB_NOECHOPROMPT:
00156                         // generic prompt for input with input echoing enabled
00157                         case SASL_CB_ECHOPROMPT:
00158                                 break;
00159                 }
00160 
00161                 interact->result = (dflt && *dflt) ? dflt : "";
00162                 interact->len = strlen(interact->result);
00163 
00164                 interact++;
00165         }
00166 
00167         return LDAP_SUCCESS;
00168 }
00169 
00170 
00171 int ld_con_connect(db_con_t* con)
00172 {
00173         struct ld_con* lcon;
00174         struct ld_uri* luri;
00175         int ret, version = 3;
00176         char* err_str = NULL;
00177 
00178         lcon = DB_GET_PAYLOAD(con);
00179         luri = DB_GET_PAYLOAD(con->uri);
00180 
00181         /* Do not reconnect already connected connections */
00182         if (lcon->flags & LD_CONNECTED) return 0;
00183 
00184         DBG("ldap: Connecting to %s\n", luri->uri);
00185 
00186         if (lcon->con) {
00187                 ret = ldap_unbind_ext_s(lcon->con, NULL, NULL);
00188                 if (ret != LDAP_SUCCESS) {
00189                         ERR("ldap: Error while unbinding from %s: %s\n",
00190                                 luri->uri, ldap_err2string(ret));
00191                 }
00192         }
00193 
00194         /* we pass the TLS_REQCERT and TLS_REQCERT attributes over environment
00195            variables to ldap library */
00196         if (luri->tls) {
00197                 if (setenv("LDAPTLS_CACERT", luri->ca_list, 1)) {
00198                         ERR("ldap: Can't set environment variable 'LDAPTLS_CACERT'\n");
00199                         goto error;
00200                 }
00201                 if (setenv("LDAPTLS_REQCERT", luri->req_cert, 1)) {
00202                         ERR("ldap: Can't set environment variable 'LDAPTLS_REQCERT'\n");
00203                         goto error;
00204                 }
00205         }
00206 
00207         ret = ldap_initialize(&lcon->con, luri->uri);
00208         if (lcon->con == NULL) {
00209                 ERR("ldap: Error while initializing new LDAP connection to %s\n",
00210                         luri->uri);
00211                 goto error;
00212         }
00213 
00214         ret = ldap_set_option(lcon->con, LDAP_OPT_PROTOCOL_VERSION, &version);
00215         if (ret != LDAP_OPT_SUCCESS) {
00216                 ERR("ldap: Error while setting protocol version 3: %s\n",
00217                         ldap_err2string(ret));
00218                 goto error;
00219         }
00220 
00221         if (luri->tls) {
00222                 ret = ldap_start_tls_s(lcon->con, NULL, NULL);
00223                 if (ret != LDAP_SUCCESS) {
00224                         /* get addition info of this error */
00225 #ifdef OPENLDAP23
00226                         ldap_get_option(lcon->con, LDAP_OPT_ERROR_STRING, &err_str);
00227 #elif OPENLDAP24
00228                         ldap_get_option(lcon->con, LDAP_OPT_DIAGNOSTIC_MESSAGE, &err_str);
00229 #endif
00230                         ERR("ldap: Error while starting TLS: %s\n", ldap_err2string(ret));
00231                         if (err_str) {
00232                                 ERR("ldap: %s\n", err_str);
00233                                 ldap_memfree(err_str);
00234                         }
00235                         goto error;
00236                 }
00237         }
00238 
00239         switch (luri->authmech) {
00240                 case LDAP_AUTHMECH_NONE:
00241                         ret = ldap_simple_bind_s(lcon->con, NULL, NULL);
00242                         break;
00243                 case LDAP_AUTHMECH_SIMPLE:
00244                         ret = ldap_simple_bind_s(lcon->con, luri->username, luri->password);
00245                         break;
00246                 case LDAP_AUTHMECH_DIGESTMD5:
00247                         ret = ldap_sasl_interactive_bind_s( lcon->con, NULL,
00248                                         LDAP_MECHANISM_STR_DIGESTMD5, NULL, NULL,
00249                                         0, lutil_sasl_interact, luri );
00250                         break;
00251                 case LDAP_AUTHMECH_EXTERNAL:
00252                 default:
00253                         ret = !LDAP_SUCCESS;
00254                         break;
00255         }
00256 
00257         if (ret != LDAP_SUCCESS) {
00258                 ERR("ldap: Bind to %s failed: %s\n",
00259                         luri->uri, ldap_err2string(ret));
00260                 goto error;
00261         }
00262 
00263         DBG("ldap: Successfully bound to %s\n", luri->uri);
00264         lcon->flags |= LD_CONNECTED;
00265         return 0;
00266 
00267  error:
00268         if (lcon->con) {
00269                 ret = ldap_unbind_ext_s(lcon->con, NULL, NULL);
00270                 if (ret) {
00271                         ERR("ldap: Error while unbinding from %s: %s\n",
00272                                 luri->uri, ldap_err2string(ret));
00273                 }
00274         }
00275         lcon->con = NULL;
00276         return -1;
00277 }
00278 
00279 
00280 void ld_con_disconnect(db_con_t* con)
00281 {
00282         struct ld_con* lcon;
00283         struct ld_uri* luri;
00284         int ret;
00285 
00286         lcon = DB_GET_PAYLOAD(con);
00287         luri = DB_GET_PAYLOAD(con->uri);
00288 
00289         if ((lcon->flags & LD_CONNECTED) == 0) return;
00290 
00291         DBG("ldap: Unbinding from %s\n", luri->uri);
00292 
00293         if (lcon->con) {
00294                 ret = ldap_unbind_ext_s(lcon->con, NULL, NULL);
00295                 if (ret) {
00296                         ERR("ldap: Error while unbinding from %s: %s\n",
00297                                 luri->uri, ldap_err2string(ret));
00298                 }
00299         }
00300 
00301         lcon->con = NULL;
00302         lcon->flags &= ~LD_CONNECTED;
00303 }
00304 
00305