ldap_mod.c

00001 /*
00002  * $Id$
00003  *
00004  * Kamailio LDAP Module
00005  *
00006  * Copyright (C) 2007 University of North Carolina
00007  *
00008  * Original author: Christian Schlatter, cs@unc.edu
00009  *
00010  *
00011  * This file is part of Kamailio, a free SIP server.
00012  *
00013  * Kamailio is free software; you can redistribute it and/or modify
00014  * it under the terms of the GNU General Public License as published by
00015  * the Free Software Foundation; either version 2 of the License, or
00016  * (at your option) any later version
00017  *
00018  * Kamailio is distributed in the hope that it will be useful,
00019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  * GNU General Public License for more details.
00022  *
00023  * You should have received a copy of the GNU General Public License
00024  * along with this program; if not, write to the Free Software
00025  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00026  *
00027  * History:
00028  * --------
00029  * 2007-02-18: Initial version
00030  */
00031 
00032 
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <sys/time.h>
00036 
00037 #include "../../ut.h"
00038 #include "../../parser/hf.h"
00039 #include "../../sr_module.h"
00040 #include "../../pvar.h"
00041 #include "../../mem/mem.h"
00042 
00043 #include "ld_session.h"
00044 #include "ldap_exp_fn.h"
00045 #include "api.h"
00046 #include "ldap_connect.h"
00047 #include "ldap_api_fn.h"
00048 #include "iniparser.h"
00049 
00050 MODULE_VERSION
00051 
00052 /*
00053 * Module management function prototypes
00054 */
00055 static int mod_init(void);
00056 static void destroy(void);
00057 static int child_init(int rank);
00058 
00059 /*
00060 * fixup functions
00061 */
00062 static int ldap_search_fixup(void** param, int param_no);
00063 static int ldap_result_fixup(void** param, int param_no);
00064 static int ldap_filter_url_encode_fixup(void** param, int param_no);
00065 static int ldap_result_check_fixup(void** param, int param_no);
00066 
00067 /*
00068 * exported functions
00069 */
00070 
00071 static int w_ldap_search(struct sip_msg* msg, char* ldap_url, char* param);
00072 static int w_ldap_result1(struct sip_msg* msg, char* src, char* param);
00073 static int w_ldap_result2(struct sip_msg* msg, char* src, char* subst);
00074 static int w_ldap_result_next(struct sip_msg* msg, char* foo, char *bar);
00075 static int w_ldap_filter_url_encode(struct sip_msg* msg, 
00076                 char* filter_component, char* dst_avp_name);
00077 static int w_ldap_result_check_1(struct sip_msg* msg, 
00078                 char* attr_name_check_str, char* param);
00079 static int w_ldap_result_check_2(struct sip_msg* msg,
00080                 char* attr_name_check_str, char* attr_val_re);
00081 
00082 
00083 /* 
00084 * Default module parameter values 
00085 */
00086 #define DEF_LDAP_CONFIG "/usr/local/etc/kamailio/ldap.cfg"
00087 
00088 /*
00089 * Module parameter variables
00090 */
00091 str ldap_config = str_init(DEF_LDAP_CONFIG);
00092 static dictionary* config_vals = NULL;
00093 
00094 /*
00095 * Exported functions
00096 */
00097 static cmd_export_t cmds[] = {
00098         {"ldap_search",            (cmd_function)w_ldap_search,            1, 
00099                 ldap_search_fixup, 0,
00100                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
00101         {"ldap_result",            (cmd_function)w_ldap_result1,           1, 
00102                 ldap_result_fixup, 0,
00103                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
00104         {"ldap_result",            (cmd_function)w_ldap_result2,           2, 
00105                 ldap_result_fixup, 0,
00106                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
00107         {"ldap_result_next",       (cmd_function)w_ldap_result_next,       0, 
00108                 0, 0,
00109                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
00110         {"ldap_result_check",      (cmd_function)w_ldap_result_check_1,    1, 
00111                 ldap_result_check_fixup, 0,
00112                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
00113         {"ldap_result_check",      (cmd_function)w_ldap_result_check_2,    2, 
00114                 ldap_result_check_fixup, 0,
00115                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
00116         {"ldap_filter_url_encode", (cmd_function)w_ldap_filter_url_encode, 2, 
00117                 ldap_filter_url_encode_fixup, 0,
00118                 REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE|ONREPLY_ROUTE|LOCAL_ROUTE},
00119         {"load_ldap",              (cmd_function)load_ldap,  0,
00120                 0, 0,
00121                 0},
00122         {0, 0, 0, 0, 0, 0}
00123 };
00124 
00125 
00126 /*
00127 * Exported parameters
00128 */
00129 static param_export_t params[] = {
00130 
00131         {"config_file",          STR_PARAM, &ldap_config},
00132         {0, 0, 0}
00133 };
00134 
00135 
00136 /*
00137 * Module interface
00138 */
00139 struct module_exports exports = {
00140         "ldap", 
00141         DEFAULT_DLFLAGS, /* dlopen flags */
00142         cmds,       /* Exported functions */
00143         params,     /* Exported parameters */
00144         0,          /* exported statistics */
00145         0,          /* exported MI functions */
00146         0,          /* exported pseudo-variables */
00147         0,          /* extra processes */
00148         mod_init,   /* module initialization function */
00149         0,          /* response function */
00150         destroy,    /* destroy function */
00151         child_init  /* child initialization function */
00152 };
00153 
00154 
00155 static int child_init(int rank)
00156 {
00157         int i = 0, ld_count = 0;
00158         char* ld_name;
00159         
00160         /* don't do anything for non-worker processes */
00161         if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
00162                 return 0;
00163 
00164         /*
00165         * build ld_sessions and connect all sessions
00166         */
00167         ld_count = iniparser_getnsec(config_vals);
00168         for (i = 0; i < ld_count; i++)
00169         {
00170                 ld_name = iniparser_getsecname(config_vals, i);
00171                 if (add_ld_session(ld_name,
00172                                         NULL,
00173                                         config_vals)
00174                                 != 0)
00175                 {
00176                         LM_ERR("[%s]: add_ld_session failed\n", ld_name);
00177                         return -1;
00178                 }
00179 
00180                 if (ldap_connect(ld_name) != 0)
00181                 {
00182                         LM_ERR("[%s]: failed to connect to LDAP host(s)\n", ld_name);
00183                         ldap_disconnect(ld_name);
00184                         return -1;
00185                 }
00186                 
00187         }
00188         
00189         return 0;
00190 }
00191 
00192 
00193 static int mod_init(void)
00194 {
00195         int ld_count = 0, i = 0;
00196         char* section_name;
00197         char* ldap_version;
00198         
00199         /*
00200         * read config file
00201         */
00202         if (strlen(ldap_config.s) == 0)
00203         {
00204                 LM_ERR("config_file is empty - this module param is mandatory\n");
00205                 return -2;
00206         }
00207         if ((config_vals = iniparser_new(ldap_config.s)) == NULL)
00208         {
00209                 LM_ERR("failed to read config_file [%s]\n", ldap_config.s);
00210                 return -2;
00211         }
00212         if ((ld_count = iniparser_getnsec(config_vals)) < 1)
00213         {
00214                 LM_ERR("no section found in config_file [%s]\n", ldap_config.s);
00215                 return -2;
00216         }
00217         /* check if mandatory settings are present */
00218         for (i = 0; i < ld_count; i++)
00219         {
00220                 section_name = iniparser_getsecname(config_vals, i);
00221                 if (strlen(section_name) > 255)
00222                 {
00223                         LM_ERR( "config_file section name [%s]"
00224                                 " longer than allowed 255 characters",
00225                                 section_name);
00226                         return -2;
00227                 }
00228                 if (!iniparser_find_entry(config_vals,
00229                                         get_ini_key_name(section_name, CFG_N_LDAP_HOST)))
00230                 {
00231                         LM_ERR( "mandatory %s not defined in [%s]\n", 
00232                                 CFG_N_LDAP_HOST, 
00233                                 section_name);
00234                         return -2;
00235                 }
00236         }       
00237         
00238         /*
00239         * print ldap version string
00240         */
00241         if (ldap_get_vendor_version(&ldap_version) != 0)
00242         {
00243                 LM_ERR("ldap_get_vendor_version failed\n");
00244                 return -2;
00245         }
00246         LM_INFO("%s\n", ldap_version);
00247 
00248         return 0;
00249 }
00250 
00251 
00252 static void destroy(void)
00253 {
00254         /* ldap_unbind */
00255         free_ld_sessions();
00256 
00257         /* free config file memory */
00258         iniparser_free(config_vals);
00259 }
00260 
00261 
00262 /*
00263 * EXPORTED functions
00264 */
00265 
00266 static int w_ldap_search(struct sip_msg* msg, char* ldap_url, char* param)
00267 {
00268         return ldap_search_impl(msg, (pv_elem_t*)ldap_url);
00269 }
00270 
00271 static int w_ldap_result1(struct sip_msg* msg, char* src, char* param)
00272 {
00273         return ldap_write_result(msg, (struct ldap_result_params*)src, NULL);
00274 }
00275 
00276 static int w_ldap_result2(struct sip_msg* msg, char* src, char* subst)
00277 {
00278         return ldap_write_result(msg, (struct ldap_result_params*)src,
00279                         (struct subst_expr*)subst);
00280 }
00281 
00282 static int w_ldap_result_next(struct sip_msg* msg, char* foo, char *bar)
00283 {
00284         return ldap_result_next();
00285 }
00286 
00287 static int w_ldap_filter_url_encode(struct sip_msg* msg,
00288                 char* filter_component, char* dst_avp_name)
00289 {
00290         return ldap_filter_url_encode(msg, (pv_elem_t*)filter_component,
00291                         (pv_spec_t*)dst_avp_name);
00292 }
00293 
00294 static int w_ldap_result_check_1(struct sip_msg* msg,
00295                 char* attr_name_check_str, char* param)
00296 {
00297         return ldap_result_check(msg,
00298                         (struct ldap_result_check_params*)attr_name_check_str, NULL);
00299 }
00300 
00301 static int w_ldap_result_check_2(struct sip_msg* msg,
00302                 char* attr_name_check_str, char* attr_val_re)
00303 {
00304         return ldap_result_check( msg, 
00305                 (struct ldap_result_check_params*)attr_name_check_str, 
00306                 (struct subst_expr*)attr_val_re);
00307 }
00308 
00309 /*
00310 * FIXUP functions
00311 */
00312 
00313 static int ldap_search_fixup(void** param, int param_no)
00314 {
00315         pv_elem_t *model;
00316         str s;
00317 
00318         if (param_no == 1) {
00319                 s.s = (char*)*param;
00320                 s.len = strlen(s.s);
00321                 if (s.len==0) {
00322                         LM_ERR("ldap url is empty string!\n");
00323                         return E_CFG;
00324                 }
00325                 if ( pv_parse_format(&s,&model) || model==NULL) {
00326                         LM_ERR("wrong format [%s] for ldap url!\n", s.s);
00327                         return E_CFG;
00328                 }
00329                 *param = (void*)model;
00330         }
00331 
00332         return 0;
00333 }
00334 
00335 static int ldap_result_fixup(void** param, int param_no)
00336 {
00337         struct ldap_result_params* lp;
00338         struct subst_expr* se;
00339         str subst;
00340         char *arg_str, *dst_avp_str, *dst_avp_val_type_str;
00341         char *p;
00342         str s;
00343         int dst_avp_val_type = 0;
00344         
00345         if (param_no == 1) {
00346                 arg_str = (char*)*param;
00347                 if ((dst_avp_str = strchr(arg_str, '/')) == 0) 
00348                 {
00349                         /* no / found in arg_str */
00350                         LM_ERR("invalid first argument [%s]\n", arg_str);
00351                         return E_UNSPEC;
00352                 }
00353                 *(dst_avp_str++) = 0;
00354 
00355                 if ((dst_avp_val_type_str = strchr(dst_avp_str, '/')))
00356                 {
00357                         *(dst_avp_val_type_str++) = 0;
00358                         if (!strcmp(dst_avp_val_type_str, "int"))
00359                         {
00360                                 dst_avp_val_type = 1;
00361                         }
00362                         else if (strcmp(dst_avp_val_type_str, "str"))
00363                         {
00364                                 LM_ERR( "invalid avp_type [%s]\n",
00365                                         dst_avp_val_type_str);
00366                                 return E_UNSPEC;
00367                         }
00368                 }
00369 
00370                 lp = (struct ldap_result_params*)pkg_malloc(sizeof(struct ldap_result_params));
00371                 if (lp == NULL) {
00372                         LM_ERR("no memory\n");
00373                         return E_OUT_OF_MEM;
00374                 }
00375                 memset(lp, 0, sizeof(struct ldap_result_params));
00376                 
00377                 lp->ldap_attr_name.s = arg_str;
00378                 lp->ldap_attr_name.len = strlen(arg_str);
00379 
00380                 lp->dst_avp_val_type = dst_avp_val_type;
00381                 s.s = dst_avp_str; s.len = strlen(s.s);
00382                 p = pv_parse_spec(&s, &lp->dst_avp_spec);
00383                 if (p == 0) {
00384                         pkg_free(lp);
00385                         LM_ERR("parse error for [%s]\n",
00386                                         dst_avp_str);
00387                         return E_UNSPEC;
00388                 }
00389                 if (lp->dst_avp_spec.type != PVT_AVP) {
00390                         pkg_free(lp);
00391                         LM_ERR( "bad attribute name [%s]\n",
00392                                 dst_avp_str);
00393                         return E_UNSPEC;
00394                 }
00395                 *param = (void*)lp;
00396                 
00397         } else if (param_no == 2) {
00398                 subst.s = *param;
00399                 subst.len = strlen(*param);
00400                 se = subst_parser(&subst);
00401                 if (se == 0) {
00402                         LM_ERR("bad subst re [%s]\n",
00403                         (char*)*param);
00404                         return E_BAD_RE;
00405                 }
00406                 *param = (void*)se;
00407         }
00408 
00409         return 0;
00410 }
00411 
00412 static int ldap_result_check_fixup(void** param, int param_no)
00413 {
00414         struct ldap_result_check_params *lp;
00415         struct subst_expr *se;
00416         str subst;
00417         str s;
00418         char *arg_str, *check_str;
00419         int arg_str_len;
00420         
00421         if (param_no == 1)
00422         {
00423                 arg_str = (char*)*param;
00424                 arg_str_len = strlen(arg_str);
00425                 if ((check_str = strchr(arg_str, '/')) == 0)
00426                 {
00427                         /* no / found in arg_str */
00428                         LM_ERR( "invalid first argument [%s] (no '/' found)\n",
00429                                 arg_str);
00430                         return E_UNSPEC;
00431                 }
00432                 *(check_str++) = 0;
00433                 
00434                 lp = (struct ldap_result_check_params*)pkg_malloc(sizeof(struct ldap_result_check_params));
00435                 if (lp == NULL) {
00436                         LM_ERR("no memory\n");
00437                         return E_OUT_OF_MEM;
00438                 }
00439                 memset(lp, 0, sizeof(struct ldap_result_check_params));
00440 
00441                 lp->ldap_attr_name.s = arg_str;
00442                 lp->ldap_attr_name.len = strlen(arg_str);
00443 
00444                 if (lp->ldap_attr_name.len + 1 == arg_str_len)
00445                 {
00446                         /* empty check_str */
00447                         lp->check_str_elem_p = 0;
00448                 }
00449                 else
00450                 {
00451                         s.s = check_str; s.len = strlen(s.s);
00452                         if (pv_parse_format(&s, &(lp->check_str_elem_p)) < 0)
00453                         {
00454                                 LM_ERR("pv_parse_format failed\n");
00455                                 return E_OUT_OF_MEM;
00456                         }
00457                 }       
00458                 *param = (void*)lp;
00459         }
00460         else if (param_no == 2)
00461         {
00462                 subst.s = *param;
00463                 subst.len = strlen(*param);
00464                 se = subst_parser(&subst);
00465                 if (se == 0) {
00466                         LM_ERR( "bad subst re [%s]\n",
00467                                 (char*)*param);
00468                         return E_BAD_RE;
00469                 }
00470                 *param = (void*)se;
00471         }
00472 
00473         return 0;       
00474 }
00475 
00476 static int ldap_filter_url_encode_fixup(void** param, int param_no)
00477 {
00478         pv_elem_t *elem_p;
00479         pv_spec_t *spec_p;
00480         str s;
00481 
00482         if (param_no == 1) {
00483                 s.s = (char*)*param;
00484                 if (s.s==0 || s.s[0]==0) {
00485                         elem_p = 0;
00486                 } else {
00487                         s.len = strlen(s.s);
00488                         if (pv_parse_format(&s, &elem_p) < 0) {
00489                                 LM_ERR("pv_parse_format failed\n");
00490                                 return E_OUT_OF_MEM;
00491                         }
00492                 }
00493                 *param = (void*)elem_p;
00494         }
00495         else if (param_no == 2)
00496         {
00497                 spec_p = (pv_spec_t*)pkg_malloc(sizeof(pv_spec_t));
00498                 if (spec_p == NULL) {
00499                         LM_ERR("no memory\n");
00500                         return E_OUT_OF_MEM;
00501                 }
00502                 s.s = (char*)*param; s.len = strlen(s.s);
00503                 if (pv_parse_spec(&s, spec_p)
00504                                 == 0)
00505                 {
00506                         pkg_free(spec_p);
00507                         LM_ERR("parse error for [%s]\n",
00508                                 (char*)*param);
00509                         return E_UNSPEC;
00510                 }
00511                 if (spec_p->type != PVT_AVP) {
00512                         pkg_free(spec_p);
00513                         LM_ERR("bad attribute name"
00514                                 " [%s]\n", (char*)*param);
00515                         return E_UNSPEC;
00516                 }
00517                 *param = (void*)spec_p;
00518         }
00519 
00520         return 0;
00521 }