dbconf.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. #include <config.h>
  11. #endif
  12. #include <string.h>
  13. /* This was malloc.h - but it's moved to stdlib.h on most platforms, and FBSD is strict */
  14. /* Make it stdlib.h, and revert to malloc.h with ifdefs if we have issues here. WB 2016 */
  15. #include <stdlib.h>
  16. #include <ctype.h>
  17. #include <ldaputil/errors.h>
  18. #include <ldaputil/certmap.h>
  19. #include <ldaputil/encode.h>
  20. #include <ldaputil/dbconf.h>
  21. #define BIG_LINE 1024
  22. static const char *DB_DIRECTIVE = "directory";
  23. static const int DB_DIRECTIVE_LEN = 9; /* strlen("DB_DIRECTIVE") */
  24. static const char *ENCODED = "encoded";
  25. static void
  26. insert_dbinfo_propval(DBConfDBInfo_t *db_info,
  27. DBPropVal_t *propval)
  28. {
  29. if (db_info->lastprop) {
  30. db_info->lastprop->next = propval;
  31. } else {
  32. db_info->firstprop = propval;
  33. }
  34. db_info->lastprop = propval;
  35. }
  36. static void
  37. insert_dbconf_dbinfo(DBConfInfo_t *conf_info,
  38. DBConfDBInfo_t *db_info)
  39. {
  40. if (conf_info->lastdb) {
  41. conf_info->lastdb->next = db_info;
  42. } else {
  43. conf_info->firstdb = db_info;
  44. }
  45. conf_info->lastdb = db_info;
  46. }
  47. void
  48. dbconf_free_propval(DBPropVal_t *propval)
  49. {
  50. if (propval) {
  51. if (propval->prop)
  52. free(propval->prop);
  53. if (propval->val)
  54. free(propval->val);
  55. memset((void *)propval, 0, sizeof(DBPropVal_t));
  56. free(propval);
  57. }
  58. }
  59. NSAPI_PUBLIC void
  60. dbconf_free_dbinfo(DBConfDBInfo_t *db_info)
  61. {
  62. if (db_info) {
  63. DBPropVal_t *next;
  64. DBPropVal_t *cur;
  65. if (db_info->dbname)
  66. free(db_info->dbname);
  67. if (db_info->url)
  68. free(db_info->url);
  69. cur = db_info->firstprop;
  70. while (cur) {
  71. next = cur->next;
  72. dbconf_free_propval(cur);
  73. cur = next;
  74. }
  75. memset((void *)db_info, 0, sizeof(DBConfDBInfo_t));
  76. free(db_info);
  77. }
  78. }
  79. NSAPI_PUBLIC void
  80. dbconf_free_confinfo(DBConfInfo_t *conf_info)
  81. {
  82. DBConfDBInfo_t *next;
  83. DBConfDBInfo_t *cur;
  84. if (conf_info) {
  85. cur = conf_info->firstdb;
  86. while (cur) {
  87. next = cur->next;
  88. dbconf_free_dbinfo(cur);
  89. cur = next;
  90. }
  91. memset((void *)conf_info, 0, sizeof(DBConfInfo_t));
  92. free(conf_info);
  93. }
  94. }
  95. static int
  96. skip_blank_lines_and_spaces(FILE *fp, char *buf, char **ptr_out, int *eof)
  97. {
  98. char *ptr = buf;
  99. char *end;
  100. while (buf && (*buf || fgets(buf, BIG_LINE, fp))) {
  101. ptr = buf;
  102. /* skip leading whitespace */
  103. while (*ptr && isspace(*ptr))
  104. ++ptr;
  105. /* skip blank line or comment */
  106. if (!*ptr || *ptr == '#') {
  107. *buf = 0; /* to force reading of next line */
  108. continue;
  109. }
  110. /* Non-blank line found */
  111. break;
  112. }
  113. *ptr_out = ptr;
  114. if (!*ptr) {
  115. *eof = 1;
  116. } else {
  117. /* skip trailing whitespace */
  118. end = ptr + strlen(ptr) - 1;
  119. while (isspace(*end))
  120. *end-- = 0;
  121. }
  122. return LDAPU_SUCCESS;
  123. }
  124. static int
  125. dbconf_parse_propval(char *buf, char *ptr, DBConfDBInfo_t *db_info)
  126. {
  127. char *dbname = db_info->dbname;
  128. int dbname_len = strlen(dbname);
  129. char *prop;
  130. char *val;
  131. DBPropVal_t *propval;
  132. char *delimeter_chars = " \t";
  133. char *lastchar;
  134. int end_of_prop;
  135. char *encval = 0; /* encoded value */
  136. char *origprop = 0;
  137. if ((ptr - buf + dbname_len > BIG_LINE) ||
  138. strncmp(ptr, dbname, dbname_len) ||
  139. !(ptr[dbname_len] == ':' || isspace(ptr[dbname_len]))) {
  140. /* Not a prop-val for the current db but not an error */
  141. return LDAPU_ERR_NOT_PROPVAL;
  142. }
  143. /* remove the last char if it is newline */
  144. lastchar = strrchr(buf, '\n');
  145. if (lastchar)
  146. *lastchar = '\0';
  147. prop = ptr + dbname_len + 1;
  148. while (*prop && (isspace(*prop) || *prop == ':'))
  149. ++prop;
  150. if (!*prop) {
  151. return LDAPU_ERR_PROP_IS_MISSING;
  152. }
  153. end_of_prop = strcspn(prop, delimeter_chars);
  154. if (prop[end_of_prop] != '\0') {
  155. /* buf doesn't end here -- val is present */
  156. prop[end_of_prop] = '\0';
  157. val = &prop[end_of_prop + 1];
  158. while (*val && isspace(*val))
  159. ++val;
  160. if (*val == '\0')
  161. val = 0;
  162. } else {
  163. val = 0;
  164. }
  165. /*
  166. * The prop-val line could be one of the following:
  167. * "<dbname>:prop val" OR "<dbname>:encoded prop encval"
  168. * If (prop == "encoded") then the val has "prop encval".
  169. * Get the actual prop from val and get encval (i.e. encoded value)
  170. * and decode it. If it is encoded then the val part must be non-NULL.
  171. */
  172. if (val && *val && !strcmp(prop, ENCODED)) {
  173. /* val has the actual prop followed by the encoded value */
  174. origprop = prop;
  175. prop = val;
  176. while (*prop && (isspace(*prop) || *prop == ':'))
  177. ++prop;
  178. if (!*prop) {
  179. return LDAPU_ERR_PROP_IS_MISSING;
  180. }
  181. end_of_prop = strcspn(prop, delimeter_chars);
  182. if (prop[end_of_prop] != '\0') {
  183. /* buf doesn't end here -- encval is present */
  184. prop[end_of_prop] = '\0';
  185. encval = &prop[end_of_prop + 1];
  186. while (*encval && isspace(*encval))
  187. ++encval;
  188. if (*encval == '\0')
  189. encval = 0;
  190. } else {
  191. encval = 0;
  192. }
  193. if (!encval) {
  194. /* special case - if encval is null, "encoded" itself is a
  195. * property and what we have in prop now is the value. */
  196. val = prop;
  197. prop = origprop;
  198. } else {
  199. /* decode the value */
  200. val = dbconf_decodeval(encval);
  201. }
  202. }
  203. /* Success - we have prop & val */
  204. propval = (DBPropVal_t *)malloc(sizeof(DBPropVal_t));
  205. if (!propval) {
  206. if (encval && val)
  207. free(val);
  208. return LDAPU_ERR_OUT_OF_MEMORY;
  209. }
  210. memset((void *)propval, 0, sizeof(DBPropVal_t));
  211. propval->prop = strdup(prop);
  212. propval->val = val ? strdup(val) : 0;
  213. if (encval && val)
  214. free(val); /* val was allocated by dbconf_decodeval */
  215. if (!propval->prop || (val && !propval->val)) {
  216. dbconf_free_propval(propval);
  217. return LDAPU_ERR_OUT_OF_MEMORY;
  218. }
  219. insert_dbinfo_propval(db_info, propval);
  220. return LDAPU_SUCCESS;
  221. }
  222. static int
  223. dbconf_read_propval(FILE *fp, char *buf, DBConfDBInfo_t *db_info, int *eof)
  224. {
  225. int rv;
  226. char *ptr = buf;
  227. while (buf && (*buf || fgets(buf, BIG_LINE, fp))) {
  228. ptr = buf;
  229. rv = skip_blank_lines_and_spaces(fp, buf, &ptr, eof);
  230. if (rv != LDAPU_SUCCESS || *eof)
  231. return rv;
  232. /* We have a non-blank line which could be prop-val pair for the
  233. * dbname in the db_info. parse the prop-val pair and continue.
  234. */
  235. rv = dbconf_parse_propval(buf, ptr, db_info);
  236. if (rv == LDAPU_ERR_NOT_PROPVAL)
  237. return LDAPU_SUCCESS;
  238. if (rv != LDAPU_SUCCESS)
  239. return rv;
  240. *buf = 0; /* to force reading of next line */
  241. }
  242. if (!*buf)
  243. *eof = 1;
  244. return LDAPU_SUCCESS;
  245. }
  246. static int
  247. parse_directive(char *buf, const char *directive, const int directive_len, DBConfDBInfo_t **db_info_out)
  248. {
  249. DBConfDBInfo_t *db_info;
  250. char *dbname;
  251. char *url;
  252. int end_of_dbname;
  253. char *delimeter_chars = " \t";
  254. char *lastchar;
  255. /* remove the last char if it is newline */
  256. lastchar = strrchr(buf, '\n');
  257. if (lastchar)
  258. *lastchar = '\0';
  259. if (strncmp(buf, directive, directive_len) ||
  260. !isspace(buf[directive_len])) {
  261. return LDAPU_ERR_DIRECTIVE_IS_MISSING;
  262. }
  263. dbname = buf + directive_len + 1;
  264. while (*dbname && isspace(*dbname))
  265. ++dbname;
  266. if (!*dbname) {
  267. return LDAPU_ERR_DBNAME_IS_MISSING;
  268. }
  269. end_of_dbname = strcspn(dbname, delimeter_chars);
  270. if (dbname[end_of_dbname] != '\0') {
  271. /* buf doesn't end here -- url is present */
  272. dbname[end_of_dbname] = '\0';
  273. url = &dbname[end_of_dbname + 1];
  274. while (*url && isspace(*url))
  275. ++url;
  276. if (*url == '\0')
  277. url = 0;
  278. } else {
  279. url = 0;
  280. }
  281. /* Success - we have dbname & url */
  282. db_info = (DBConfDBInfo_t *)malloc(sizeof(DBConfDBInfo_t));
  283. if (!db_info)
  284. return LDAPU_ERR_OUT_OF_MEMORY;
  285. memset((void *)db_info, 0, sizeof(DBConfDBInfo_t));
  286. db_info->dbname = strdup(dbname);
  287. db_info->url = url ? strdup(url) : 0;
  288. if (!db_info->dbname || (url && !db_info->url)) {
  289. dbconf_free_dbinfo(db_info);
  290. return LDAPU_ERR_OUT_OF_MEMORY;
  291. }
  292. *db_info_out = db_info;
  293. return LDAPU_SUCCESS;
  294. }
  295. /* Read the next database info from the file and put it in db_info_out. The
  296. * buf may contain first line of the database info. When this function
  297. * finishes, the buf may contain unprocessed information (which should be
  298. * passed to the next call to read_db_info).
  299. */
  300. static int
  301. read_db_info(FILE *fp, char *buf, DBConfDBInfo_t **db_info_out, const char *directive, const int directive_len, int *eof)
  302. {
  303. char *ptr;
  304. DBConfDBInfo_t *db_info;
  305. int rv;
  306. *db_info_out = 0;
  307. rv = skip_blank_lines_and_spaces(fp, buf, &ptr, eof);
  308. if (rv != LDAPU_SUCCESS || *eof)
  309. return rv;
  310. /* We possibly have a directive of the form "directory <name> <url>" */
  311. rv = parse_directive(ptr, directive, directive_len, &db_info);
  312. if (rv != LDAPU_SUCCESS)
  313. return rv;
  314. /* We have parsed the directive successfully -- lets look for additional
  315. * property-value pairs for the database.
  316. */
  317. if (!fgets(buf, BIG_LINE, fp)) {
  318. *eof = 1;
  319. rv = LDAPU_SUCCESS;
  320. } else {
  321. rv = dbconf_read_propval(fp, buf, db_info, eof);
  322. }
  323. if (rv != LDAPU_SUCCESS) {
  324. dbconf_free_dbinfo(db_info);
  325. *db_info_out = 0;
  326. } else {
  327. *db_info_out = db_info;
  328. }
  329. return rv;
  330. }
  331. int
  332. dbconf_read_config_file_sub(const char *file,
  333. const char *directive,
  334. const int directive_len,
  335. DBConfInfo_t **conf_info_out)
  336. {
  337. FILE *fp;
  338. DBConfInfo_t *conf_info;
  339. DBConfDBInfo_t *db_info;
  340. char buf[BIG_LINE];
  341. int rv;
  342. int eof;
  343. buf[0] = 0;
  344. if ((fp = fopen(file, "r")) == NULL) {
  345. return LDAPU_ERR_CANNOT_OPEN_FILE;
  346. }
  347. /* Allocate DBConfInfo_t */
  348. conf_info = (DBConfInfo_t *)malloc(sizeof(DBConfInfo_t));
  349. if (!conf_info) {
  350. fclose(fp);
  351. return LDAPU_ERR_OUT_OF_MEMORY;
  352. }
  353. memset((void *)conf_info, 0, sizeof(DBConfInfo_t));
  354. /* Read each db info */
  355. eof = 0;
  356. while (!eof &&
  357. ((rv = read_db_info(fp, buf, &db_info, directive, directive_len, &eof)) == LDAPU_SUCCESS)) {
  358. insert_dbconf_dbinfo(conf_info, db_info);
  359. }
  360. if (rv != LDAPU_SUCCESS) {
  361. dbconf_free_confinfo(conf_info);
  362. *conf_info_out = 0;
  363. } else {
  364. *conf_info_out = conf_info;
  365. }
  366. fclose(fp);
  367. return rv;
  368. }
  369. NSAPI_PUBLIC int
  370. dbconf_read_config_file(const char *file, DBConfInfo_t **conf_info_out)
  371. {
  372. return dbconf_read_config_file_sub(file, DB_DIRECTIVE, DB_DIRECTIVE_LEN,
  373. conf_info_out);
  374. }
  375. int
  376. dbconf_read_default_dbinfo_sub(const char *file,
  377. const char *directive,
  378. const int directive_len,
  379. DBConfDBInfo_t **db_info_out)
  380. {
  381. FILE *fp;
  382. DBConfDBInfo_t *db_info;
  383. char buf[BIG_LINE];
  384. int rv;
  385. int eof;
  386. buf[0] = 0;
  387. if ((fp = fopen(file, "r")) == NULL) {
  388. return LDAPU_ERR_CANNOT_OPEN_FILE;
  389. }
  390. /* Read each db info until eof or dbname == default*/
  391. eof = 0;
  392. while (!eof &&
  393. ((rv = read_db_info(fp, buf, &db_info, directive, directive_len, &eof)) == LDAPU_SUCCESS)) {
  394. if (!strcmp(db_info->dbname, DBCONF_DEFAULT_DBNAME))
  395. break;
  396. dbconf_free_dbinfo(db_info);
  397. db_info = NULL;
  398. }
  399. if (rv != LDAPU_SUCCESS) {
  400. *db_info_out = 0;
  401. } else {
  402. *db_info_out = db_info;
  403. }
  404. fclose(fp);
  405. return rv;
  406. }
  407. NSAPI_PUBLIC int
  408. dbconf_read_default_dbinfo(const char *file,
  409. DBConfDBInfo_t **db_info_out)
  410. {
  411. return dbconf_read_default_dbinfo_sub(file, DB_DIRECTIVE, DB_DIRECTIVE_LEN,
  412. db_info_out);
  413. }
  414. /*
  415. * ldapu_strcasecmp - is like strcasecmp on UNIX but also accepts null strings.
  416. */
  417. int
  418. ldapu_strcasecmp(const char *s1, const char *s2)
  419. {
  420. if (!s1)
  421. return !s2 ? 0 : 0 - tolower(*s2);
  422. else if (!s2)
  423. return tolower(*s1);
  424. return strcasecmp(s1, s2);
  425. }
  426. NSAPI_PUBLIC int
  427. ldapu_dbinfo_attrval(DBConfDBInfo_t *db_info,
  428. const char *attr,
  429. char **val)
  430. {
  431. /* Look for given attr in the db_info and return its value */
  432. int rv = LDAPU_ATTR_NOT_FOUND;
  433. DBPropVal_t *next;
  434. *val = 0;
  435. if (db_info) {
  436. next = db_info->firstprop;
  437. while (next) {
  438. rv = ldapu_strcasecmp(attr, next->prop);
  439. if (!rv) {
  440. /* Found the property */
  441. *val = next->val ? strdup(next->val) : 0;
  442. if (next->val && !*val) {
  443. rv = LDAPU_ERR_OUT_OF_MEMORY;
  444. } else {
  445. rv = LDAPU_SUCCESS;
  446. }
  447. break;
  448. }
  449. next = next->next;
  450. }
  451. }
  452. return rv;
  453. }
  454. void
  455. dbconf_print_propval(DBPropVal_t *propval)
  456. {
  457. if (propval) {
  458. fprintf(stderr, "\tprop: \"%s\"\tval: \"%s\"\n", propval->prop,
  459. propval->val ? propval->val : "");
  460. } else {
  461. fprintf(stderr, "Null propval\n");
  462. }
  463. }
  464. void
  465. dbconf_print_dbinfo(DBConfDBInfo_t *db_info)
  466. {
  467. DBPropVal_t *next;
  468. if (db_info) {
  469. fprintf(stderr, "dbname: \"%s\"\n", db_info->dbname);
  470. fprintf(stderr, "url: \t\"%s\"\n", db_info->url ? db_info->url : "");
  471. next = db_info->firstprop;
  472. while (next) {
  473. dbconf_print_propval(next);
  474. next = next->next;
  475. }
  476. } else {
  477. fprintf(stderr, "Null db_info\n");
  478. }
  479. }
  480. void
  481. dbconf_print_confinfo(DBConfInfo_t *conf_info)
  482. {
  483. DBConfDBInfo_t *next;
  484. if (conf_info) {
  485. next = conf_info->firstdb;
  486. while (next) {
  487. dbconf_print_dbinfo(next);
  488. next = next->next;
  489. }
  490. } else {
  491. fprintf(stderr, "Null conf_info\n");
  492. }
  493. }
  494. NSAPI_PUBLIC int
  495. dbconf_output_db_directive(FILE *fp, const char *dbname, const char *url)
  496. {
  497. fprintf(fp, "%s %s %s\n", DB_DIRECTIVE, dbname, url);
  498. return LDAPU_SUCCESS;
  499. }
  500. NSAPI_PUBLIC int
  501. dbconf_output_propval(FILE *fp, const char *dbname, const char *prop, const char *val, const int encoded)
  502. {
  503. if (encoded && val && *val) {
  504. char *new_val = dbconf_encodeval(val);
  505. if (!new_val)
  506. return LDAPU_ERR_OUT_OF_MEMORY;
  507. fprintf(fp, "%s:%s %s %s\n", dbname, ENCODED,
  508. prop, new_val);
  509. free(new_val);
  510. } else {
  511. fprintf(fp, "%s:%s %s\n", dbname, prop, val ? val : "");
  512. }
  513. return LDAPU_SUCCESS;
  514. }
  515. NSAPI_PUBLIC int
  516. dbconf_get_dbnames(const char *dbmap, char ***dbnames_out, int *cnt_out)
  517. {
  518. DBConfInfo_t *conf_info = 0;
  519. DBConfDBInfo_t *db = 0;
  520. int cnt = 0;
  521. char **dbnames = 0;
  522. char *heap = 0;
  523. int rv;
  524. *dbnames_out = 0;
  525. *cnt_out = 0;
  526. rv = dbconf_read_config_file(dbmap, &conf_info);
  527. if (rv != LDAPU_SUCCESS)
  528. return rv;
  529. db = conf_info->firstdb;
  530. dbnames = (char **)malloc(32 * 1024);
  531. heap = (char *)dbnames + 2 * 1024;
  532. if (!dbnames) {
  533. dbconf_free_confinfo(conf_info);
  534. return LDAPU_ERR_OUT_OF_MEMORY;
  535. }
  536. *dbnames_out = dbnames;
  537. while (db) {
  538. *dbnames++ = heap;
  539. strcpy(heap, db->dbname);
  540. heap += strlen(db->dbname) + 1;
  541. db = db->next;
  542. cnt++;
  543. }
  544. *dbnames = NULL;
  545. *cnt_out = cnt;
  546. dbconf_free_confinfo(conf_info);
  547. return LDAPU_SUCCESS;
  548. }
  549. NSAPI_PUBLIC int
  550. dbconf_free_dbnames(char **dbnames)
  551. {
  552. if (dbnames)
  553. free(dbnames);
  554. return LDAPU_SUCCESS;
  555. }