ld_uri.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_uri.h"
00034 #include "ld_cfg.h"
00035 
00036 #include "../../mem/mem.h"
00037 #include "../../ut.h"
00038 
00039 #include <string.h>
00040 
00045 #define cmpstr(s1, s2, f) \
00046         ((s1)!=(s2)) && ((s1)==0 || (s2)==0 || (f)((s1), (s2))!=0)
00047 
00048 
00057 static unsigned char ld_uri_cmp(db_uri_t* uri1, db_uri_t* uri2)
00058 {
00059         struct ld_uri* luri1, *luri2;
00060 
00061         if (!uri1 || !uri2) return 0;
00062 
00063         luri1 = DB_GET_PAYLOAD(uri1);
00064         luri2 = DB_GET_PAYLOAD(uri2);
00065 
00066         if (luri1->ldap_url->lud_port != luri2->ldap_url->lud_port) return 0;
00067         if (cmpstr(luri1->ldap_url->lud_host,
00068                            luri2->ldap_url->lud_host, strcasecmp))
00069                 return 0;
00070         return 1;
00071 }
00072 
00075 static int dupl_string(char** dst, const char* begin, const char* end)
00076 {
00077         if (*dst) pkg_free(*dst);
00078 
00079         *dst = pkg_malloc(end - begin + 1);
00080         if ((*dst) == NULL) {
00081                 return -1;
00082         }
00083 
00084         memcpy(*dst, begin, end - begin);
00085         (*dst)[end - begin] = '\0';
00086         return 0;
00087 }
00088 
00091 static char* pkgstrdup(str* s)
00092 {
00093         char* dst;
00094 
00095         if (!s)
00096                 return NULL;
00097 
00098         dst = pkg_malloc(s->len + 1);
00099         if (dst == NULL)
00100                 return NULL;
00101 
00102         memcpy(dst, s->s, s->len);
00103         dst[s->len] = '\0';
00104 
00105         return dst;
00106 }
00107 
00108 
00109 /*
00110  * Parse ldap URI of form
00111  * //[username[:password]@]hostname[:port]
00112  *
00113  * Returns 0 if parsing was successful and -1 otherwise
00114  */
00115 int parse_ldap_uri(struct ld_uri* res, str* scheme, str* uri)
00116 {
00117 #define SHORTEST_DB_URL "a"
00118 #define SHORTEST_DB_URL_LEN (sizeof(SHORTEST_DB_URL) - 1)
00119 
00120         enum state {
00121                 ST_BEGIN,      /* First state */
00122                 ST_SECTION_ID,  /* Config section id */
00123                 ST_SLASH2,     /* Second slash */
00124                 ST_USER_HOST,  /* Username or hostname */
00125                 ST_PASS_PORT,  /* Password or port part */
00126                 ST_HOST_PORT   /* Hostname and port part */
00127         };
00128         enum state st;
00129         int  i, ldapurllen;
00130         const char* begin;
00131         const char* ldapbegin;
00132         char* prev_token;
00133         struct ld_con_info* cfg_conn_info;
00134         char* sport, *puri;
00135         int portlen = 0;
00136 
00137         prev_token = 0;
00138 
00139         if (!res || !scheme || !uri) {
00140                 goto err;
00141         }
00142 
00143         if (uri->len < SHORTEST_DB_URL_LEN) {
00144                 goto err;
00145         }
00146 
00147         st = ST_BEGIN;
00148         ldapbegin = begin = uri->s;
00149 
00150         for(i = 0; i < uri->len && st != ST_SECTION_ID; i++) {
00151                 switch(st) {
00152                 case ST_BEGIN:
00153                         switch(uri->s[i]) {
00154                         case '/':
00155                                 st = ST_SLASH2;
00156                                 break;
00157 
00158                         default:
00159                                 st = ST_SECTION_ID;
00160                         }
00161                         break;
00162 
00163                 case ST_SECTION_ID:
00164                         break;
00165 
00166                 case ST_SLASH2:
00167                         switch(uri->s[i]) {
00168                         case '/':
00169                                 st = ST_USER_HOST;
00170                                 ldapbegin = begin = uri->s + i + 1;
00171                                 break;
00172 
00173                         default:
00174                                 goto err;
00175                         }
00176                         break;
00177 
00178                 case ST_USER_HOST:
00179                         switch(uri->s[i]) {
00180                         case '@':
00181                                 st = ST_HOST_PORT;
00182                                 if (dupl_string(&res->username, begin, uri->s + i) < 0) goto err;
00183                                 ldapbegin = begin = uri->s + i + 1;
00184                                 break;
00185 
00186                         case ':':
00187                                 st = ST_PASS_PORT;
00188                                 if (dupl_string(&prev_token, begin, uri->s + i) < 0) goto err;
00189                                 begin = uri->s + i + 1;
00190                                 break;
00191                         }
00192                         break;
00193 
00194                 case ST_PASS_PORT:
00195                         switch(uri->s[i]) {
00196                         case '@':
00197                                 st = ST_HOST_PORT;
00198                                 res->username = prev_token;
00199                                 if (dupl_string(&res->password, begin, uri->s + i) < 0) goto err;
00200                                 ldapbegin = begin = uri->s + i + 1;
00201                                 break;
00202                         }
00203                         break;
00204 
00205                 case ST_HOST_PORT:
00206                         break;
00207                 }
00208         }
00209 
00210         switch(st) {
00211         case ST_PASS_PORT:
00212         case ST_USER_HOST:
00213         case ST_HOST_PORT:
00214                 ldapurllen = uri->len - (int)(ldapbegin - uri->s);
00215                 // +3 for the '://' ldap url snippet
00216                 res->uri = pkg_malloc(scheme->len + 3 + ldapurllen + 1);
00217                 if (res->uri== NULL) {
00218                         ERR("ldap: No memory left\n");
00219                         goto err;
00220                 }
00221                 memcpy(res->uri, scheme->s, scheme->len);
00222                 res->uri[scheme->len] = ':';
00223                 res->uri[scheme->len + 1] = '/';
00224                 res->uri[scheme->len + 2] = '/';
00225                 memcpy(res->uri + scheme->len + 3, ldapbegin, ldapurllen);
00226                 res->uri[scheme->len + 3 + ldapurllen] = '\0';
00227 
00228                 if (ldap_url_parse(res->uri, &res->ldap_url) != 0) {
00229                         ERR("ldap: Error while parsing URL '%s'\n", res->uri);
00230                         goto err;
00231                 }
00232                 break;
00233         case ST_SECTION_ID:
00234                 /* the value of uri is the id of the config
00235                    connection section in this case */
00236                 cfg_conn_info = ld_find_conn_info(uri);
00237                 if (!cfg_conn_info) {
00238                         ERR("ldap: connection id '%.*s' not found in ldap config\n", uri->len, uri->s);
00239                         goto err;
00240                 }
00241 
00242                 ldapurllen = cfg_conn_info->host.len;
00243                 sport = NULL;
00244                 if (cfg_conn_info->port) {
00245                         sport = int2str(cfg_conn_info->port, &portlen);
00246                         // +1: we need space for ':' host and port delimiter
00247                         ldapurllen += portlen + 1;
00248                 }
00249 
00250                 // +3 for the '://' ldap url snippet
00251                 puri = res->uri = pkg_malloc(scheme->len + 3 + ldapurllen + 1);
00252                 if (res->uri== NULL) {
00253                         ERR("ldap: No memory left\n");
00254                         goto err;
00255                 }
00256                 memcpy(puri, scheme->s, scheme->len);
00257                 puri += scheme->len;
00258                 memcpy(puri, "://", strlen("://"));
00259                 puri+= strlen("://");
00260                 memcpy(puri, cfg_conn_info->host.s, cfg_conn_info->host.len);
00261                 puri+=cfg_conn_info->host.len;
00262                 if (sport) {
00263                         *puri++ = ':';
00264                         memcpy(puri, sport, portlen);
00265                 }
00266                 res->uri[scheme->len + 3 + ldapurllen] = '\0';
00267 
00268                 if (ldap_url_parse(res->uri, &res->ldap_url) != 0) {
00269                         ERR("ldap: Error while parsing URL '%s'\n", res->uri);
00270                         goto err;
00271                 }
00272 
00273                 if (cfg_conn_info->username.s) {
00274                         if (!(res->username = pkgstrdup(&cfg_conn_info->username))) {
00275                                 ERR("ldap: No memory left\n");
00276                                 goto err;
00277                         }
00278                 }
00279 
00280                 if (cfg_conn_info->password.s) {
00281                         if (!(res->password = pkgstrdup(&cfg_conn_info->password))) {
00282                                 ERR("ldap: No memory left\n");
00283                                 goto err;
00284                         }
00285                 }
00286 
00287                 res->authmech = cfg_conn_info->authmech;
00288                 res->tls = cfg_conn_info->tls;
00289                 if (cfg_conn_info->ca_list.s) {
00290                         if (!(res->ca_list = pkgstrdup(&cfg_conn_info->ca_list))) {
00291                                         ERR("ldap: No memory left\n");
00292                                         goto err;
00293                         }
00294                 }
00295                 if (cfg_conn_info->req_cert.s) {
00296                         if (!(res->req_cert = pkgstrdup(&cfg_conn_info->req_cert))) {
00297                                         ERR("ldap: No memory left\n");
00298                                         goto err;
00299                         }
00300                 }
00301 
00302                 break;
00303         default:
00304                 goto err;
00305         }
00306 
00307         return 0;
00308 
00309  err:
00310         if (prev_token) pkg_free(prev_token);
00311         if (res == NULL) return -1;
00312         if (res->username) {
00313                 pkg_free(res->username);
00314                 res->username = NULL;
00315         }
00316         if (res->password) {
00317                 pkg_free(res->password);
00318                 res->password = NULL;
00319         }
00320         if (res->ca_list) {
00321                 pkg_free(res->ca_list);
00322                 res->ca_list = NULL;
00323         }
00324         if (res->req_cert) {
00325                 pkg_free(res->req_cert);
00326                 res->req_cert = NULL;
00327         }
00328         return -1;
00329 }
00330 
00331 static void ld_uri_free(db_uri_t* uri, struct ld_uri* payload)
00332 {
00333         if (payload == NULL) return;
00334         if (payload->ldap_url) ldap_free_urldesc(payload->ldap_url);
00335         if (payload->uri) pkg_free(payload->uri);
00336     if (payload->username) pkg_free(payload->username);
00337     if (payload->password) pkg_free(payload->password);
00338     if (payload->ca_list) pkg_free(payload->ca_list);
00339     if (payload->req_cert) pkg_free(payload->req_cert);
00340         db_drv_free(&payload->drv);
00341         pkg_free(payload);
00342 }
00343 
00344 
00345 int ld_uri(db_uri_t* uri)
00346 {
00347         struct ld_uri* luri;
00348 
00349         luri = (struct ld_uri*)pkg_malloc(sizeof(struct ld_uri));
00350         if (luri == NULL) {
00351                 ERR("ldap: No memory left\n");
00352                 goto error;
00353         }
00354         memset(luri, '\0', sizeof(struct ld_uri));
00355         if (db_drv_init(&luri->drv, ld_uri_free) < 0) goto error;
00356     if (parse_ldap_uri(luri,  &uri->scheme, &uri->body) < 0) goto error;
00357 
00358         DB_SET_PAYLOAD(uri, luri);
00359         uri->cmp = ld_uri_cmp;
00360         return 0;
00361 
00362  error:
00363         if (luri) {
00364                 if (luri->uri) pkg_free(luri->uri);
00365                 if (luri->ldap_url) ldap_free_urldesc(luri->ldap_url);
00366                 db_drv_free(&luri->drv);
00367                 pkg_free(luri);
00368         }
00369         return -1;
00370 }
00371 
00372