utilmod.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. /*
  5. * The following code handles the storage of PKCS 11 modules used by the
  6. * NSS. For the rest of NSS, only one kind of database handle exists:
  7. *
  8. * SFTKDBHandle
  9. *
  10. * There is one SFTKDBHandle for each key database and one for each cert
  11. * database. These databases are opened as associated pairs, one pair per
  12. * slot. SFTKDBHandles are reference counted objects.
  13. *
  14. * Each SFTKDBHandle points to a low level database handle (SDB). This handle
  15. * represents the underlying physical database. These objects are not
  16. * reference counted, and are 'owned' by their respective SFTKDBHandles.
  17. */
  18. #include "prprf.h"
  19. #include "prsystem.h"
  20. #include "secport.h"
  21. #include "utilpars.h"
  22. #include "secerr.h"
  23. #if defined(_WIN32)
  24. #include <io.h>
  25. #include <windows.h>
  26. #endif
  27. #ifdef XP_UNIX
  28. #include <unistd.h>
  29. #endif
  30. #include <sys/types.h>
  31. #include <sys/stat.h>
  32. #include <fcntl.h>
  33. #if defined(_WIN32)
  34. #define os_fdopen _fdopen
  35. #define os_truncate_open_flags _O_CREAT | _O_RDWR | _O_TRUNC
  36. #define os_append_open_flags _O_CREAT | _O_RDWR | _O_APPEND
  37. #define os_open_permissions_type int
  38. #define os_open_permissions_default _S_IREAD | _S_IWRITE
  39. #define os_stat_type struct _stat
  40. /*
  41. * Convert a UTF8 string to Unicode wide character
  42. */
  43. LPWSTR
  44. _NSSUTIL_UTF8ToWide(const char *buf)
  45. {
  46. DWORD size;
  47. LPWSTR wide;
  48. if (!buf) {
  49. return NULL;
  50. }
  51. size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, NULL, 0);
  52. if (size == 0) {
  53. return NULL;
  54. }
  55. wide = PORT_Alloc(sizeof(WCHAR) * size);
  56. if (!wide) {
  57. return NULL;
  58. }
  59. size = MultiByteToWideChar(CP_UTF8, 0, buf, -1, wide, size);
  60. if (size == 0) {
  61. PORT_Free(wide);
  62. return NULL;
  63. }
  64. return wide;
  65. }
  66. static int
  67. os_open(const char *filename, int oflag, int pmode)
  68. {
  69. int fd;
  70. if (!filename) {
  71. return -1;
  72. }
  73. wchar_t *filenameWide = _NSSUTIL_UTF8ToWide(filename);
  74. if (!filenameWide) {
  75. return -1;
  76. }
  77. fd = _wopen(filenameWide, oflag, pmode);
  78. PORT_Free(filenameWide);
  79. return fd;
  80. }
  81. static int
  82. os_stat(const char *path, os_stat_type *buffer)
  83. {
  84. int result;
  85. if (!path) {
  86. return -1;
  87. }
  88. wchar_t *pathWide = _NSSUTIL_UTF8ToWide(path);
  89. if (!pathWide) {
  90. return -1;
  91. }
  92. result = _wstat(pathWide, buffer);
  93. PORT_Free(pathWide);
  94. return result;
  95. }
  96. static FILE *
  97. os_fopen(const char *filename, const char *mode)
  98. {
  99. FILE *fp;
  100. if (!filename || !mode) {
  101. return NULL;
  102. }
  103. wchar_t *filenameWide = _NSSUTIL_UTF8ToWide(filename);
  104. if (!filenameWide) {
  105. return NULL;
  106. }
  107. wchar_t *modeWide = _NSSUTIL_UTF8ToWide(mode);
  108. if (!modeWide) {
  109. PORT_Free(filenameWide);
  110. return NULL;
  111. }
  112. fp = _wfopen(filenameWide, modeWide);
  113. PORT_Free(filenameWide);
  114. PORT_Free(modeWide);
  115. return fp;
  116. }
  117. PRStatus
  118. _NSSUTIL_Access(const char *path, PRAccessHow how)
  119. {
  120. int result;
  121. if (!path) {
  122. return PR_FAILURE;
  123. }
  124. int mode;
  125. switch (how) {
  126. case PR_ACCESS_WRITE_OK:
  127. mode = 2;
  128. break;
  129. case PR_ACCESS_READ_OK:
  130. mode = 4;
  131. break;
  132. case PR_ACCESS_EXISTS:
  133. mode = 0;
  134. break;
  135. default:
  136. return PR_FAILURE;
  137. }
  138. wchar_t *pathWide = _NSSUTIL_UTF8ToWide(path);
  139. if (!pathWide) {
  140. return PR_FAILURE;
  141. }
  142. result = _waccess(pathWide, mode);
  143. PORT_Free(pathWide);
  144. return result < 0 ? PR_FAILURE : PR_SUCCESS;
  145. }
  146. static PRStatus
  147. nssutil_Delete(const char *name)
  148. {
  149. BOOL result;
  150. if (!name) {
  151. return PR_FAILURE;
  152. }
  153. wchar_t *nameWide = _NSSUTIL_UTF8ToWide(name);
  154. if (!nameWide) {
  155. return PR_FAILURE;
  156. }
  157. result = DeleteFileW(nameWide);
  158. PORT_Free(nameWide);
  159. return result ? PR_SUCCESS : PR_FAILURE;
  160. }
  161. static PRStatus
  162. nssutil_Rename(const char *from, const char *to)
  163. {
  164. BOOL result;
  165. if (!from || !to) {
  166. return PR_FAILURE;
  167. }
  168. wchar_t *fromWide = _NSSUTIL_UTF8ToWide(from);
  169. if (!fromWide) {
  170. return PR_FAILURE;
  171. }
  172. wchar_t *toWide = _NSSUTIL_UTF8ToWide(to);
  173. if (!toWide) {
  174. PORT_Free(fromWide);
  175. return PR_FAILURE;
  176. }
  177. result = MoveFileW(fromWide, toWide);
  178. PORT_Free(fromWide);
  179. PORT_Free(toWide);
  180. return result ? PR_SUCCESS : PR_FAILURE;
  181. }
  182. #else
  183. #define os_fopen fopen
  184. #define os_open open
  185. #define os_fdopen fdopen
  186. #define os_stat stat
  187. #define os_truncate_open_flags O_CREAT | O_RDWR | O_TRUNC
  188. #define os_append_open_flags O_CREAT | O_RDWR | O_APPEND
  189. #define os_open_permissions_type mode_t
  190. #define os_open_permissions_default 0600
  191. #define os_stat_type struct stat
  192. #define nssutil_Delete PR_Delete
  193. #define nssutil_Rename PR_Rename
  194. #endif
  195. /****************************************************************
  196. *
  197. * Secmod database.
  198. *
  199. * The new secmod database is simply a text file with each of the module
  200. * entries in the following form:
  201. *
  202. * #
  203. * # This is a comment The next line is the library to load
  204. * library=libmypkcs11.so
  205. * name="My PKCS#11 module"
  206. * params="my library's param string"
  207. * nss="NSS parameters"
  208. * other="parameters for other libraries and applications"
  209. *
  210. * library=libmynextpk11.so
  211. * name="My other PKCS#11 module"
  212. */
  213. /*
  214. * Smart string cat functions. Automatically manage the memory.
  215. * The first parameter is the destination string. If it's null, we
  216. * allocate memory for it. If it's not, we reallocate memory
  217. * so the the concanenated string fits.
  218. */
  219. static char *
  220. nssutil_DupnCat(char *baseString, const char *str, int str_len)
  221. {
  222. int baseStringLen = baseString ? PORT_Strlen(baseString) : 0;
  223. int len = baseStringLen + 1;
  224. char *newString;
  225. len += str_len;
  226. newString = (char *)PORT_Realloc(baseString, len);
  227. if (newString == NULL) {
  228. PORT_Free(baseString);
  229. return NULL;
  230. }
  231. PORT_Memcpy(&newString[baseStringLen], str, str_len);
  232. newString[len - 1] = 0;
  233. return newString;
  234. }
  235. /* Same as nssutil_DupnCat except it concatenates the full string, not a
  236. * partial one */
  237. static char *
  238. nssutil_DupCat(char *baseString, const char *str)
  239. {
  240. return nssutil_DupnCat(baseString, str, PORT_Strlen(str));
  241. }
  242. /* function to free up all the memory associated with a null terminated
  243. * array of module specs */
  244. static SECStatus
  245. nssutil_releaseSpecList(char **moduleSpecList)
  246. {
  247. if (moduleSpecList) {
  248. char **index;
  249. for (index = moduleSpecList; *index; index++) {
  250. PORT_Free(*index);
  251. }
  252. PORT_Free(moduleSpecList);
  253. }
  254. return SECSuccess;
  255. }
  256. #define SECMOD_STEP 10
  257. static SECStatus
  258. nssutil_growList(char ***pModuleList, int *useCount, int last)
  259. {
  260. char **newModuleList;
  261. *useCount += SECMOD_STEP;
  262. newModuleList = (char **)PORT_Realloc(*pModuleList,
  263. *useCount * sizeof(char *));
  264. if (newModuleList == NULL) {
  265. return SECFailure;
  266. }
  267. PORT_Memset(&newModuleList[last], 0, sizeof(char *) * SECMOD_STEP);
  268. *pModuleList = newModuleList;
  269. return SECSuccess;
  270. }
  271. static char *
  272. _NSSUTIL_GetOldSecmodName(const char *dbname, const char *filename)
  273. {
  274. char *file = NULL;
  275. char *dirPath = PORT_Strdup(dbname);
  276. char *sep;
  277. sep = PORT_Strrchr(dirPath, *NSSUTIL_PATH_SEPARATOR);
  278. #ifdef _WIN32
  279. if (!sep) {
  280. /* utilparst.h defines NSSUTIL_PATH_SEPARATOR as "/" for all
  281. * platforms. */
  282. sep = PORT_Strrchr(dirPath, '\\');
  283. }
  284. #endif
  285. if (sep) {
  286. *sep = 0;
  287. file = PR_smprintf("%s" NSSUTIL_PATH_SEPARATOR "%s", dirPath, filename);
  288. } else {
  289. file = PR_smprintf("%s", filename);
  290. }
  291. PORT_Free(dirPath);
  292. return file;
  293. }
  294. static SECStatus nssutil_AddSecmodDBEntry(const char *appName,
  295. const char *filename,
  296. const char *dbname,
  297. const char *module, PRBool rw);
  298. enum lfopen_mode { lfopen_truncate,
  299. lfopen_append };
  300. FILE *
  301. lfopen(const char *name, enum lfopen_mode om, os_open_permissions_type open_perms)
  302. {
  303. int fd;
  304. FILE *file;
  305. fd = os_open(name,
  306. (om == lfopen_truncate) ? os_truncate_open_flags : os_append_open_flags,
  307. open_perms);
  308. if (fd < 0) {
  309. return NULL;
  310. }
  311. file = os_fdopen(fd, (om == lfopen_truncate) ? "w+" : "a+");
  312. if (!file) {
  313. close(fd);
  314. }
  315. /* file inherits fd */
  316. return file;
  317. }
  318. #define MAX_LINE_LENGTH 2048
  319. /*
  320. * Read all the existing modules in out of the file.
  321. */
  322. static char **
  323. nssutil_ReadSecmodDB(const char *appName,
  324. const char *filename, const char *dbname,
  325. char *params, PRBool rw)
  326. {
  327. FILE *fd = NULL;
  328. char **moduleList = NULL;
  329. int moduleCount = 1;
  330. int useCount = SECMOD_STEP;
  331. char line[MAX_LINE_LENGTH];
  332. PRBool internal = PR_FALSE;
  333. PRBool skipParams = PR_FALSE;
  334. char *moduleString = NULL;
  335. char *paramsValue = NULL;
  336. PRBool failed = PR_TRUE;
  337. moduleList = (char **)PORT_ZAlloc(useCount * sizeof(char *));
  338. if (moduleList == NULL)
  339. return NULL;
  340. if (dbname == NULL) {
  341. goto return_default;
  342. }
  343. /* do we really want to use streams here */
  344. fd = os_fopen(dbname, "r");
  345. if (fd == NULL)
  346. goto done;
  347. /*
  348. * the following loop takes line separated config lines and collapses
  349. * the lines to a single string, escaping and quoting as necessary.
  350. */
  351. /* loop state variables */
  352. moduleString = NULL; /* current concatenated string */
  353. internal = PR_FALSE; /* is this an internal module */
  354. skipParams = PR_FALSE; /* did we find an override parameter block*/
  355. paramsValue = NULL; /* the current parameter block value */
  356. do {
  357. int len;
  358. if (fgets(line, sizeof(line), fd) == NULL) {
  359. goto endloop;
  360. }
  361. /* remove the ending newline */
  362. len = PORT_Strlen(line);
  363. if (len >= 2 && line[len - 2] == '\r' && line[len - 1] == '\n') {
  364. len = len - 2;
  365. line[len] = 0;
  366. } else if (len && (line[len - 1] == '\n' || line[len - 1] == '\r')) {
  367. len--;
  368. line[len] = 0;
  369. }
  370. if (*line == '#') {
  371. continue;
  372. }
  373. if (*line != 0) {
  374. /*
  375. * The PKCS #11 group standard assumes blocks of strings
  376. * separated by new lines, clumped by new lines. Internally
  377. * we take strings separated by spaces, so we may need to escape
  378. * certain spaces.
  379. */
  380. char *value = PORT_Strchr(line, '=');
  381. /* there is no value, write out the stanza as is */
  382. if (value == NULL || value[1] == 0) {
  383. if (moduleString) {
  384. moduleString = nssutil_DupnCat(moduleString, " ", 1);
  385. if (moduleString == NULL)
  386. goto loser;
  387. }
  388. moduleString = nssutil_DupCat(moduleString, line);
  389. if (moduleString == NULL)
  390. goto loser;
  391. /* value is already quoted, just write it out */
  392. } else if (value[1] == '"') {
  393. if (moduleString) {
  394. moduleString = nssutil_DupnCat(moduleString, " ", 1);
  395. if (moduleString == NULL)
  396. goto loser;
  397. }
  398. moduleString = nssutil_DupCat(moduleString, line);
  399. if (moduleString == NULL)
  400. goto loser;
  401. /* we have an override parameter section, remember that
  402. * we found this (see following comment about why this
  403. * is necessary). */
  404. if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
  405. skipParams = PR_TRUE;
  406. }
  407. /*
  408. * The internal token always overrides it's parameter block
  409. * from the passed in parameters, so wait until then end
  410. * before we include the parameter block in case we need to
  411. * override it. NOTE: if the parameter block is quoted with ("),
  412. * this override does not happen. This allows you to override
  413. * the application's parameter configuration.
  414. *
  415. * parameter block state is controlled by the following variables:
  416. * skipParams - Bool : set to true of we have an override param
  417. * block (all other blocks, either implicit or explicit are
  418. * ignored).
  419. * paramsValue - char * : pointer to the current param block. In
  420. * the absence of overrides, paramsValue is set to the first
  421. * parameter block we find. All subsequent blocks are ignored.
  422. * When we find an internal token, the application passed
  423. * parameters take precident.
  424. */
  425. } else if (PORT_Strncasecmp(line, "parameters", 10) == 0) {
  426. /* already have parameters */
  427. if (paramsValue) {
  428. continue;
  429. }
  430. paramsValue = NSSUTIL_Quote(&value[1], '"');
  431. if (paramsValue == NULL)
  432. goto loser;
  433. continue;
  434. } else {
  435. /* may need to quote */
  436. char *newLine;
  437. if (moduleString) {
  438. moduleString = nssutil_DupnCat(moduleString, " ", 1);
  439. if (moduleString == NULL)
  440. goto loser;
  441. }
  442. moduleString = nssutil_DupnCat(moduleString, line, value - line + 1);
  443. if (moduleString == NULL)
  444. goto loser;
  445. newLine = NSSUTIL_Quote(&value[1], '"');
  446. if (newLine == NULL)
  447. goto loser;
  448. moduleString = nssutil_DupCat(moduleString, newLine);
  449. PORT_Free(newLine);
  450. if (moduleString == NULL)
  451. goto loser;
  452. }
  453. /* check to see if it's internal? */
  454. if (PORT_Strncasecmp(line, "NSS=", 4) == 0) {
  455. /* This should be case insensitive! reviewers make
  456. * me fix it if it's not */
  457. if (PORT_Strstr(line, "internal")) {
  458. internal = PR_TRUE;
  459. /* override the parameters */
  460. if (paramsValue) {
  461. PORT_Free(paramsValue);
  462. }
  463. paramsValue = NSSUTIL_Quote(params, '"');
  464. }
  465. }
  466. continue;
  467. }
  468. if ((moduleString == NULL) || (*moduleString == 0)) {
  469. continue;
  470. }
  471. endloop:
  472. /*
  473. * if we are here, we have found a complete stanza. Now write out
  474. * any param section we may have found.
  475. */
  476. if (paramsValue) {
  477. /* we had an override */
  478. if (!skipParams) {
  479. moduleString = nssutil_DupnCat(moduleString, " parameters=", 12);
  480. if (moduleString == NULL)
  481. goto loser;
  482. moduleString = nssutil_DupCat(moduleString, paramsValue);
  483. if (moduleString == NULL)
  484. goto loser;
  485. }
  486. PORT_Free(paramsValue);
  487. paramsValue = NULL;
  488. }
  489. if ((moduleCount + 1) >= useCount) {
  490. SECStatus rv;
  491. rv = nssutil_growList(&moduleList, &useCount, moduleCount + 1);
  492. if (rv != SECSuccess) {
  493. goto loser;
  494. }
  495. }
  496. if (internal) {
  497. moduleList[0] = moduleString;
  498. } else {
  499. moduleList[moduleCount] = moduleString;
  500. moduleCount++;
  501. }
  502. moduleString = NULL;
  503. internal = PR_FALSE;
  504. skipParams = PR_FALSE;
  505. } while (!feof(fd));
  506. if (moduleString) {
  507. PORT_Free(moduleString);
  508. moduleString = NULL;
  509. }
  510. done:
  511. /* if we couldn't open a pkcs11 database, look for the old one */
  512. if (fd == NULL) {
  513. char *olddbname = _NSSUTIL_GetOldSecmodName(dbname, filename);
  514. PRStatus status;
  515. /* couldn't get the old name */
  516. if (!olddbname) {
  517. goto bail;
  518. }
  519. /* old one exists */
  520. status = _NSSUTIL_Access(olddbname, PR_ACCESS_EXISTS);
  521. if (status == PR_SUCCESS) {
  522. PR_smprintf_free(olddbname);
  523. PORT_ZFree(moduleList, useCount * sizeof(char *));
  524. PORT_SetError(SEC_ERROR_LEGACY_DATABASE);
  525. return NULL;
  526. }
  527. bail:
  528. if (olddbname) {
  529. PR_smprintf_free(olddbname);
  530. }
  531. }
  532. return_default:
  533. if (!moduleList[0]) {
  534. char *newParams;
  535. moduleString = PORT_Strdup(NSSUTIL_DEFAULT_INTERNAL_INIT1);
  536. newParams = NSSUTIL_Quote(params, '"');
  537. if (newParams == NULL)
  538. goto loser;
  539. moduleString = nssutil_DupCat(moduleString, newParams);
  540. PORT_Free(newParams);
  541. if (moduleString == NULL)
  542. goto loser;
  543. moduleString = nssutil_DupCat(moduleString,
  544. NSSUTIL_DEFAULT_INTERNAL_INIT2);
  545. if (moduleString == NULL)
  546. goto loser;
  547. moduleString = nssutil_DupCat(moduleString,
  548. NSSUTIL_DEFAULT_SFTKN_FLAGS);
  549. if (moduleString == NULL)
  550. goto loser;
  551. moduleString = nssutil_DupCat(moduleString,
  552. NSSUTIL_DEFAULT_INTERNAL_INIT3);
  553. if (moduleString == NULL)
  554. goto loser;
  555. moduleList[0] = moduleString;
  556. moduleString = NULL;
  557. }
  558. failed = PR_FALSE;
  559. loser:
  560. /*
  561. * cleanup
  562. */
  563. /* deal with trust cert db here */
  564. if (moduleString) {
  565. PORT_Free(moduleString);
  566. moduleString = NULL;
  567. }
  568. if (paramsValue) {
  569. PORT_Free(paramsValue);
  570. paramsValue = NULL;
  571. }
  572. if (failed || (moduleList[0] == NULL)) {
  573. /* This is wrong! FIXME */
  574. nssutil_releaseSpecList(moduleList);
  575. moduleList = NULL;
  576. failed = PR_TRUE;
  577. }
  578. if (fd != NULL) {
  579. fclose(fd);
  580. } else if (!failed && rw) {
  581. /* update our internal module */
  582. nssutil_AddSecmodDBEntry(appName, filename, dbname, moduleList[0], rw);
  583. }
  584. return moduleList;
  585. }
  586. static SECStatus
  587. nssutil_ReleaseSecmodDBData(const char *appName,
  588. const char *filename, const char *dbname,
  589. char **moduleSpecList, PRBool rw)
  590. {
  591. if (moduleSpecList) {
  592. nssutil_releaseSpecList(moduleSpecList);
  593. }
  594. return SECSuccess;
  595. }
  596. /*
  597. * Delete a module from the Data Base
  598. */
  599. static SECStatus
  600. nssutil_DeleteSecmodDBEntry(const char *appName,
  601. const char *filename,
  602. const char *dbname,
  603. const char *args,
  604. PRBool rw)
  605. {
  606. /* SHDB_FIXME implement */
  607. os_stat_type stat_existing;
  608. os_open_permissions_type file_mode;
  609. FILE *fd = NULL;
  610. FILE *fd2 = NULL;
  611. char line[MAX_LINE_LENGTH];
  612. char *dbname2 = NULL;
  613. char *block = NULL;
  614. char *name = NULL;
  615. char *lib = NULL;
  616. int name_len = 0, lib_len = 0;
  617. PRBool skip = PR_FALSE;
  618. PRBool found = PR_FALSE;
  619. if (dbname == NULL) {
  620. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  621. return SECFailure;
  622. }
  623. if (!rw) {
  624. PORT_SetError(SEC_ERROR_READ_ONLY);
  625. return SECFailure;
  626. }
  627. dbname2 = PORT_Strdup(dbname);
  628. if (dbname2 == NULL)
  629. goto loser;
  630. dbname2[strlen(dbname) - 1]++;
  631. /* get the permissions of the existing file, or use the default */
  632. if (!os_stat(dbname, &stat_existing)) {
  633. file_mode = stat_existing.st_mode;
  634. } else {
  635. file_mode = os_open_permissions_default;
  636. }
  637. /* do we really want to use streams here */
  638. fd = os_fopen(dbname, "r");
  639. if (fd == NULL)
  640. goto loser;
  641. fd2 = lfopen(dbname2, lfopen_truncate, file_mode);
  642. if (fd2 == NULL)
  643. goto loser;
  644. name = NSSUTIL_ArgGetParamValue("name", args);
  645. if (name) {
  646. name_len = PORT_Strlen(name);
  647. }
  648. lib = NSSUTIL_ArgGetParamValue("library", args);
  649. if (lib) {
  650. lib_len = PORT_Strlen(lib);
  651. }
  652. /*
  653. * the following loop takes line separated config files and collapses
  654. * the lines to a single string, escaping and quoting as necessary.
  655. */
  656. /* loop state variables */
  657. block = NULL;
  658. skip = PR_FALSE;
  659. while (fgets(line, sizeof(line), fd) != NULL) {
  660. /* If we are processing a block (we haven't hit a blank line yet */
  661. if (*line != '\n') {
  662. /* skip means we are in the middle of a block we are deleting */
  663. if (skip) {
  664. continue;
  665. }
  666. /* if we haven't found the block yet, check to see if this block
  667. * matches our requirements */
  668. if (!found && ((name && (PORT_Strncasecmp(line, "name=", 5) == 0) &&
  669. (PORT_Strncmp(line + 5, name, name_len) == 0)) ||
  670. (lib && (PORT_Strncasecmp(line, "library=", 8) == 0) &&
  671. (PORT_Strncmp(line + 8, lib, lib_len) == 0)))) {
  672. /* yup, we don't need to save any more data, */
  673. PORT_Free(block);
  674. block = NULL;
  675. /* we don't need to collect more of this block */
  676. skip = PR_TRUE;
  677. /* we don't need to continue searching for the block */
  678. found = PR_TRUE;
  679. continue;
  680. }
  681. /* not our match, continue to collect data in this block */
  682. block = nssutil_DupCat(block, line);
  683. continue;
  684. }
  685. /* we've collected a block of data that wasn't the module we were
  686. * looking for, write it out */
  687. if (block) {
  688. fwrite(block, PORT_Strlen(block), 1, fd2);
  689. PORT_Free(block);
  690. block = NULL;
  691. }
  692. /* If we didn't just delete the this block, keep the blank line */
  693. if (!skip) {
  694. fputs(line, fd2);
  695. }
  696. /* we are definately not in a deleted block anymore */
  697. skip = PR_FALSE;
  698. }
  699. fclose(fd);
  700. fclose(fd2);
  701. if (found) {
  702. /* rename dbname2 to dbname */
  703. nssutil_Delete(dbname);
  704. nssutil_Rename(dbname2, dbname);
  705. } else {
  706. nssutil_Delete(dbname2);
  707. }
  708. PORT_Free(dbname2);
  709. PORT_Free(lib);
  710. PORT_Free(name);
  711. PORT_Free(block);
  712. return SECSuccess;
  713. loser:
  714. if (fd != NULL) {
  715. fclose(fd);
  716. }
  717. if (fd2 != NULL) {
  718. fclose(fd2);
  719. }
  720. if (dbname2) {
  721. nssutil_Delete(dbname2);
  722. PORT_Free(dbname2);
  723. }
  724. PORT_Free(lib);
  725. PORT_Free(name);
  726. return SECFailure;
  727. }
  728. /*
  729. * Add a module to the Data base
  730. */
  731. static SECStatus
  732. nssutil_AddSecmodDBEntry(const char *appName,
  733. const char *filename, const char *dbname,
  734. const char *module, PRBool rw)
  735. {
  736. os_stat_type stat_existing;
  737. os_open_permissions_type file_mode;
  738. FILE *fd = NULL;
  739. char *block = NULL;
  740. PRBool libFound = PR_FALSE;
  741. if (dbname == NULL) {
  742. PORT_SetError(SEC_ERROR_INVALID_ARGS);
  743. return SECFailure;
  744. }
  745. /* can't write to a read only module */
  746. if (!rw) {
  747. PORT_SetError(SEC_ERROR_READ_ONLY);
  748. return SECFailure;
  749. }
  750. /* remove the previous version if it exists */
  751. (void)nssutil_DeleteSecmodDBEntry(appName, filename, dbname, module, rw);
  752. /* get the permissions of the existing file, or use the default */
  753. if (!os_stat(dbname, &stat_existing)) {
  754. file_mode = stat_existing.st_mode;
  755. } else {
  756. file_mode = os_open_permissions_default;
  757. }
  758. fd = lfopen(dbname, lfopen_append, file_mode);
  759. if (fd == NULL) {
  760. return SECFailure;
  761. }
  762. module = NSSUTIL_ArgStrip(module);
  763. while (*module) {
  764. int count;
  765. char *keyEnd = PORT_Strchr(module, '=');
  766. char *value;
  767. if (PORT_Strncmp(module, "library=", 8) == 0) {
  768. libFound = PR_TRUE;
  769. }
  770. if (keyEnd == NULL) {
  771. block = nssutil_DupCat(block, module);
  772. break;
  773. }
  774. block = nssutil_DupnCat(block, module, keyEnd - module + 1);
  775. if (block == NULL) {
  776. goto loser;
  777. }
  778. value = NSSUTIL_ArgFetchValue(&keyEnd[1], &count);
  779. if (value) {
  780. block = nssutil_DupCat(block, NSSUTIL_ArgStrip(value));
  781. PORT_Free(value);
  782. }
  783. if (block == NULL) {
  784. goto loser;
  785. }
  786. block = nssutil_DupnCat(block, "\n", 1);
  787. module = keyEnd + 1 + count;
  788. module = NSSUTIL_ArgStrip(module);
  789. }
  790. if (block) {
  791. if (!libFound) {
  792. fprintf(fd, "library=\n");
  793. }
  794. fwrite(block, PORT_Strlen(block), 1, fd);
  795. fprintf(fd, "\n");
  796. PORT_Free(block);
  797. block = NULL;
  798. }
  799. fclose(fd);
  800. return SECSuccess;
  801. loser:
  802. PORT_Free(block);
  803. fclose(fd);
  804. return SECFailure;
  805. }
  806. char **
  807. NSSUTIL_DoModuleDBFunction(unsigned long function, char *parameters, void *args)
  808. {
  809. char *secmod = NULL;
  810. char *appName = NULL;
  811. char *filename = NULL;
  812. NSSDBType dbType = NSS_DB_TYPE_NONE;
  813. PRBool rw;
  814. static char *success = "Success";
  815. char **rvstr = NULL;
  816. secmod = _NSSUTIL_GetSecmodName(parameters, &dbType, &appName,
  817. &filename, &rw);
  818. if ((dbType == NSS_DB_TYPE_LEGACY) ||
  819. (dbType == NSS_DB_TYPE_MULTIACCESS)) {
  820. /* we can't handle the old database, only softoken can */
  821. PORT_SetError(SEC_ERROR_LEGACY_DATABASE);
  822. rvstr = NULL;
  823. goto done;
  824. }
  825. switch (function) {
  826. case SECMOD_MODULE_DB_FUNCTION_FIND:
  827. rvstr = nssutil_ReadSecmodDB(appName, filename,
  828. secmod, (char *)parameters, rw);
  829. break;
  830. case SECMOD_MODULE_DB_FUNCTION_ADD:
  831. rvstr = (nssutil_AddSecmodDBEntry(appName, filename,
  832. secmod, (char *)args, rw) == SECSuccess)
  833. ? &success
  834. : NULL;
  835. break;
  836. case SECMOD_MODULE_DB_FUNCTION_DEL:
  837. rvstr = (nssutil_DeleteSecmodDBEntry(appName, filename,
  838. secmod, (char *)args, rw) == SECSuccess)
  839. ? &success
  840. : NULL;
  841. break;
  842. case SECMOD_MODULE_DB_FUNCTION_RELEASE:
  843. rvstr = (nssutil_ReleaseSecmodDBData(appName, filename,
  844. secmod, (char **)args, rw) == SECSuccess)
  845. ? &success
  846. : NULL;
  847. break;
  848. }
  849. done:
  850. if (secmod)
  851. PR_smprintf_free(secmod);
  852. if (appName)
  853. PORT_Free(appName);
  854. if (filename)
  855. PORT_Free(filename);
  856. return rvstr;
  857. }