ld_cfg.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. /*
  2. * LDAP module - Configuration file parser
  3. *
  4. * Copyright (C) 2001-2003 FhG FOKUS
  5. * Copyright (C) 2004,2005 Free Software Foundation, Inc.
  6. * Copyright (C) 2005,2006 iptelorg GmbH
  7. *
  8. * This file is part of ser, a free SIP server.
  9. *
  10. * SER is free software; you can redistribute it and/or modify it under the
  11. * terms of the GNU General Public License as published by the Free Software
  12. * Foundation; either version 2 of the License, or (at your option) any later
  13. * version.
  14. *
  15. * SER is distributed in the hope that it will be useful, but WITHOUT ANY
  16. * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  17. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  18. * details.
  19. *
  20. * You should have received a copy of the GNU General Public License along
  21. * with this program; if not, write to the Free Software Foundation, Inc.,
  22. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. */
  24. #include "ld_cfg.h"
  25. #include "ld_mod.h"
  26. #include "ld_uri.h"
  27. #include "../../cfg_parser.h"
  28. #include "../../mem/mem.h"
  29. #include "../../dprint.h"
  30. #include "../../trim.h"
  31. #include "../../ut.h"
  32. #include "../../resolve.h"
  33. #include <ldap.h>
  34. #include <stdlib.h>
  35. #include <stdio.h>
  36. #include <libgen.h>
  37. enum section_type {
  38. LDAP_CON_SECTION = 0,
  39. LDAP_TABLE_SECTION
  40. };
  41. static struct ld_cfg* cfg = NULL;
  42. static struct ld_con_info* con = NULL;
  43. void ld_cfg_free(void)
  44. {
  45. struct ld_con_info* c;
  46. struct ld_cfg* ptr;
  47. int i;
  48. while (cfg) {
  49. ptr = cfg;
  50. cfg = cfg->next;
  51. if (ptr->table.s) pkg_free(ptr->table.s);
  52. if (ptr->base.s) pkg_free(ptr->base.s);
  53. if (ptr->filter.s) pkg_free(ptr->filter.s);
  54. for(i = 0; i < ptr->n; i++) {
  55. if (ptr->field[i].s) pkg_free(ptr->field[i].s);
  56. if (ptr->attr[i].s) pkg_free(ptr->attr[i].s);
  57. }
  58. if (ptr->field) pkg_free(ptr->field);
  59. if (ptr->attr) pkg_free(ptr->attr);
  60. if (ptr->syntax) pkg_free(ptr->syntax);
  61. }
  62. while (con) {
  63. c = con;
  64. con = con->next;
  65. if (c->id.s) pkg_free(c->id.s);
  66. if (c->host.s) pkg_free(c->host.s);
  67. if (c->username.s) pkg_free(c->username.s);
  68. if (c->password.s) pkg_free(c->password.s);
  69. pkg_free(c);
  70. }
  71. }
  72. static int parse_field_map(void* param, cfg_parser_t* st, unsigned int flags)
  73. {
  74. int ret;
  75. cfg_token_t t;
  76. void* ptr;
  77. static cfg_option_t syntaxes[] = {
  78. {"GeneralizedTime", .val = LD_SYNTAX_GENTIME},
  79. {"Integer", .val = LD_SYNTAX_INT },
  80. {"BitString", .val = LD_SYNTAX_BIT },
  81. {"Boolean", .val = LD_SYNTAX_BOOL },
  82. {"String", .val = LD_SYNTAX_STRING },
  83. {"Binary", .val = LD_SYNTAX_BIN },
  84. {"Float", .val = LD_SYNTAX_FLOAT },
  85. {0}
  86. };
  87. cfg_option_t* syntax;
  88. if (cfg_eat_equal(st, flags)) return -1;
  89. if (!(ptr = pkg_realloc(cfg->field, sizeof(str) * (cfg->n + 1)))) {
  90. ERR("ldap:%s:%d:%d Out of memory\n", st->file, st->line, st->col);
  91. return -1;
  92. }
  93. cfg->field = (str*)ptr;
  94. cfg->field[cfg->n].s = NULL;
  95. if (!(ptr = pkg_realloc(cfg->attr, sizeof(str) * (cfg->n + 1)))) {
  96. ERR("ldap:%s:%d:%d: Out of memory\n", st->file, st->line, st->col);
  97. return -1;
  98. }
  99. cfg->attr = (str*)ptr;
  100. cfg->attr[cfg->n].s = NULL;
  101. if (!(ptr = pkg_realloc(cfg->syntax, sizeof(enum ld_syntax)*(cfg->n+1)))) {
  102. ERR("ldap:%s:%d:%d: Out of memory\n", st->file, st->line, st->col);
  103. return -1;
  104. }
  105. cfg->syntax = (enum ld_syntax*)ptr;
  106. cfg->syntax[cfg->n] = LD_SYNTAX_STRING;
  107. cfg->n++;
  108. ret = cfg_get_token(&t, st, 0);
  109. if (ret < 0) return -1;
  110. if (ret > 0) {
  111. ERR("ldap:%s:%d:%d: Database field name expected\n",
  112. st->file, st->line, st->col);
  113. return -1;
  114. }
  115. if (t.type != CFG_TOKEN_ALPHA) {
  116. ERR("ldap:%s:%d:%d: Invalid field name format %d:'%.*s'\n",
  117. st->file, t.start.line, t.start.col,
  118. t.type, STR_FMT(&t.val));
  119. return -1;
  120. }
  121. if ((cfg->field[cfg->n - 1].s = as_asciiz(&t.val)) == NULL) {
  122. ERR("ldap:%s:%d:%d: Out of memory\n", st->file,
  123. t.start.line, t.start.col);
  124. return -1;
  125. }
  126. cfg->field[cfg->n - 1].len = t.val.len;
  127. ret = cfg_get_token(&t, st, 0);
  128. if (ret < 0) return -1;
  129. if (ret > 0) {
  130. ERR("ldap:%s:%d:%d: Delimiter ':' missing\n",
  131. st->file, st->line, st->col);
  132. return -1;
  133. }
  134. if (t.type != ':') {
  135. ERR("ldap:%s:%d:%d: Syntax error, ':' expected\n",
  136. st->file, t.start.line, t.start.col);
  137. return -1;
  138. }
  139. ret = cfg_get_token(&t, st, 0);
  140. if (ret < 0) return -1;
  141. if (ret > 0) {
  142. ERR("ldap:%s:%d:%d: LDAP Attribute syntax or name expected\n",
  143. st->file, st->line, st->col);
  144. return -1;
  145. }
  146. if (t.type == '(') {
  147. ret = cfg_get_token(&t, st, 0);
  148. if (ret < 0) return -1;
  149. if (ret > 0) {
  150. ERR("ldap:%s:%d:%d: LDAP Attribute Syntax expected\n",
  151. st->file, st->line, st->col);
  152. return -1;
  153. }
  154. if (t.type != CFG_TOKEN_ALPHA) {
  155. ERR("ldap:%s:%d:%d: Invalid LDAP attribute syntax format %d:'%.*s'\n",
  156. st->file, t.start.line, t.start.col,
  157. t.type, STR_FMT(&t.val));
  158. return -1;
  159. }
  160. if ((syntax = cfg_lookup_token(syntaxes, &t.val)) == NULL) {
  161. ERR("ldap:%s:%d:%d: Invalid syntaxt value '%.*s'\n",
  162. st->file, t.start.line, t.start.col, STR_FMT(&t.val));
  163. return -1;
  164. }
  165. cfg->syntax[cfg->n - 1] = syntax->val;
  166. ret = cfg_get_token(&t, st, 0);
  167. if (ret < 0) return -1;
  168. if (ret > 0) {
  169. ERR("ldap:%s:%d:%d: Closing ')' missing in attribute syntax\n",
  170. st->file, st->line, st->col);
  171. return -1;
  172. }
  173. if (t.type != ')') {
  174. ERR("ldap:%s:%d:%d: Syntax error, ')' expected\n",
  175. st->file, st->line, st->col);
  176. return -1;
  177. }
  178. ret = cfg_get_token(&t, st, 0);
  179. if (ret < 0) return -1;
  180. if (ret > 0) {
  181. ERR("ldap:%s:%d:%d: LDAP Attribute name expected\n",
  182. st->file, st->line, st->col);
  183. return -1;
  184. }
  185. }
  186. if (t.type != CFG_TOKEN_ALPHA) {
  187. ERR("ldap:%s:%d:%d: Invalid LDAP attribute name format %d:'%.*s'\n",
  188. st->file, t.start.line, t.start.col, t.type, STR_FMT(&t.val));
  189. return -1;
  190. }
  191. if ((cfg->attr[cfg->n - 1].s = as_asciiz(&t.val)) == NULL) {
  192. ERR("ldap:%s:%d:%d: Out of memory\n",
  193. st->file, t.start.line, t.start.col);
  194. return -1;
  195. }
  196. cfg->attr[cfg->n - 1].len = t.val.len;
  197. if (cfg_eat_eol(st, flags)) return -1;
  198. return 0;
  199. }
  200. static cfg_option_t scope_values[] = {
  201. {"base", .val = LDAP_SCOPE_BASE },
  202. {"onelevel", .val = LDAP_SCOPE_ONELEVEL},
  203. {"one", .val = LDAP_SCOPE_ONELEVEL},
  204. {"subtree", .val = LDAP_SCOPE_SUBTREE },
  205. {"sub", .val = LDAP_SCOPE_SUBTREE },
  206. #if defined HAVE_SCOPE_CHILDREN
  207. {"children", .val = LDAP_SCOPE_CHILDREN},
  208. #endif
  209. {0}
  210. };
  211. static cfg_option_t deref_values[] = {
  212. {"never", .val = LDAP_DEREF_NEVER }, /* default, 0x00 */
  213. {"searching", .val = LDAP_DEREF_SEARCHING},
  214. {"finding", .val = LDAP_DEREF_FINDING },
  215. {"always", .val = LDAP_DEREF_ALWAYS },
  216. {0}
  217. };
  218. static cfg_option_t ldap_tab_options[] = {
  219. {"scope", .param = scope_values, .f = cfg_parse_enum_opt},
  220. {"field_map", .f = parse_field_map},
  221. {"filter", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
  222. {"base", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
  223. {"timelimit", .f = cfg_parse_int_opt},
  224. {"sizelimit", .f = cfg_parse_int_opt},
  225. {"chase_references", .param = deref_values, .f = cfg_parse_enum_opt},
  226. {"chase_referrals", .f = cfg_parse_bool_opt},
  227. {0}
  228. };
  229. static cfg_option_t auth_values[] = {
  230. {"none", .val = LDAP_AUTHMECH_NONE},
  231. {"simple", .val = LDAP_AUTHMECH_SIMPLE},
  232. {"digest-md5", .val = LDAP_AUTHMECH_DIGESTMD5},
  233. {"external", .val = LDAP_AUTHMECH_EXTERNAL},
  234. {0}
  235. };
  236. static cfg_option_t ldap_con_options[] = {
  237. {"host", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
  238. {"port", .f = cfg_parse_int_opt},
  239. {"username", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
  240. {"password", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
  241. {"authtype", .param = auth_values, .f = cfg_parse_enum_opt},
  242. {"tls", .f = cfg_parse_bool_opt},
  243. {"ca_list", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
  244. {"require_certificate", .f = cfg_parse_str_opt, .flags = CFG_STR_PKGMEM},
  245. {0}
  246. };
  247. static cfg_option_t section_types[] = {
  248. {"connection", .val = LDAP_CON_SECTION},
  249. {"con", .val = LDAP_CON_SECTION},
  250. {"table", .val = LDAP_TABLE_SECTION},
  251. {0}
  252. };
  253. static int parse_section(void* param, cfg_parser_t* st, unsigned int flags)
  254. {
  255. cfg_token_t t;
  256. int ret, type, i;
  257. cfg_option_t* opt;
  258. str* id = NULL;
  259. struct ld_cfg* tab;
  260. struct ld_con_info* cinfo;
  261. ret = cfg_get_token(&t, st, 0);
  262. if (ret < 0) return -1;
  263. if (ret > 0) {
  264. ERR("%s:%d:%d: Section type missing\n",
  265. st->file, st->line, st->col);
  266. return -1;
  267. }
  268. if (t.type != CFG_TOKEN_ALPHA ||
  269. ((opt = cfg_lookup_token(section_types, &t.val)) == NULL)) {
  270. ERR("%s:%d:%d: Invalid section type %d:'%.*s'\n",
  271. st->file, t.start.line, t.start.col, t.type, STR_FMT(&t.val));
  272. return -1;
  273. }
  274. type = opt->val;
  275. if (type == LDAP_TABLE_SECTION) {
  276. if ((tab = pkg_malloc(sizeof(*tab))) == NULL) {
  277. ERR("ldap:%s:%d: Out of memory\n", st->file, st->line);
  278. return -1;
  279. }
  280. memset(tab, '\0', sizeof(*tab));
  281. tab->next = cfg;
  282. cfg = tab;
  283. cfg_set_options(st, ldap_tab_options);
  284. ldap_tab_options[2].param = &cfg->filter;
  285. ldap_tab_options[3].param = &cfg->base;
  286. for(i = 0; scope_values[i].name; i++) {
  287. scope_values[i].param = &cfg->scope;
  288. }
  289. ldap_tab_options[4].param = &cfg->timelimit;
  290. ldap_tab_options[5].param = &cfg->sizelimit;
  291. for(i = 0; deref_values[i].name; i++) {
  292. deref_values[i].param = &cfg->chase_references;
  293. }
  294. ldap_tab_options[7].param = &cfg->chase_referrals;
  295. } else if (type == LDAP_CON_SECTION) {
  296. if ((cinfo = pkg_malloc(sizeof(*cinfo))) == NULL) {
  297. ERR("ldap:%s:%d: Out of memory\n", st->file, st->line);
  298. return -1;
  299. }
  300. memset(cinfo, '\0', sizeof(*cinfo));
  301. cinfo->next = con;
  302. con = cinfo;
  303. cfg_set_options(st, ldap_con_options);
  304. ldap_con_options[0].param = &con->host;
  305. ldap_con_options[1].param = &con->port;
  306. ldap_con_options[2].param = &con->username;
  307. ldap_con_options[3].param = &con->password;
  308. for(i = 0; auth_values[i].name; i++) {
  309. auth_values[i].param = &con->authmech;
  310. }
  311. ldap_con_options[5].param = &con->tls;
  312. ldap_con_options[6].param = &con->ca_list;
  313. ldap_con_options[7].param = &con->req_cert;
  314. } else {
  315. BUG("%s:%d:%d: Unsupported section type %c\n",
  316. st->file, t.start.line, t.start.col, t.type);
  317. return -1;
  318. }
  319. ret = cfg_get_token(&t, st, 0);
  320. if (ret < 0) return -1;
  321. if (ret > 0) {
  322. ERR("%s:%d:%d: Delimiter ':' expected.\n",
  323. st->file, st->line, st->col);
  324. return -1;
  325. }
  326. if (type == LDAP_TABLE_SECTION) {
  327. id = &cfg->table;
  328. } else if (type == LDAP_CON_SECTION) {
  329. id = &con->id;
  330. } else {
  331. BUG("%s:%d:%d: Invalid section type %d\n", st->file,
  332. st->line, st->col, type);
  333. }
  334. ret = cfg_parse_str(id, st, CFG_STR_PKGMEM);
  335. if (ret < 0) return -1;
  336. if (ret > 0) {
  337. ERR("%s:%d:%d: Section identifier expected\n",
  338. st->file, st->line, st->col);
  339. return -1;
  340. }
  341. ret = cfg_get_token(&t, st, 0);
  342. if (ret < 0) return ret;
  343. if (ret > 0) {
  344. ERR("%s:%d:%d: Missing closing ']'.\n",
  345. st->file, st->line, st->col);
  346. return -1;
  347. }
  348. if (t. type != ']') {
  349. ERR("%s:%d:%d: Syntax error, ']' expected.\n",
  350. st->file, t.start.line, t.start.col);
  351. return -1;
  352. }
  353. if (cfg_eat_eol(st, flags)) return -1;
  354. return 0;
  355. }
  356. struct ld_cfg* ld_find_cfg(str* table)
  357. {
  358. struct ld_cfg* ptr;
  359. ptr = cfg;
  360. while(ptr) {
  361. if (ptr->table.len == table->len &&
  362. !strncmp(ptr->table.s, table->s, table->len))
  363. return ptr;
  364. ptr = ptr->next;
  365. }
  366. return NULL;
  367. }
  368. char* ld_find_attr_name(enum ld_syntax* syntax, struct ld_cfg* cfg, char* fld_name)
  369. {
  370. int i;
  371. for(i = 0; i < cfg->n; i++) {
  372. if (!strcmp(fld_name, cfg->field[i].s)) {
  373. *syntax = cfg->syntax[i];
  374. return cfg->attr[i].s;
  375. }
  376. }
  377. return NULL;
  378. }
  379. struct ld_con_info* ld_find_conn_info(str* conn_id)
  380. {
  381. struct ld_con_info* ptr;
  382. ptr = con;
  383. while(ptr) {
  384. if (ptr->id.len == conn_id->len &&
  385. !memcmp(ptr->id.s, conn_id->s, conn_id->len)) {
  386. return ptr;
  387. }
  388. ptr = ptr->next;
  389. }
  390. return NULL;
  391. }
  392. static int ld_cfg_validity_check(struct ld_cfg *cfg)
  393. {
  394. struct ld_cfg *pcfg;
  395. for (pcfg = cfg; pcfg; pcfg = pcfg->next) {
  396. if (pcfg->sizelimit < 0 || pcfg->sizelimit > LD_MAXINT) {
  397. ERR("ldap: invalid sizelimit (%d) specified\n", pcfg->sizelimit);
  398. return -1;
  399. }
  400. if (pcfg->timelimit < 0 || pcfg->timelimit > LD_MAXINT) {
  401. ERR("ldap: invalid timelimit (%d) specified\n", pcfg->timelimit);
  402. return -1;
  403. }
  404. }
  405. return 0;
  406. }
  407. int ld_load_cfg(str* filename)
  408. {
  409. cfg_parser_t* parser;
  410. cfg = NULL;
  411. if ((parser = cfg_parser_init(0, filename)) == NULL) {
  412. ERR("ldap: Error while initializing configuration file parser.\n");
  413. return -1;
  414. }
  415. cfg_section_parser(parser, parse_section, NULL);
  416. if (sr_cfg_parse(parser)) {
  417. if (cfg == NULL) {
  418. ERR("ldap: A table name (i.e. [table_name]) is missing in the "
  419. "configuration file.\n");
  420. }
  421. cfg_parser_close(parser);
  422. ld_cfg_free();
  423. return -1;
  424. }
  425. cfg_parser_close(parser);
  426. if (ld_cfg_validity_check(cfg)) {
  427. ld_cfg_free();
  428. return -1;
  429. }
  430. return 0;
  431. }