dbconf.c 14 KB

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