res_config_ldap.c 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896
  1. /*
  2. * Asterisk -- An open source telephony toolkit.
  3. *
  4. * Copyright (C) 2005, Oxymium sarl
  5. * Manuel Guesdon <mguesdon@oxymium.net> - LDAP RealTime Driver Author/Adaptor
  6. *
  7. * Copyright (C) 2007, Digium, Inc.
  8. * Russell Bryant <russell@digium.com>
  9. *
  10. * See http://www.asterisk.org for more information about
  11. * the Asterisk project. Please do not directly contact
  12. * any of the maintainers of this project for assistance;
  13. * the project provides a web site, mailing lists and IRC
  14. * channels for your use.
  15. *
  16. * This program is free software, distributed under the terms of
  17. * the GNU General Public License Version 2. See the LICENSE file
  18. * at the top of the source tree.
  19. *
  20. */
  21. /*! \file
  22. *
  23. * \brief LDAP plugin for portable configuration engine (ARA)
  24. *
  25. * \author Mark Spencer <markster@digium.com>
  26. * \author Manuel Guesdon
  27. * \author Carl-Einar Thorner <cthorner@voicerd.com>
  28. * \author Russell Bryant <russell@digium.com>
  29. *
  30. * OpenLDAP http://www.openldap.org
  31. */
  32. /*! \li \ref res_config_ldap.c uses the configuration file \ref res_ldap.conf
  33. * \addtogroup configuration_file Configuration Files
  34. */
  35. /*!
  36. * \page res_ldap.conf res_ldap.conf
  37. * \verbinclude res_ldap.conf.sample
  38. */
  39. /*** MODULEINFO
  40. <depend>ldap</depend>
  41. <support_level>extended</support_level>
  42. ***/
  43. #include "asterisk.h"
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <ctype.h>
  47. #include <stdio.h>
  48. #include <ldap.h>
  49. ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
  50. #include "asterisk/channel.h"
  51. #include "asterisk/logger.h"
  52. #include "asterisk/config.h"
  53. #include "asterisk/module.h"
  54. #include "asterisk/lock.h"
  55. #include "asterisk/options.h"
  56. #include "asterisk/cli.h"
  57. #include "asterisk/utils.h"
  58. #include "asterisk/strings.h"
  59. #include "asterisk/pbx.h"
  60. #include "asterisk/linkedlists.h"
  61. #define RES_CONFIG_LDAP_CONF "res_ldap.conf"
  62. #define RES_CONFIG_LDAP_DEFAULT_BASEDN "asterisk"
  63. AST_MUTEX_DEFINE_STATIC(ldap_lock);
  64. static LDAP *ldapConn;
  65. static char url[512];
  66. static char user[512];
  67. static char pass[512];
  68. static char base_distinguished_name[512];
  69. static int version;
  70. static time_t connect_time;
  71. static int parse_config(void);
  72. static int ldap_reconnect(void);
  73. static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
  74. struct category_and_metric {
  75. const char *name;
  76. int metric;
  77. const char *variable_name;
  78. const char *variable_value;
  79. int var_metric; /*!< For organizing variables (particularly includes and switch statments) within a context */
  80. };
  81. /*! \brief Table configuration
  82. */
  83. struct ldap_table_config {
  84. char *table_name; /*!< table name */
  85. char *additional_filter; /*!< additional filter */
  86. struct ast_variable *attributes; /*!< attribute names conversion */
  87. struct ast_variable *delimiters; /*!< the current delimiter is semicolon, so we are not using this variable */
  88. AST_LIST_ENTRY(ldap_table_config) entry;
  89. /* TODO: Make proxies work */
  90. };
  91. /*! \brief Should be locked before using it
  92. */
  93. static AST_LIST_HEAD_NOLOCK_STATIC(table_configs, ldap_table_config);
  94. static struct ldap_table_config *base_table_config;
  95. static struct ldap_table_config *static_table_config;
  96. static struct ast_cli_entry ldap_cli[] = {
  97. AST_CLI_DEFINE(realtime_ldap_status, "Shows connection information for the LDAP RealTime driver"),
  98. };
  99. /*! \brief Create a new table_config
  100. */
  101. static struct ldap_table_config *table_config_new(const char *table_name)
  102. {
  103. struct ldap_table_config *p;
  104. if (!(p = ast_calloc(1, sizeof(*p))))
  105. return NULL;
  106. if (table_name) {
  107. if (!(p->table_name = ast_strdup(table_name))) {
  108. free(p);
  109. return NULL;
  110. }
  111. }
  112. return p;
  113. }
  114. /*! \brief Find a table_config
  115. *
  116. * Should be locked before using it
  117. *
  118. * \note This function assumes ldap_lock to be locked.
  119. */
  120. static struct ldap_table_config *table_config_for_table_name(const char *table_name)
  121. {
  122. struct ldap_table_config *c = NULL;
  123. AST_LIST_TRAVERSE(&table_configs, c, entry) {
  124. if (!strcmp(c->table_name, table_name))
  125. break;
  126. }
  127. return c;
  128. }
  129. /*! \brief Find variable by name
  130. */
  131. static struct ast_variable *variable_named(struct ast_variable *var, const char *name)
  132. {
  133. for (; var; var = var->next) {
  134. if (!strcasecmp(name, var->name))
  135. break;
  136. }
  137. return var;
  138. }
  139. /*! \brief Count semicolons in string
  140. * \param somestr - pointer to a string
  141. *
  142. * \return number of occurances of the delimiter(semicolon)
  143. */
  144. static int semicolon_count_str(const char *somestr)
  145. {
  146. int count = 0;
  147. for (; *somestr; somestr++) {
  148. if (*somestr == ';')
  149. count++;
  150. }
  151. return count;
  152. }
  153. /* \brief Count semicolons in variables
  154. *
  155. * takes a linked list of \a ast_variable variables, finds the one with the name variable_value
  156. * and returns the number of semicolons in the value for that \a ast_variable
  157. */
  158. static int semicolon_count_var(struct ast_variable *var)
  159. {
  160. struct ast_variable *var_value = variable_named(var, "variable_value");
  161. if (!var_value) {
  162. return 0;
  163. }
  164. ast_debug(2, "LINE(%d) semicolon_count_var: %s\n", __LINE__, var_value->value);
  165. return semicolon_count_str(var_value->value);
  166. }
  167. /*! \brief add attribute to table config
  168. *
  169. * Should be locked before using it
  170. */
  171. static void ldap_table_config_add_attribute(struct ldap_table_config *table_config,
  172. const char *attribute_name, const char *attribute_value)
  173. {
  174. struct ast_variable *var;
  175. if (ast_strlen_zero(attribute_name) || ast_strlen_zero(attribute_value)) {
  176. return;
  177. }
  178. if (!(var = ast_variable_new(attribute_name, attribute_value, table_config->table_name))) {
  179. return;
  180. }
  181. if (table_config->attributes) {
  182. var->next = table_config->attributes;
  183. }
  184. table_config->attributes = var;
  185. }
  186. /*! \brief Free table_config
  187. *
  188. * \note assumes ldap_lock to be locked
  189. */
  190. static void table_configs_free(void)
  191. {
  192. struct ldap_table_config *c;
  193. while ((c = AST_LIST_REMOVE_HEAD(&table_configs, entry))) {
  194. if (c->table_name) {
  195. ast_free(c->table_name);
  196. }
  197. if (c->additional_filter) {
  198. ast_free(c->additional_filter);
  199. }
  200. if (c->attributes) {
  201. ast_variables_destroy(c->attributes);
  202. }
  203. free(c);
  204. }
  205. base_table_config = NULL;
  206. static_table_config = NULL;
  207. }
  208. /*! \brief Convert variable name to ldap attribute name
  209. *
  210. * \note Should be locked before using it
  211. */
  212. static const char *convert_attribute_name_to_ldap(struct ldap_table_config *table_config,
  213. const char *attribute_name)
  214. {
  215. int i = 0;
  216. struct ldap_table_config *configs[] = { table_config, base_table_config };
  217. for (i = 0; i < ARRAY_LEN(configs); i++) {
  218. struct ast_variable *attribute;
  219. if (!configs[i]) {
  220. continue;
  221. }
  222. attribute = configs[i]->attributes;
  223. for (; attribute; attribute = attribute->next) {
  224. if (!strcasecmp(attribute_name, attribute->name)) {
  225. return attribute->value;
  226. }
  227. }
  228. }
  229. return attribute_name;
  230. }
  231. /*! \brief Convert ldap attribute name to variable name
  232. *
  233. * \note Should be locked before using it
  234. */
  235. static const char *convert_attribute_name_from_ldap(struct ldap_table_config *table_config,
  236. const char *attribute_name)
  237. {
  238. int i = 0;
  239. struct ldap_table_config *configs[] = { table_config, base_table_config };
  240. for (i = 0; i < ARRAY_LEN(configs); i++) {
  241. struct ast_variable *attribute;
  242. if (!configs[i]) {
  243. continue;
  244. }
  245. attribute = configs[i]->attributes;
  246. for (; attribute; attribute = attribute->next) {
  247. if (strcasecmp(attribute_name, attribute->value) == 0) {
  248. return attribute->name;
  249. }
  250. }
  251. }
  252. return attribute_name;
  253. }
  254. /*! \brief Get variables from ldap entry attributes
  255. * \note Should be locked before using it
  256. * \return a linked list of ast_variable variables.
  257. */
  258. static struct ast_variable *realtime_ldap_entry_to_var(struct ldap_table_config *table_config,
  259. LDAPMessage *ldap_entry)
  260. {
  261. BerElement *ber = NULL;
  262. struct ast_variable *var = NULL;
  263. struct ast_variable *prev = NULL;
  264. int is_delimited = 0;
  265. int i = 0;
  266. char *ldap_attribute_name;
  267. struct berval *value;
  268. int pos = 0;
  269. ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
  270. while (ldap_attribute_name) {
  271. struct berval **values = NULL;
  272. const char *attribute_name = convert_attribute_name_from_ldap(table_config, ldap_attribute_name);
  273. int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
  274. values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name); /* these are freed at the end */
  275. if (values) {
  276. struct berval **v;
  277. char *valptr;
  278. for (v = values; *v; v++) {
  279. value = *v;
  280. valptr = value->bv_val;
  281. ast_debug(2, "LINE(%d) attribute_name: %s LDAP value: %s\n", __LINE__, attribute_name, valptr);
  282. if (is_realmed_password_attribute) {
  283. if (!strncasecmp(valptr, "{md5}", 5)) {
  284. valptr += 5;
  285. }
  286. ast_debug(2, "md5: %s\n", valptr);
  287. }
  288. if (valptr) {
  289. /* ok, so looping through all delimited values except the last one (not, last character is not delimited...) */
  290. if (is_delimited) {
  291. i = 0;
  292. pos = 0;
  293. while (!ast_strlen_zero(valptr + i)) {
  294. if (valptr[i] == ';') {
  295. valptr[i] = '\0';
  296. if (prev) {
  297. prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
  298. if (prev->next) {
  299. prev = prev->next;
  300. }
  301. } else {
  302. prev = var = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
  303. }
  304. pos = i + 1;
  305. }
  306. i++;
  307. }
  308. }
  309. /* for the last delimited value or if the value is not delimited: */
  310. if (prev) {
  311. prev->next = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
  312. if (prev->next) {
  313. prev = prev->next;
  314. }
  315. } else {
  316. prev = var = ast_variable_new(attribute_name, &valptr[pos], table_config->table_name);
  317. }
  318. }
  319. }
  320. ldap_value_free_len(values);
  321. }
  322. ldap_memfree(ldap_attribute_name);
  323. ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
  324. }
  325. ber_free(ber, 0);
  326. return var;
  327. }
  328. /*! \brief Get variables from ldap entry attributes - Should be locked before using it
  329. *
  330. * The results are freed outside this function so is the \a vars array.
  331. *
  332. * \return \a vars - an array of ast_variable variables terminated with a null.
  333. */
  334. static struct ast_variable **realtime_ldap_result_to_vars(struct ldap_table_config *table_config,
  335. LDAPMessage *ldap_result_msg, unsigned int *entries_count_ptr)
  336. {
  337. struct ast_variable **vars;
  338. int i = 0;
  339. int tot_count = 0;
  340. int entry_index = 0;
  341. LDAPMessage *ldap_entry = NULL;
  342. BerElement *ber = NULL;
  343. struct ast_variable *var = NULL;
  344. struct ast_variable *prev = NULL;
  345. int is_delimited = 0;
  346. char *delim_value = NULL;
  347. int delim_tot_count = 0;
  348. int delim_count = 0;
  349. /* \breif First find the total count
  350. */
  351. ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
  352. for (tot_count = 0; ldap_entry; tot_count++) {
  353. struct ast_variable *tmp = realtime_ldap_entry_to_var(table_config, ldap_entry);
  354. tot_count += semicolon_count_var(tmp);
  355. ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
  356. ast_variables_destroy(tmp);
  357. }
  358. if (entries_count_ptr) {
  359. *entries_count_ptr = tot_count;
  360. }
  361. /*! \note Now that we have the total count we allocate space and create the variables
  362. * Remember that each element in vars is a linked list that points to realtime variable.
  363. * If the we are dealing with a static realtime variable we create a new element in the \a vars array for each delimited
  364. * value in \a variable_value; otherwise, we keep \a vars static and increase the length of the linked list of variables in the array element.
  365. * This memory must be freed outside of this function.
  366. */
  367. vars = ast_calloc(sizeof(struct ast_variable *), tot_count + 1);
  368. ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
  369. i = 0;
  370. /* \brief For each static realtime variable we may create several entries in the \a vars array if it's delimited
  371. */
  372. for (entry_index = 0; ldap_entry; ) {
  373. int pos = 0;
  374. delim_value = NULL;
  375. delim_tot_count = 0;
  376. delim_count = 0;
  377. do { /* while delim_count */
  378. /* Starting new static var */
  379. char *ldap_attribute_name = ldap_first_attribute(ldapConn, ldap_entry, &ber);
  380. struct berval *value;
  381. while (ldap_attribute_name) {
  382. const char *attribute_name = convert_attribute_name_from_ldap(table_config, ldap_attribute_name);
  383. int is_realmed_password_attribute = strcasecmp(attribute_name, "md5secret") == 0;
  384. struct berval **values = NULL;
  385. values = ldap_get_values_len(ldapConn, ldap_entry, ldap_attribute_name);
  386. if (values) {
  387. struct berval **v;
  388. char *valptr;
  389. for (v = values; *v; v++) {
  390. value = *v;
  391. valptr = value->bv_val;
  392. if (is_realmed_password_attribute) {
  393. if (strncasecmp(valptr, "{md5}", 5) == 0) {
  394. valptr += 5;
  395. }
  396. ast_debug(2, "md5: %s\n", valptr);
  397. }
  398. if (valptr) {
  399. if (delim_value == NULL && !is_realmed_password_attribute
  400. && (static_table_config != table_config || strcmp(attribute_name, "variable_value") == 0)) {
  401. delim_value = ast_strdup(valptr);
  402. if ((delim_tot_count = semicolon_count_str(delim_value)) > 0) {
  403. ast_debug(4, "LINE(%d) is delimited %d times: %s\n", __LINE__, delim_tot_count, delim_value);
  404. is_delimited = 1;
  405. }
  406. }
  407. if (is_delimited != 0 && !is_realmed_password_attribute
  408. && (static_table_config != table_config || strcmp(attribute_name, "variable_value") == 0) ) {
  409. /* for non-Static RealTime, first */
  410. for (i = pos; !ast_strlen_zero(valptr + i); i++) {
  411. ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
  412. if (delim_value[i] == ';') {
  413. delim_value[i] = '\0';
  414. ast_debug(2, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
  415. if (prev) {
  416. prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
  417. if (prev->next) {
  418. prev = prev->next;
  419. }
  420. } else {
  421. prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
  422. }
  423. pos = i + 1;
  424. if (static_table_config == table_config) {
  425. break;
  426. }
  427. }
  428. }
  429. if (ast_strlen_zero(valptr + i)) {
  430. ast_debug(4, "LINE(%d) DELIM pos: %d i: %d delim_count: %d\n", __LINE__, pos, i, delim_count);
  431. /* Last delimited value */
  432. ast_debug(4, "LINE(%d) DELIM - attribute_name: %s value: %s pos: %d\n", __LINE__, attribute_name, &delim_value[pos], pos);
  433. if (prev) {
  434. prev->next = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
  435. if (prev->next) {
  436. prev = prev->next;
  437. }
  438. } else {
  439. prev = var = ast_variable_new(attribute_name, &delim_value[pos], table_config->table_name);
  440. }
  441. /* Remembering to free memory */
  442. is_delimited = 0;
  443. pos = 0;
  444. }
  445. free(delim_value);
  446. delim_value = NULL;
  447. ast_debug(4, "LINE(%d) DELIM pos: %d i: %d\n", __LINE__, pos, i);
  448. } else {
  449. /* not delimited */
  450. if (delim_value) {
  451. free(delim_value);
  452. delim_value = NULL;
  453. }
  454. ast_debug(2, "LINE(%d) attribute_name: %s value: %s\n", __LINE__, attribute_name, valptr);
  455. if (prev) {
  456. prev->next = ast_variable_new(attribute_name, valptr, table_config->table_name);
  457. if (prev->next) {
  458. prev = prev->next;
  459. }
  460. } else {
  461. prev = var = ast_variable_new(attribute_name, valptr, table_config->table_name);
  462. }
  463. }
  464. }
  465. } /*!< for (v = values; *v; v++) */
  466. ldap_value_free_len(values);
  467. }/*!< if (values) */
  468. ldap_memfree(ldap_attribute_name);
  469. ldap_attribute_name = ldap_next_attribute(ldapConn, ldap_entry, ber);
  470. } /*!< while (ldap_attribute_name) */
  471. ber_free(ber, 0);
  472. if (static_table_config == table_config) {
  473. if (option_debug > 2) {
  474. const struct ast_variable *tmpdebug = variable_named(var, "variable_name");
  475. const struct ast_variable *tmpdebug2 = variable_named(var, "variable_value");
  476. if (tmpdebug && tmpdebug2) {
  477. ast_debug(3, "LINE(%d) Added to vars - %s = %s\n", __LINE__, tmpdebug->value, tmpdebug2->value);
  478. }
  479. }
  480. vars[entry_index++] = var;
  481. prev = NULL;
  482. }
  483. delim_count++;
  484. } while (delim_count <= delim_tot_count && static_table_config == table_config);
  485. if (static_table_config != table_config) {
  486. ast_debug(3, "LINE(%d) Added to vars - non static\n", __LINE__);
  487. vars[entry_index++] = var;
  488. prev = NULL;
  489. }
  490. ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
  491. } /*!< end for loop over ldap_entry */
  492. return vars;
  493. }
  494. /*! \brief Check if we have a connection error
  495. */
  496. static int is_ldap_connect_error(int err)
  497. {
  498. return (err == LDAP_SERVER_DOWN || err == LDAP_TIMEOUT || err == LDAP_CONNECT_ERROR);
  499. }
  500. /*! \brief Get LDAP entry by dn and return attributes as variables
  501. *
  502. * Should be locked before using it
  503. *
  504. * This is used for setting the default values of an object
  505. * i.e., with accountBaseDN
  506. */
  507. static struct ast_variable *ldap_loadentry(struct ldap_table_config *table_config,
  508. const char *dn)
  509. {
  510. if (!table_config) {
  511. ast_log(LOG_ERROR, "No table config\n");
  512. return NULL;
  513. } else {
  514. struct ast_variable **vars = NULL;
  515. struct ast_variable *var = NULL;
  516. int result = -1;
  517. LDAPMessage *ldap_result_msg = NULL;
  518. int tries = 0;
  519. ast_debug(2, "ldap_loadentry dn=%s\n", dn);
  520. do {
  521. result = ldap_search_ext_s(ldapConn, dn, LDAP_SCOPE_BASE,
  522. "(objectclass=*)", NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &ldap_result_msg);
  523. if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
  524. ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1);
  525. tries++;
  526. if (tries < 3) {
  527. usleep(500000L * tries);
  528. if (ldapConn) {
  529. ldap_unbind_ext_s(ldapConn, NULL, NULL);
  530. ldapConn = NULL;
  531. }
  532. if (!ldap_reconnect()) {
  533. break;
  534. }
  535. }
  536. }
  537. } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
  538. if (result != LDAP_SUCCESS) {
  539. ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
  540. ast_debug(2, "dn=%s\n", dn);
  541. ast_mutex_unlock(&ldap_lock);
  542. return NULL;
  543. } else {
  544. int num_entry = 0;
  545. unsigned int *entries_count_ptr = NULL; /*!< not using this */
  546. if ((num_entry = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
  547. ast_debug(3, "num_entry: %d\n", num_entry);
  548. vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
  549. if (num_entry > 1) {
  550. ast_log(LOG_NOTICE, "More than one entry for dn=%s. Take only 1st one\n", dn);
  551. }
  552. } else {
  553. ast_debug(2, "Could not find any entry dn=%s.\n", dn);
  554. }
  555. }
  556. ldap_msgfree(ldap_result_msg);
  557. /* Chopping \a vars down to one variable */
  558. if (vars != NULL) {
  559. struct ast_variable **p = vars;
  560. /* Only take the first one. */
  561. var = *vars;
  562. /* Destroy the rest. */
  563. while (*++p) {
  564. ast_variables_destroy(*p);
  565. }
  566. ast_free(vars);
  567. }
  568. return var;
  569. }
  570. }
  571. /*! \note caller should free returned pointer
  572. */
  573. static char *substituted(struct ast_channel *channel, const char *string)
  574. {
  575. #define MAXRESULT 2048
  576. char *ret_string = NULL;
  577. if (!ast_strlen_zero(string)) {
  578. ret_string = ast_calloc(1, MAXRESULT);
  579. pbx_substitute_variables_helper(channel, string, ret_string, MAXRESULT - 1);
  580. }
  581. ast_debug(2, "substituted: string: '%s' => '%s' \n", string, ret_string);
  582. return ret_string;
  583. }
  584. /*! \note caller should free returned pointer
  585. */
  586. static char *cleaned_basedn(struct ast_channel *channel, const char *basedn)
  587. {
  588. char *cbasedn = NULL;
  589. if (basedn) {
  590. char *p = NULL;
  591. cbasedn = substituted(channel, basedn);
  592. if (*cbasedn == '"') {
  593. cbasedn++;
  594. if (!ast_strlen_zero(cbasedn)) {
  595. int len = strlen(cbasedn);
  596. if (cbasedn[len - 1] == '"')
  597. cbasedn[len - 1] = '\0';
  598. }
  599. }
  600. p = cbasedn;
  601. while (*p) {
  602. if (*p == '|')
  603. *p = ',';
  604. p++;
  605. }
  606. }
  607. ast_debug(2, "basedn: '%s' => '%s' \n", basedn, cbasedn);
  608. return cbasedn;
  609. }
  610. /*! \brief Replace \<search\> by \<by\> in string.
  611. * \note No check is done on string allocated size !
  612. */
  613. static int replace_string_in_string(char *string, const char *search, const char *by)
  614. {
  615. int search_len = strlen(search);
  616. int by_len = strlen(by);
  617. int replaced = 0;
  618. char *p = strstr(string, search);
  619. if (p) {
  620. replaced = 1;
  621. while (p) {
  622. if (by_len == search_len) {
  623. memcpy(p, by, by_len);
  624. } else {
  625. memmove(p + by_len, p + search_len, strlen(p + search_len) + 1);
  626. memcpy(p, by, by_len);
  627. }
  628. p = strstr(p + by_len, search);
  629. }
  630. }
  631. return replaced;
  632. }
  633. /*! \brief Append a name=value filter string. The filter string can grow.
  634. */
  635. static void append_var_and_value_to_filter(struct ast_str **filter,
  636. struct ldap_table_config *table_config,
  637. const char *name, const char *value)
  638. {
  639. char *new_name = NULL;
  640. char *new_value = NULL;
  641. char *like_pos = strstr(name, " LIKE");
  642. ast_debug(2, "name='%s' value='%s'\n", name, value);
  643. if (like_pos) {
  644. int len = like_pos - name;
  645. name = new_name = ast_strdupa(name);
  646. new_name[len] = '\0';
  647. value = new_value = ast_strdupa(value);
  648. replace_string_in_string(new_value, "\\_", "_");
  649. replace_string_in_string(new_value, "%", "*");
  650. }
  651. name = convert_attribute_name_to_ldap(table_config, name);
  652. ast_str_append(filter, 0, "(%s=%s)", name, value);
  653. }
  654. /*! \brief LDAP base function
  655. * \return a null terminated array of ast_variable (one per entry) or NULL if no entry is found or if an error occured
  656. * caller should free the returned array and ast_variables
  657. * \param entries_count_ptr is a pointer to found entries count (can be NULL)
  658. * \param basedn is the base DN
  659. * \param table_name is the table_name (used dor attribute convertion and additional filter)
  660. * \param fields contains list of pairs name/value
  661. */
  662. static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_ptr,
  663. const char *basedn, const char *table_name, const struct ast_variable *fields)
  664. {
  665. struct ast_variable **vars = NULL;
  666. const struct ast_variable *field = fields;
  667. struct ldap_table_config *table_config = NULL;
  668. char *clean_basedn = cleaned_basedn(NULL, basedn);
  669. struct ast_str *filter = NULL;
  670. int tries = 0;
  671. int result = 0;
  672. LDAPMessage *ldap_result_msg = NULL;
  673. if (!table_name) {
  674. ast_log(LOG_ERROR, "No table_name specified.\n");
  675. ast_free(clean_basedn);
  676. return NULL;
  677. }
  678. if (!(filter = ast_str_create(80))) {
  679. ast_log(LOG_ERROR, "Can't initialize data structures.n");
  680. ast_free(clean_basedn);
  681. return NULL;
  682. }
  683. if (!field) {
  684. ast_log(LOG_ERROR, "Realtime retrieval requires at least 1 parameter"
  685. " and 1 value to search on.\n");
  686. ast_free(filter);
  687. ast_free(clean_basedn);
  688. return NULL;
  689. }
  690. ast_mutex_lock(&ldap_lock);
  691. /* We now have our complete statement; Lets connect to the server and execute it. */
  692. if (!ldap_reconnect()) {
  693. ast_mutex_unlock(&ldap_lock);
  694. ast_free(filter);
  695. ast_free(clean_basedn);
  696. return NULL;
  697. }
  698. table_config = table_config_for_table_name(table_name);
  699. if (!table_config) {
  700. ast_log(LOG_WARNING, "No table named '%s'.\n", table_name);
  701. ast_mutex_unlock(&ldap_lock);
  702. ast_free(filter);
  703. ast_free(clean_basedn);
  704. return NULL;
  705. }
  706. ast_str_append(&filter, 0, "(&");
  707. if (table_config && table_config->additional_filter) {
  708. ast_str_append(&filter, 0, "%s", table_config->additional_filter);
  709. }
  710. if (table_config != base_table_config && base_table_config &&
  711. base_table_config->additional_filter) {
  712. ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
  713. }
  714. /* Create the first part of the query using the first parameter/value pairs we just extracted.
  715. * If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat
  716. */
  717. append_var_and_value_to_filter(&filter, table_config, field->name, field->value);
  718. while ((field = field->next)) {
  719. append_var_and_value_to_filter(&filter, table_config, field->name, field->value);
  720. }
  721. ast_str_append(&filter, 0, ")");
  722. do {
  723. /* freeing ldap_result further down */
  724. result = ldap_search_ext_s(ldapConn, clean_basedn,
  725. LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
  726. &ldap_result_msg);
  727. if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
  728. ast_debug(1, "Failed to query directory. Try %d/10\n", tries + 1);
  729. if (++tries < 10) {
  730. usleep(1);
  731. if (ldapConn) {
  732. ldap_unbind_ext_s(ldapConn, NULL, NULL);
  733. ldapConn = NULL;
  734. }
  735. if (!ldap_reconnect()) {
  736. break;
  737. }
  738. }
  739. }
  740. } while (result != LDAP_SUCCESS && tries < 10 && is_ldap_connect_error(result));
  741. if (result != LDAP_SUCCESS) {
  742. ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
  743. ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
  744. } else {
  745. /* this is where we create the variables from the search result
  746. * freeing this \a vars outside this function */
  747. if (ldap_count_entries(ldapConn, ldap_result_msg) > 0) {
  748. /* is this a static var or some other? they are handled different for delimited values */
  749. vars = realtime_ldap_result_to_vars(table_config, ldap_result_msg, entries_count_ptr);
  750. } else {
  751. ast_debug(1, "Could not find any entry matching %s in base dn %s.\n", ast_str_buffer(filter), clean_basedn);
  752. }
  753. ldap_msgfree(ldap_result_msg);
  754. /*! \TODO get the default variables from the accountBaseDN, not implemented with delimited values
  755. */
  756. if (vars) {
  757. struct ast_variable **p = vars;
  758. while (*p) {
  759. struct ast_variable *append_var = NULL;
  760. struct ast_variable *tmp = *p;
  761. while (tmp) {
  762. if (strcasecmp(tmp->name, "accountBaseDN") == 0) {
  763. /* Get the variable to compare with for the defaults */
  764. struct ast_variable *base_var = ldap_loadentry(table_config, tmp->value);
  765. while (base_var) {
  766. struct ast_variable *next = base_var->next;
  767. struct ast_variable *test_var = *p;
  768. int base_var_found = 0;
  769. /* run throught the default values and fill it inn if it is missing */
  770. while (test_var) {
  771. if (strcasecmp(test_var->name, base_var->name) == 0) {
  772. base_var_found = 1;
  773. break;
  774. } else {
  775. test_var = test_var->next;
  776. }
  777. }
  778. if (base_var_found) {
  779. base_var->next = NULL;
  780. ast_variables_destroy(base_var);
  781. base_var = next;
  782. } else {
  783. /*!
  784. * \todo XXX The interactions with base_var and append_var may
  785. * cause a memory leak of base_var nodes. Also the append_var
  786. * list and base_var list may get cross linked.
  787. */
  788. if (append_var) {
  789. base_var->next = append_var;
  790. } else {
  791. base_var->next = NULL;
  792. }
  793. append_var = base_var;
  794. base_var = next;
  795. }
  796. }
  797. }
  798. if (!tmp->next && append_var) {
  799. tmp->next = append_var;
  800. tmp = NULL;
  801. } else {
  802. tmp = tmp->next;
  803. }
  804. }
  805. p++;
  806. }
  807. }
  808. }
  809. if (filter) {
  810. ast_free(filter);
  811. }
  812. if (clean_basedn) {
  813. ast_free(clean_basedn);
  814. }
  815. ast_mutex_unlock(&ldap_lock);
  816. return vars;
  817. }
  818. static struct ast_variable *realtime_arguments_to_fields(va_list ap)
  819. {
  820. struct ast_variable *fields = NULL;
  821. const char *newparam, *newval;
  822. while ((newparam = va_arg(ap, const char *))) {
  823. struct ast_variable *field;
  824. newval = va_arg(ap, const char *);
  825. if (!(field = ast_variable_new(newparam, newval, ""))) {
  826. ast_variables_destroy(fields);
  827. return NULL;
  828. }
  829. field->next = fields;
  830. fields = field;
  831. }
  832. return fields;
  833. }
  834. /*! \brief same as realtime_ldap_base_ap but take variable arguments count list
  835. */
  836. static struct ast_variable **realtime_ldap_base(unsigned int *entries_count_ptr,
  837. const char *basedn, const char *table_name, ...)
  838. {
  839. RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
  840. struct ast_variable **vars = NULL;
  841. va_list ap;
  842. va_start(ap, table_name);
  843. fields = realtime_arguments_to_fields(ap);
  844. va_end(ap);
  845. vars = realtime_ldap_base_ap(entries_count_ptr, basedn, table_name, fields);
  846. return vars;
  847. }
  848. /*! \brief See Asterisk doc
  849. *
  850. * For Realtime Dynamic(i.e., switch, queues, and directory)
  851. */
  852. static struct ast_variable *realtime_ldap(const char *basedn,
  853. const char *table_name, const struct ast_variable *fields)
  854. {
  855. struct ast_variable **vars = realtime_ldap_base_ap(NULL, basedn, table_name, fields);
  856. struct ast_variable *var = NULL;
  857. if (vars) {
  858. struct ast_variable *last_var = NULL;
  859. struct ast_variable **p = vars;
  860. /* Chain the vars array of lists into one list to return. */
  861. while (*p) {
  862. if (last_var) {
  863. while (last_var->next) {
  864. last_var = last_var->next;
  865. }
  866. last_var->next = *p;
  867. } else {
  868. var = *p;
  869. last_var = var;
  870. }
  871. p++;
  872. }
  873. free(vars);
  874. }
  875. return var;
  876. }
  877. /*! \brief See Asterisk doc
  878. *
  879. * this function will be called for the switch statment if no match is found with the realtime_ldap function(i.e. it is a failover);
  880. * however, the ast_load_realtime wil match on wildcharacters also depending on what the mode is set to
  881. * this is an area of asterisk that could do with a lot of modification
  882. * I think this function returns Realtime dynamic objects
  883. */
  884. static struct ast_config *realtime_multi_ldap(const char *basedn,
  885. const char *table_name, const struct ast_variable *fields)
  886. {
  887. char *op;
  888. const char *initfield = NULL;
  889. struct ast_variable **vars =
  890. realtime_ldap_base_ap(NULL, basedn, table_name, fields);
  891. struct ast_config *cfg = NULL;
  892. if (!fields) {
  893. ast_log(LOG_WARNING, "realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
  894. return NULL;
  895. }
  896. initfield = ast_strdupa(fields->name);
  897. if ((op = strchr(initfield, ' '))) {
  898. *op = '\0';
  899. }
  900. if (vars) {
  901. cfg = ast_config_new();
  902. if (!cfg) {
  903. ast_log(LOG_ERROR, "Unable to create a config!\n");
  904. } else {
  905. struct ast_variable **p = vars;
  906. while (*p) {
  907. struct ast_category *cat = NULL;
  908. cat = ast_category_new("", table_name, -1);
  909. if (!cat) {
  910. ast_log(LOG_ERROR, "Unable to create a new category!\n");
  911. break;
  912. } else {
  913. struct ast_variable *var = *p;
  914. while (var) {
  915. struct ast_variable *next = var->next;
  916. if (initfield && !strcmp(initfield, var->name)) {
  917. ast_category_rename(cat, var->value);
  918. }
  919. var->next = NULL;
  920. ast_variable_append(cat, var);
  921. var = next;
  922. }
  923. }
  924. ast_category_append(cfg, cat);
  925. p++;
  926. }
  927. }
  928. free(vars);
  929. }
  930. return cfg;
  931. }
  932. /*! \brief Sorting alogrithm for qsort to find the order of the variables \a a and \a b
  933. * \param a pointer to category_and_metric struct
  934. * \param b pointer to category_and_metric struct
  935. *
  936. * \retval -1 for if b is greater
  937. * \retval 0 zero for equal
  938. * \retval 1 if a is greater
  939. */
  940. static int compare_categories(const void *a, const void *b)
  941. {
  942. const struct category_and_metric *as = a;
  943. const struct category_and_metric *bs = b;
  944. if (as->metric < bs->metric) {
  945. return -1;
  946. } else if (as->metric > bs->metric) {
  947. return 1;
  948. } else if (as->metric == bs->metric && strcmp(as->name, bs->name) != 0) {
  949. return strcmp(as->name, bs->name);
  950. }
  951. /* if the metric and the category name is the same, we check the variable metric */
  952. if (as->var_metric < bs->var_metric) {
  953. return -1;
  954. } else if (as->var_metric > bs->var_metric) {
  955. return 1;
  956. }
  957. return 0;
  958. }
  959. /*! \brief See Asterisk Realtime Documentation
  960. *
  961. * This is for Static Realtime
  962. *
  963. * load the configuration stuff for the .conf files
  964. * called on a reload
  965. */
  966. static struct ast_config *config_ldap(const char *basedn, const char *table_name,
  967. const char *file, struct ast_config *cfg, struct ast_flags config_flags, const char *sugg_incl, const char *who_asked)
  968. {
  969. unsigned int vars_count = 0;
  970. struct ast_variable **vars;
  971. int i = 0;
  972. struct ast_variable *new_v = NULL;
  973. struct ast_category *cur_cat = NULL;
  974. const char *last_category = NULL;
  975. int last_category_metric = 0;
  976. struct category_and_metric *categories;
  977. struct ast_variable **p;
  978. if (ast_strlen_zero(file) || !strcasecmp(file, RES_CONFIG_LDAP_CONF)) {
  979. ast_log(LOG_ERROR, "Missing configuration file: %s. Can't configure myself.\n", RES_CONFIG_LDAP_CONF);
  980. return NULL;
  981. }
  982. vars = realtime_ldap_base(&vars_count, basedn, table_name, "filename", file, "commented", "FALSE", NULL);
  983. if (!vars) {
  984. ast_log(LOG_WARNING, "Could not find config '%s' in directory.\n", file);
  985. return NULL;
  986. }
  987. /*! \note Since the items come back in random order, they need to be sorted
  988. * first, and since the data could easily exceed stack size, this is
  989. * allocated from the heap.
  990. */
  991. if (!(categories = ast_calloc(sizeof(*categories), vars_count))) {
  992. return NULL;
  993. }
  994. for (vars_count = 0, p = vars; *p; p++) {
  995. struct ast_variable *category = variable_named(*p, "category");
  996. struct ast_variable *cat_metric = variable_named(*p, "cat_metric");
  997. struct ast_variable *var_name = variable_named(*p, "variable_name");
  998. struct ast_variable *var_val = variable_named(*p, "variable_value");
  999. struct ast_variable *var_metric = variable_named(*p, "var_metric");
  1000. struct ast_variable *dn = variable_named(*p, "dn");
  1001. if (!category) {
  1002. ast_log(LOG_ERROR, "No category name in entry '%s' for file '%s'.\n",
  1003. (dn ? dn->value : "?"), file);
  1004. } else if (!cat_metric) {
  1005. ast_log(LOG_ERROR, "No category metric in entry '%s'(category: %s) for file '%s'.\n",
  1006. (dn ? dn->value : "?"), category->value, file);
  1007. } else if (!var_metric) {
  1008. ast_log(LOG_ERROR, "No variable metric in entry '%s'(category: %s) for file '%s'.\n",
  1009. (dn ? dn->value : "?"), category->value, file);
  1010. } else if (!var_name) {
  1011. ast_log(LOG_ERROR, "No variable name in entry '%s' (category: %s metric: %s) for file '%s'.\n",
  1012. (dn ? dn->value : "?"), category->value,
  1013. cat_metric->value, file);
  1014. } else if (!var_val) {
  1015. ast_log(LOG_ERROR, "No variable value in entry '%s' (category: %s metric: %s variable: %s) for file '%s'.\n",
  1016. (dn ? dn->value : "?"), category->value,
  1017. cat_metric->value, var_name->value, file);
  1018. } else {
  1019. categories[vars_count].name = category->value;
  1020. categories[vars_count].metric = atoi(cat_metric->value);
  1021. categories[vars_count].variable_name = var_name->value;
  1022. categories[vars_count].variable_value = var_val->value;
  1023. categories[vars_count].var_metric = atoi(var_metric->value);
  1024. vars_count++;
  1025. }
  1026. ast_debug(3, "category: %s\n", category->value);
  1027. ast_debug(3, "var_name: %s\n", var_name->value);
  1028. ast_debug(3, "var_val: %s\n", var_val->value);
  1029. ast_debug(3, "cat_metric: %s\n", cat_metric->value);
  1030. }
  1031. qsort(categories, vars_count, sizeof(*categories), compare_categories);
  1032. for (i = 0; i < vars_count; i++) {
  1033. if (!strcmp(categories[i].variable_name, "#include")) {
  1034. struct ast_flags flags = { 0 };
  1035. if (!ast_config_internal_load(categories[i].variable_value, cfg, flags, "", who_asked)) {
  1036. break;
  1037. }
  1038. continue;
  1039. }
  1040. if (!last_category || strcmp(last_category, categories[i].name) ||
  1041. last_category_metric != categories[i].metric) {
  1042. cur_cat = ast_category_new(categories[i].name, table_name, -1);
  1043. if (!cur_cat) {
  1044. break;
  1045. }
  1046. last_category = categories[i].name;
  1047. last_category_metric = categories[i].metric;
  1048. ast_category_append(cfg, cur_cat);
  1049. }
  1050. if (!(new_v = ast_variable_new(categories[i].variable_name, categories[i].variable_value, table_name))) {
  1051. break;
  1052. }
  1053. ast_variable_append(cur_cat, new_v);
  1054. }
  1055. ast_free(vars);
  1056. ast_free(categories);
  1057. return cfg;
  1058. }
  1059. /* \brief Function to update a set of values in ldap static mode
  1060. */
  1061. static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
  1062. const char *lookup, const struct ast_variable *fields)
  1063. {
  1064. int error = 0;
  1065. LDAPMessage *ldap_entry = NULL;
  1066. LDAPMod **ldap_mods;
  1067. const char *newparam;
  1068. const struct ast_variable *field = fields;
  1069. char *dn;
  1070. int num_entries = 0;
  1071. int i = 0;
  1072. int mods_size = 0;
  1073. int mod_exists = 0;
  1074. struct ldap_table_config *table_config = NULL;
  1075. char *clean_basedn = NULL;
  1076. struct ast_str *filter = NULL;
  1077. int tries = 0;
  1078. int result = 0;
  1079. LDAPMessage *ldap_result_msg = NULL;
  1080. if (!table_name) {
  1081. ast_log(LOG_ERROR, "No table_name specified.\n");
  1082. return -1;
  1083. }
  1084. if (!(filter = ast_str_create(80))) {
  1085. return -1;
  1086. }
  1087. if (!attribute || !lookup) {
  1088. ast_log(LOG_WARNING, "LINE(%d): search parameters are empty.\n", __LINE__);
  1089. return -1;
  1090. }
  1091. ast_mutex_lock(&ldap_lock);
  1092. /* We now have our complete statement; Lets connect to the server and execute it. */
  1093. if (!ldap_reconnect()) {
  1094. ast_mutex_unlock(&ldap_lock);
  1095. return -1;
  1096. }
  1097. table_config = table_config_for_table_name(table_name);
  1098. if (!table_config) {
  1099. ast_log(LOG_ERROR, "No table named '%s'.\n", table_name);
  1100. ast_mutex_unlock(&ldap_lock);
  1101. return -1;
  1102. }
  1103. clean_basedn = cleaned_basedn(NULL, basedn);
  1104. /* Create the filter with the table additional filter and the parameter/value pairs we were given */
  1105. ast_str_append(&filter, 0, "(&");
  1106. if (table_config && table_config->additional_filter) {
  1107. ast_str_append(&filter, 0, "%s", table_config->additional_filter);
  1108. }
  1109. if (table_config != base_table_config && base_table_config && base_table_config->additional_filter) {
  1110. ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
  1111. }
  1112. append_var_and_value_to_filter(&filter, table_config, attribute, lookup);
  1113. ast_str_append(&filter, 0, ")");
  1114. /* Create the modification array with the parameter/value pairs we were given,
  1115. * if there are several parameters with the same name, we collect them into
  1116. * one parameter/value pair and delimit them with a semicolon */
  1117. newparam = convert_attribute_name_to_ldap(table_config, field->name);
  1118. if (!newparam) {
  1119. ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__);
  1120. return -1;
  1121. }
  1122. mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */
  1123. ldap_mods = ldap_memcalloc(sizeof(LDAPMod *), mods_size);
  1124. ldap_mods[0] = ldap_memcalloc(1, sizeof(LDAPMod));
  1125. ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
  1126. ldap_mods[0]->mod_type = ldap_strdup(newparam);
  1127. ldap_mods[0]->mod_values = ast_calloc(sizeof(char *), 2);
  1128. ldap_mods[0]->mod_values[0] = ldap_strdup(field->value);
  1129. while ((field = field->next)) {
  1130. newparam = convert_attribute_name_to_ldap(table_config, field->name);
  1131. mod_exists = 0;
  1132. for (i = 0; i < mods_size - 1; i++) {
  1133. if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
  1134. /* We have the parameter allready, adding the value as a semicolon delimited value */
  1135. ldap_mods[i]->mod_values[0] = ldap_memrealloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(field->value) + 2));
  1136. strcat(ldap_mods[i]->mod_values[0], ";");
  1137. strcat(ldap_mods[i]->mod_values[0], field->value);
  1138. mod_exists = 1;
  1139. break;
  1140. }
  1141. }
  1142. /* create new mod */
  1143. if (!mod_exists) {
  1144. mods_size++;
  1145. ldap_mods = ldap_memrealloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
  1146. ldap_mods[mods_size - 1] = NULL;
  1147. ldap_mods[mods_size - 2] = ldap_memcalloc(1, sizeof(LDAPMod));
  1148. ldap_mods[mods_size - 2]->mod_type = ldap_memcalloc(sizeof(char), strlen(newparam) + 1);
  1149. strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
  1150. if (strlen(field->value) == 0) {
  1151. ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_DELETE;
  1152. } else {
  1153. ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
  1154. ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(sizeof(char *), 2);
  1155. ldap_mods[mods_size - 2]->mod_values[0] = ldap_memcalloc(sizeof(char), strlen(field->value) + 1);
  1156. strcpy(ldap_mods[mods_size - 2]->mod_values[0], field->value);
  1157. }
  1158. }
  1159. }
  1160. /* freeing ldap_mods further down */
  1161. do {
  1162. /* freeing ldap_result further down */
  1163. result = ldap_search_ext_s(ldapConn, clean_basedn,
  1164. LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
  1165. &ldap_result_msg);
  1166. if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
  1167. ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1);
  1168. tries++;
  1169. if (tries < 3) {
  1170. usleep(500000L * tries);
  1171. if (ldapConn) {
  1172. ldap_unbind_ext_s(ldapConn, NULL, NULL);
  1173. ldapConn = NULL;
  1174. }
  1175. if (!ldap_reconnect())
  1176. break;
  1177. }
  1178. }
  1179. } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
  1180. if (result != LDAP_SUCCESS) {
  1181. ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
  1182. ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
  1183. ast_mutex_unlock(&ldap_lock);
  1184. free(filter);
  1185. free(clean_basedn);
  1186. ldap_msgfree(ldap_result_msg);
  1187. ldap_mods_free(ldap_mods, 0);
  1188. return -1;
  1189. }
  1190. /* Ready to update */
  1191. if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
  1192. ast_debug(3, "LINE(%d) Modifying %s=%s hits: %d\n", __LINE__, attribute, lookup, num_entries);
  1193. for (i = 0; option_debug > 2 && i < mods_size - 1; i++) {
  1194. if (ldap_mods[i]->mod_op != LDAP_MOD_DELETE) {
  1195. ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
  1196. } else {
  1197. ast_debug(3, "LINE(%d) deleting %s \n", __LINE__, ldap_mods[i]->mod_type);
  1198. }
  1199. }
  1200. ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
  1201. for (i = 0; ldap_entry; i++) {
  1202. dn = ldap_get_dn(ldapConn, ldap_entry);
  1203. if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
  1204. ast_log(LOG_ERROR, "Couldn't modify '%s'='%s', dn:%s because %s\n",
  1205. attribute, lookup, dn, ldap_err2string(error));
  1206. }
  1207. ldap_memfree(dn);
  1208. ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
  1209. }
  1210. }
  1211. ast_mutex_unlock(&ldap_lock);
  1212. ast_free(filter);
  1213. ast_free(clean_basedn);
  1214. ldap_msgfree(ldap_result_msg);
  1215. ldap_mods_free(ldap_mods, 0);
  1216. return num_entries;
  1217. }
  1218. static int update2_ldap(const char *basedn, const char *table_name, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
  1219. {
  1220. int error = 0;
  1221. LDAPMessage *ldap_entry = NULL;
  1222. LDAPMod **ldap_mods;
  1223. const char *newparam;
  1224. const struct ast_variable *field;
  1225. char *dn;
  1226. int num_entries = 0;
  1227. int i = 0;
  1228. int mods_size = 0;
  1229. int mod_exists = 0;
  1230. struct ldap_table_config *table_config = NULL;
  1231. char *clean_basedn = NULL;
  1232. struct ast_str *filter = NULL;
  1233. int tries = 0;
  1234. int result = 0;
  1235. LDAPMessage *ldap_result_msg = NULL;
  1236. if (!table_name) {
  1237. ast_log(LOG_ERROR, "No table_name specified.\n");
  1238. return -1;
  1239. }
  1240. if (!(filter = ast_str_create(80))) {
  1241. return -1;
  1242. }
  1243. ast_mutex_lock(&ldap_lock);
  1244. /* We now have our complete statement; Lets connect to the server and execute it. */
  1245. if (!ldap_reconnect()) {
  1246. ast_mutex_unlock(&ldap_lock);
  1247. ast_free(filter);
  1248. return -1;
  1249. }
  1250. table_config = table_config_for_table_name(table_name);
  1251. if (!table_config) {
  1252. ast_log(LOG_ERROR, "No table named '%s'.\n", table_name);
  1253. ast_mutex_unlock(&ldap_lock);
  1254. ast_free(filter);
  1255. return -1;
  1256. }
  1257. clean_basedn = cleaned_basedn(NULL, basedn);
  1258. /* Create the filter with the table additional filter and the parameter/value pairs we were given */
  1259. ast_str_append(&filter, 0, "(&");
  1260. if (table_config && table_config->additional_filter) {
  1261. ast_str_append(&filter, 0, "%s", table_config->additional_filter);
  1262. }
  1263. if (table_config != base_table_config && base_table_config
  1264. && base_table_config->additional_filter) {
  1265. ast_str_append(&filter, 0, "%s", base_table_config->additional_filter);
  1266. }
  1267. /* Get multiple lookup keyfields and values */
  1268. for (field = lookup_fields; field; field = field->next) {
  1269. append_var_and_value_to_filter(&filter, table_config, field->name, field->value);
  1270. }
  1271. ast_str_append(&filter, 0, ")");
  1272. /* Create the modification array with the parameter/value pairs we were given,
  1273. * if there are several parameters with the same name, we collect them into
  1274. * one parameter/value pair and delimit them with a semicolon */
  1275. field = update_fields;
  1276. newparam = convert_attribute_name_to_ldap(table_config, field->name);
  1277. if (!newparam) {
  1278. ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__);
  1279. ast_free(filter);
  1280. ast_free(clean_basedn);
  1281. return -1;
  1282. }
  1283. mods_size = 2; /* one for the first param/value pair and one for the the terminating NULL */
  1284. ldap_mods = ast_calloc(sizeof(LDAPMod *), mods_size);
  1285. ldap_mods[0] = ast_calloc(1, sizeof(LDAPMod));
  1286. ldap_mods[0]->mod_op = LDAP_MOD_REPLACE;
  1287. ldap_mods[0]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
  1288. strcpy(ldap_mods[0]->mod_type, newparam);
  1289. ldap_mods[0]->mod_values = ast_calloc(sizeof(char), 2);
  1290. ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(field->value) + 1);
  1291. strcpy(ldap_mods[0]->mod_values[0], field->value);
  1292. while ((field = field->next)) {
  1293. newparam = convert_attribute_name_to_ldap(table_config, field->name);
  1294. mod_exists = 0;
  1295. for (i = 0; i < mods_size - 1; i++) {
  1296. if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
  1297. /* We have the parameter allready, adding the value as a semicolon delimited value */
  1298. ldap_mods[i]->mod_values[0] = ast_realloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(field->value) + 2));
  1299. strcat(ldap_mods[i]->mod_values[0], ";");
  1300. strcat(ldap_mods[i]->mod_values[0], field->value);
  1301. mod_exists = 1;
  1302. break;
  1303. }
  1304. }
  1305. /* create new mod */
  1306. if (!mod_exists) {
  1307. mods_size++;
  1308. ldap_mods = ast_realloc(ldap_mods, sizeof(LDAPMod *) * mods_size);
  1309. ldap_mods[mods_size - 1] = NULL;
  1310. ldap_mods[mods_size - 2] = ast_calloc(1, sizeof(LDAPMod));
  1311. ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
  1312. ldap_mods[mods_size - 2]->mod_type = ast_calloc(sizeof(char), strlen(newparam) + 1);
  1313. strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
  1314. ldap_mods[mods_size - 2]->mod_values = ast_calloc(sizeof(char *), 2);
  1315. ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(field->value) + 1);
  1316. strcpy(ldap_mods[mods_size - 2]->mod_values[0], field->value);
  1317. }
  1318. }
  1319. /* freeing ldap_mods further down */
  1320. do {
  1321. /* freeing ldap_result further down */
  1322. result = ldap_search_ext_s(ldapConn, clean_basedn,
  1323. LDAP_SCOPE_SUBTREE, ast_str_buffer(filter), NULL, 0, NULL, NULL, NULL, LDAP_NO_LIMIT,
  1324. &ldap_result_msg);
  1325. if (result != LDAP_SUCCESS && is_ldap_connect_error(result)) {
  1326. ast_log(LOG_WARNING, "Failed to query directory. Try %d/3\n", tries + 1);
  1327. tries++;
  1328. if (tries < 3) {
  1329. usleep(500000L * tries);
  1330. if (ldapConn) {
  1331. ldap_unbind_ext_s(ldapConn, NULL, NULL);
  1332. ldapConn = NULL;
  1333. }
  1334. if (!ldap_reconnect()) {
  1335. break;
  1336. }
  1337. }
  1338. }
  1339. } while (result != LDAP_SUCCESS && tries < 3 && is_ldap_connect_error(result));
  1340. if (result != LDAP_SUCCESS) {
  1341. ast_log(LOG_WARNING, "Failed to query directory. Error: %s.\n", ldap_err2string(result));
  1342. ast_log(LOG_WARNING, "Query: %s\n", ast_str_buffer(filter));
  1343. ast_mutex_unlock(&ldap_lock);
  1344. ast_free(filter);
  1345. ast_free(clean_basedn);
  1346. ldap_msgfree(ldap_result_msg);
  1347. ldap_mods_free(ldap_mods, 0);
  1348. return -1;
  1349. }
  1350. /* Ready to update */
  1351. if ((num_entries = ldap_count_entries(ldapConn, ldap_result_msg)) > 0) {
  1352. for (i = 0; option_debug > 2 && i < mods_size - 1; i++) {
  1353. ast_debug(3, "LINE(%d) %s=%s \n", __LINE__, ldap_mods[i]->mod_type, ldap_mods[i]->mod_values[0]);
  1354. }
  1355. ldap_entry = ldap_first_entry(ldapConn, ldap_result_msg);
  1356. for (i = 0; ldap_entry; i++) {
  1357. dn = ldap_get_dn(ldapConn, ldap_entry);
  1358. if ((error = ldap_modify_ext_s(ldapConn, dn, ldap_mods, NULL, NULL)) != LDAP_SUCCESS) {
  1359. ast_log(LOG_ERROR, "Couldn't modify dn:%s because %s", dn, ldap_err2string(error));
  1360. }
  1361. ldap_memfree(dn);
  1362. ldap_entry = ldap_next_entry(ldapConn, ldap_entry);
  1363. }
  1364. }
  1365. ast_mutex_unlock(&ldap_lock);
  1366. if (filter) {
  1367. ast_free(filter);
  1368. }
  1369. if (clean_basedn) {
  1370. ast_free(clean_basedn);
  1371. }
  1372. ldap_msgfree(ldap_result_msg);
  1373. ldap_mods_free(ldap_mods, 0);
  1374. return num_entries;
  1375. }
  1376. static struct ast_config_engine ldap_engine = {
  1377. .name = "ldap",
  1378. .load_func = config_ldap,
  1379. .realtime_func = realtime_ldap,
  1380. .realtime_multi_func = realtime_multi_ldap,
  1381. .update_func = update_ldap,
  1382. .update2_func = update2_ldap,
  1383. };
  1384. /*!
  1385. * \brief Load the module
  1386. *
  1387. * Module loading including tests for configuration or dependencies.
  1388. * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
  1389. * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
  1390. * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
  1391. * configuration file or other non-critical problem return
  1392. * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
  1393. *
  1394. * \todo Don't error or warn on a default install. If the config is
  1395. * default we should not attempt to connect to a server. -lathama
  1396. */
  1397. static int load_module(void)
  1398. {
  1399. if (parse_config() < 0) {
  1400. ast_log(LOG_ERROR, "Cannot load LDAP RealTime driver.\n");
  1401. return 0;
  1402. }
  1403. ast_mutex_lock(&ldap_lock);
  1404. if (!ldap_reconnect()) {
  1405. ast_log(LOG_WARNING, "Couldn't establish connection to LDAP directory. Check debug.\n");
  1406. }
  1407. ast_config_engine_register(&ldap_engine);
  1408. ast_verb(1, "LDAP RealTime driver loaded.\n");
  1409. ast_cli_register_multiple(ldap_cli, ARRAY_LEN(ldap_cli));
  1410. ast_mutex_unlock(&ldap_lock);
  1411. return 0;
  1412. }
  1413. /*! \brief Unload Module
  1414. *
  1415. */
  1416. static int unload_module(void)
  1417. {
  1418. /* Aquire control before doing anything to the module itself. */
  1419. ast_mutex_lock(&ldap_lock);
  1420. table_configs_free();
  1421. if (ldapConn) {
  1422. ldap_unbind_ext_s(ldapConn, NULL, NULL);
  1423. ldapConn = NULL;
  1424. }
  1425. ast_cli_unregister_multiple(ldap_cli, ARRAY_LEN(ldap_cli));
  1426. ast_config_engine_deregister(&ldap_engine);
  1427. ast_verb(1, "LDAP RealTime driver unloaded.\n");
  1428. /* Unlock so something else can destroy the lock. */
  1429. ast_mutex_unlock(&ldap_lock);
  1430. return 0;
  1431. }
  1432. /*! \breif Relod Module
  1433. */
  1434. static int reload(void)
  1435. {
  1436. /* Aquire control before doing anything to the module itself. */
  1437. ast_mutex_lock(&ldap_lock);
  1438. if (ldapConn) {
  1439. ldap_unbind_ext_s(ldapConn, NULL, NULL);
  1440. ldapConn = NULL;
  1441. }
  1442. if (parse_config() < 0) {
  1443. ast_log(LOG_NOTICE, "Cannot reload LDAP RealTime driver.\n");
  1444. ast_mutex_unlock(&ldap_lock);
  1445. return 0;
  1446. }
  1447. if (!ldap_reconnect()) {
  1448. ast_log(LOG_WARNING, "Couldn't establish connection to your directory server. Check debug.\n");
  1449. }
  1450. ast_verb(2, "LDAP RealTime driver reloaded.\n");
  1451. /* Done reloading. Release lock so others can now use driver. */
  1452. ast_mutex_unlock(&ldap_lock);
  1453. return 0;
  1454. }
  1455. /*! \brief parse the configuration file
  1456. */
  1457. static int parse_config(void)
  1458. {
  1459. struct ast_config *config;
  1460. struct ast_flags config_flags = {0};
  1461. const char *s, *host;
  1462. int port;
  1463. char *category_name = NULL;
  1464. /* Make sure that global variables are reset */
  1465. url[0] = '\0';
  1466. user[0] = '\0';
  1467. pass[0] = '\0';
  1468. base_distinguished_name[0] = '\0';
  1469. version = 3;
  1470. config = ast_config_load(RES_CONFIG_LDAP_CONF, config_flags);
  1471. if (config == CONFIG_STATUS_FILEMISSING || config == CONFIG_STATUS_FILEINVALID) {
  1472. ast_log(LOG_ERROR, "Cannot load configuration file: %s\n", RES_CONFIG_LDAP_CONF);
  1473. return -1;
  1474. }
  1475. if (!(s = ast_variable_retrieve(config, "_general", "user"))) {
  1476. ast_log(LOG_NOTICE, "No directory user found, anonymous binding as default.\n");
  1477. user[0] = '\0';
  1478. } else {
  1479. ast_copy_string(user, s, sizeof(user));
  1480. }
  1481. if (!ast_strlen_zero(user)) {
  1482. if (!(s = ast_variable_retrieve(config, "_general", "pass"))) {
  1483. ast_log(LOG_WARNING, "No directory password found, using 'asterisk' as default.\n");
  1484. ast_copy_string(pass, "asterisk", sizeof(pass));
  1485. } else {
  1486. ast_copy_string(pass, s, sizeof(pass));
  1487. }
  1488. }
  1489. /* URL is preferred, use host and port if not found */
  1490. if ((s = ast_variable_retrieve(config, "_general", "url"))) {
  1491. ast_copy_string(url, s, sizeof(url));
  1492. } else if ((host = ast_variable_retrieve(config, "_general", "host"))) {
  1493. if (!(s = ast_variable_retrieve(config, "_general", "port")) || sscanf(s, "%5d", &port) != 1 || port > 65535) {
  1494. ast_log(LOG_NOTICE, "No directory port found, using 389 as default.\n");
  1495. port = 389;
  1496. }
  1497. snprintf(url, sizeof(url), "ldap://%s:%d", host, port);
  1498. } else {
  1499. ast_log(LOG_ERROR, "No directory URL or host found.\n");
  1500. ast_config_destroy(config);
  1501. return -1;
  1502. }
  1503. if (!(s = ast_variable_retrieve(config, "_general", "basedn"))) {
  1504. ast_log(LOG_ERROR, "No LDAP base dn found, using '%s' as default.\n", RES_CONFIG_LDAP_DEFAULT_BASEDN);
  1505. ast_copy_string(base_distinguished_name, RES_CONFIG_LDAP_DEFAULT_BASEDN, sizeof(base_distinguished_name));
  1506. } else
  1507. ast_copy_string(base_distinguished_name, s, sizeof(base_distinguished_name));
  1508. if (!(s = ast_variable_retrieve(config, "_general", "version")) && !(s = ast_variable_retrieve(config, "_general", "protocol"))) {
  1509. ast_log(LOG_NOTICE, "No explicit LDAP version found, using 3 as default.\n");
  1510. } else if (sscanf(s, "%30d", &version) != 1 || version < 1 || version > 6) {
  1511. ast_log(LOG_WARNING, "Invalid LDAP version '%s', using 3 as default.\n", s);
  1512. version = 3;
  1513. }
  1514. table_configs_free();
  1515. while ((category_name = ast_category_browse(config, category_name))) {
  1516. int is_general = (strcasecmp(category_name, "_general") == 0);
  1517. int is_config = (strcasecmp(category_name, "config") == 0); /*!< using the [config] context for Static RealTime */
  1518. struct ast_variable *var = ast_variable_browse(config, category_name);
  1519. if (var) {
  1520. struct ldap_table_config *table_config =
  1521. table_config_for_table_name(category_name);
  1522. if (!table_config) {
  1523. table_config = table_config_new(category_name);
  1524. AST_LIST_INSERT_HEAD(&table_configs, table_config, entry);
  1525. if (is_general)
  1526. base_table_config = table_config;
  1527. if (is_config)
  1528. static_table_config = table_config;
  1529. }
  1530. for (; var; var = var->next) {
  1531. if (!strcasecmp(var->name, "additionalFilter")) {
  1532. table_config->additional_filter = ast_strdup(var->value);
  1533. } else {
  1534. ldap_table_config_add_attribute(table_config, var->name, var->value);
  1535. }
  1536. }
  1537. }
  1538. }
  1539. ast_config_destroy(config);
  1540. return 1;
  1541. }
  1542. /*! \note ldap_lock should have been locked before calling this function. */
  1543. static int ldap_reconnect(void)
  1544. {
  1545. int bind_result = 0;
  1546. struct berval cred;
  1547. if (ldapConn) {
  1548. ast_debug(2, "Everything seems fine.\n");
  1549. return 1;
  1550. }
  1551. if (ast_strlen_zero(url)) {
  1552. ast_log(LOG_ERROR, "Not enough parameters to connect to ldap directory\n");
  1553. return 0;
  1554. }
  1555. if (LDAP_SUCCESS != ldap_initialize(&ldapConn, url)) {
  1556. ast_log(LOG_ERROR, "Failed to init ldap connection to '%s'. Check debug for more info.\n", url);
  1557. return 0;
  1558. }
  1559. if (LDAP_OPT_SUCCESS != ldap_set_option(ldapConn, LDAP_OPT_PROTOCOL_VERSION, &version)) {
  1560. ast_log(LOG_WARNING, "Unable to set LDAP protocol version to %d, falling back to default.\n", version);
  1561. }
  1562. if (!ast_strlen_zero(user)) {
  1563. ast_debug(2, "bind to '%s' as user '%s'\n", url, user);
  1564. cred.bv_val = (char *) pass;
  1565. cred.bv_len = strlen(pass);
  1566. bind_result = ldap_sasl_bind_s(ldapConn, user, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
  1567. } else {
  1568. ast_debug(2, "bind %s anonymously\n", url);
  1569. cred.bv_val = NULL;
  1570. cred.bv_len = 0;
  1571. bind_result = ldap_sasl_bind_s(ldapConn, NULL, LDAP_SASL_SIMPLE, &cred, NULL, NULL, NULL);
  1572. }
  1573. if (bind_result == LDAP_SUCCESS) {
  1574. ast_debug(2, "Successfully connected to directory.\n");
  1575. connect_time = time(NULL);
  1576. return 1;
  1577. } else {
  1578. ast_log(LOG_WARNING, "bind failed: %s\n", ldap_err2string(bind_result));
  1579. ldap_unbind_ext_s(ldapConn, NULL, NULL);
  1580. ldapConn = NULL;
  1581. return 0;
  1582. }
  1583. }
  1584. /*! \brief Realtime Status
  1585. *
  1586. */
  1587. static char *realtime_ldap_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
  1588. {
  1589. char status[256], credentials[100] = "";
  1590. int ctimesec = time(NULL) - connect_time;
  1591. switch (cmd) {
  1592. case CLI_INIT:
  1593. e->command = "realtime show ldap status";
  1594. e->usage =
  1595. "Usage: realtime show ldap status\n"
  1596. " Shows connection information for the LDAP RealTime driver\n";
  1597. return NULL;
  1598. case CLI_GENERATE:
  1599. return NULL;
  1600. }
  1601. if (!ldapConn)
  1602. return CLI_FAILURE;
  1603. if (!ast_strlen_zero(url))
  1604. snprintf(status, sizeof(status), "Connected to '%s', baseDN %s", url, base_distinguished_name);
  1605. if (!ast_strlen_zero(user))
  1606. snprintf(credentials, sizeof(credentials), " with username %s", user);
  1607. if (ctimesec > 31536000) {
  1608. ast_cli(a->fd, "%s%s for %d years, %d days, %d hours, %d minutes, %d seconds.\n",
  1609. status, credentials, ctimesec / 31536000,
  1610. (ctimesec % 31536000) / 86400, (ctimesec % 86400) / 3600,
  1611. (ctimesec % 3600) / 60, ctimesec % 60);
  1612. } else if (ctimesec > 86400) {
  1613. ast_cli(a->fd, "%s%s for %d days, %d hours, %d minutes, %d seconds.\n",
  1614. status, credentials, ctimesec / 86400, (ctimesec % 86400) / 3600,
  1615. (ctimesec % 3600) / 60, ctimesec % 60);
  1616. } else if (ctimesec > 3600) {
  1617. ast_cli(a->fd, "%s%s for %d hours, %d minutes, %d seconds.\n",
  1618. status, credentials, ctimesec / 3600, (ctimesec % 3600) / 60,
  1619. ctimesec % 60);
  1620. } else if (ctimesec > 60) {
  1621. ast_cli(a->fd, "%s%s for %d minutes, %d seconds.\n", status, credentials,
  1622. ctimesec / 60, ctimesec % 60);
  1623. } else {
  1624. ast_cli(a->fd, "%s%s for %d seconds.\n", status, credentials, ctimesec);
  1625. }
  1626. return CLI_SUCCESS;
  1627. }
  1628. /*! \brief Module Information
  1629. *
  1630. */
  1631. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "LDAP realtime interface",
  1632. .support_level = AST_MODULE_SUPPORT_EXTENDED,
  1633. .load = load_module,
  1634. .unload = unload_module,
  1635. .reload = reload,
  1636. .load_pri = AST_MODPRI_REALTIME_DRIVER,
  1637. );