cookie.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  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. --- END COPYRIGHT BLOCK --- */
  6. /*
  7. * cookie.c -- routines to generate and manipulate cookies for dsgw
  8. */
  9. #include "dsgw.h"
  10. #include "../../include/portable.h"
  11. #include <stdio.h>
  12. #if !defined( XP_WIN32 )
  13. #include <sys/param.h>
  14. #endif
  15. #include <ssl.h>
  16. #ifdef NSS38_AND_OLDER
  17. #include <secrng.h>
  18. #else
  19. #include "ecl-exp.h"
  20. #endif
  21. #include <nss.h>
  22. #include <base64.h>
  23. #include <sys/types.h>
  24. #include <limits.h>
  25. #include <string.h>
  26. #ifdef _WIN32
  27. #include <windows.h>
  28. #include <time.h>
  29. #include <io.h>
  30. #include <fcntl.h>
  31. #include <sys/locking.h>
  32. #else /* _WIN32 */
  33. #include <unistd.h>
  34. #endif /* _WIN32 */
  35. #include <pk11func.h>
  36. #include <pkcs11.h>
  37. #include <pk11pqg.h>
  38. static char *dsgw_MungeString(const char *unmunged_string);
  39. static char *dsgw_UnMungeString(const char *munged_string);
  40. static char *dsgw_encDec(CK_ATTRIBUTE_TYPE operation, const char *msg);
  41. void dsgw_initNSS(void);
  42. static char tokDes[34] = "Communicator Generic Crypto Svcs";
  43. static char ptokDes[34] = "Internal (Software) Token ";
  44. int dsgw_NSSInitializedAlready = 0;
  45. /* Table for converting binary values to and from hexadecimal */
  46. static char hex[] = "0123456789abcdef";
  47. #if 0
  48. static char dec[256] = {
  49. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */
  50. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 37 */
  51. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ' ' - '/' */
  52. 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* '0' - '?' */
  53. 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '@' - 'O' */
  54. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 'P' - '_' */
  55. 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '`' - 'o' */
  56. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 'p' - DEL */
  57. };
  58. #endif
  59. #define CKLEN 32
  60. #define RNDBUFLEN ( CKLEN / 2 )
  61. #define CKBUFSIZ 255
  62. /*
  63. * Given a buffer buf of length len, return a pointer to a string containing
  64. * the hex-encoded version of buf. The caller is responsible for freeing
  65. * the memory this routine allocates.
  66. */
  67. static char *
  68. buf2str( unsigned char *buf, int len )
  69. {
  70. char *obuf;
  71. int i;
  72. char *p;
  73. if ( buf == NULL ) {
  74. return NULL;
  75. }
  76. p = obuf = dsgw_ch_malloc( CKLEN + 1 );
  77. for ( i = 0; i < len; i++) {
  78. *p++ = hex[( buf[ i ] >> 4 ) & 0xf ];
  79. *p++ = hex[( buf[ i ]) & 0xf ];
  80. }
  81. *p++ = '\0';
  82. return obuf;
  83. }
  84. /*
  85. * Generate a random string of hex-encoded digits, CKLEN characters in
  86. * length. This routine allocates memory which the caller is responsible
  87. * for freeing.
  88. */
  89. char *
  90. dsgw_mkrndstr()
  91. {
  92. unsigned char buf[ RNDBUFLEN ];
  93. PK11_ConfigurePKCS11(NULL, NULL, tokDes, ptokDes, NULL, NULL, NULL, NULL, 0, 0 );
  94. /*NSS_NoDB_Init(NULL);*/
  95. dsgw_initNSS();
  96. PK11_GenerateRandom(buf, RNDBUFLEN);
  97. return( buf2str( buf, RNDBUFLEN ));
  98. }
  99. FILE *
  100. dsgw_opencookiedb()
  101. {
  102. FILE *fp;
  103. time_t now;
  104. int newfile = 0;
  105. char cdb[MAXPATHLEN]; /*DSGW_COOKIEDB_FNAME + context*/
  106. #ifdef XP_WIN32
  107. #ifndef F_OK
  108. #define F_OK 0
  109. #endif
  110. #endif
  111. sprintf(cdb, "%s.%s", DSGW_COOKIEDB_FNAME, context);
  112. if ( access( cdb, F_OK ) == 0 ) {
  113. fp = fopen( cdb, "r+" );
  114. } else {
  115. newfile = 1;
  116. fp = fopen( cdb, "w" );
  117. }
  118. if ( fp == NULL ) {
  119. return NULL;
  120. }
  121. /* fseek( fp, 0L, SEEK_SET ); */
  122. #ifdef XP_WIN32
  123. (void) chmod( cdb, _S_IREAD | _S_IWRITE );
  124. #else
  125. (void) chmod( cdb, S_IRUSR | S_IWUSR );
  126. #endif
  127. /* acquire a lock */
  128. #ifdef _WIN32
  129. while ( _locking( _fileno( fp ), LK_NBLCK, 0xFFFFFFFF ) != 0 ) {
  130. #else
  131. #ifdef USE_LOCKF
  132. while ( lockf( fileno( fp ), F_LOCK, 0 ) != 0 ) {
  133. #else /* _WIN32 */
  134. while ( flock( fileno( fp ), LOCK_EX ) != 0 ) {
  135. #endif
  136. #endif /* _WIN32 */
  137. ; /* NULL */
  138. }
  139. if ( newfile ) {
  140. time( &now );
  141. fprintf( fp, "lastpurge: %-20lu\n", now );
  142. fflush( fp );
  143. fseek( fp, 0L, SEEK_SET );
  144. }
  145. return fp;
  146. }
  147. void
  148. dsgw_closecookiedb( FILE *fp )
  149. {
  150. #ifdef _WIN32
  151. _locking( _fileno( fp ), LK_UNLCK, 0xFFFFFFFF );
  152. #else /* _WIN32 */
  153. #ifdef USE_LOCKF
  154. lockf( fileno( fp ), F_ULOCK, 0 );
  155. #else
  156. flock( fileno( fp ), LOCK_UN );
  157. #endif
  158. #endif /* _WIN32 */
  159. fclose( fp );
  160. }
  161. /*
  162. * Return a pointer to the password associated with the given
  163. * cookie and dn. If the cookie was not found in the database,
  164. * or if the cookie has expired, 1 is returned. On success, 0 is returned
  165. * and ret_pw is set to the password from the database. As a side effect,
  166. * if the database has not been purged of expired entries in more than
  167. * 10 minutes, the database is purged.
  168. *
  169. * As a special case, if the cookie is expired and gc->gc_mode is
  170. * DSGW_MODE_DOMODIFY (that is, the user is saving a modified entry), then
  171. * return 0 if the cookie has been expired for no more than 5 minutes.
  172. * This keeps users from being frustrated by getting an editable view of
  173. * an entry and having the cookie expire while editing.
  174. * The caller is responsible for freeing ret_pw.
  175. */
  176. int
  177. dsgw_ckdn2passwd( char *rndstr, char *dn, char **ret_pw )
  178. {
  179. FILE *fp;
  180. char buf[ CKBUFSIZ ];
  181. char *p, *pw, *lifetimestr, *cdn;
  182. time_t now;
  183. int expired = 0;
  184. if ( !strcmp( rndstr, DSGW_UNAUTHSTR )) {
  185. *ret_pw = NULL;
  186. return 0;
  187. }
  188. if (( fp = dsgw_opencookiedb()) == NULL ) {
  189. return DSGW_CKDB_CANTOPEN;
  190. }
  191. for (;;) {
  192. if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) {
  193. dsgw_closecookiedb( fp );
  194. #ifdef DSGW_DEBUG
  195. dsgw_log( "dsgw_ckdn2passwd: cookie <%s> not found in db\n",
  196. rndstr );
  197. #endif
  198. return DSGW_CKDB_KEY_NOT_PRESENT;
  199. }
  200. #ifdef DSGW_DEBUG
  201. dsgw_log( "dsgw_ckdn2passwd: retrieved buf from db: <%s>\n", buf );
  202. #endif
  203. if ( buf[ strlen( buf ) - 1 ] == '\n' ) {
  204. buf[ strlen( buf ) - 1 ] = '\0';
  205. }
  206. if ( strncmp( buf, rndstr, strlen( rndstr ))) {
  207. continue;
  208. }
  209. if (( p = strchr( buf, ':' )) == NULL ) {
  210. dsgw_closecookiedb( fp );
  211. #ifdef DSGW_DEBUG
  212. dsgw_log( "dsgw_ckdn2passwd: colon 1 missing\n" );
  213. #endif
  214. return DSGW_CKDB_DBERROR;
  215. }
  216. *p++ = '\0';
  217. lifetimestr = p;
  218. if (( p = strchr( lifetimestr, ':' )) == NULL ) {
  219. dsgw_closecookiedb( fp );
  220. #ifdef DSGW_DEBUG
  221. dsgw_log( "dsgw_ckdn2passwd: colon 2 missing\n" );
  222. #endif
  223. return DSGW_CKDB_DBERROR;
  224. }
  225. *p++ = '\0';
  226. pw = p;
  227. if (( p = strchr( pw, ':' )) == NULL ) {
  228. dsgw_closecookiedb( fp );
  229. #ifdef DSGW_DEBUG
  230. dsgw_log( "dsgw_ckdn2passwd: colon 3 missing\n" );
  231. #endif
  232. return DSGW_CKDB_DBERROR;
  233. }
  234. *p++ = '\0';
  235. cdn = p;
  236. if ( strcmp( dn, cdn )) {
  237. dsgw_closecookiedb( fp );
  238. #ifdef DSGW_DEBUG
  239. dsgw_log( "dsgw_ckdn2passwd: dn <%s> != cdn <%s>\n", dn, cdn );
  240. #endif
  241. return DSGW_CKDB_KEY_NOT_PRESENT;
  242. }
  243. /* expired? */
  244. time( &now );
  245. if ( gc->gc_mode == DSGW_MODE_DOMODIFY ) {
  246. if ( now > ( atoi( lifetimestr ) + DSGW_MODIFY_GRACEPERIOD )) {
  247. expired = 1;
  248. } else {
  249. #ifdef DSGW_DEBUG
  250. dsgw_log( "dsgw_ckdn2passwd: cookie expired (%ld > %ld) but within domodify grace period\n", now, atoi( lifetimestr ));
  251. #endif
  252. }
  253. } else if ( now > atoi( lifetimestr )) {
  254. expired = 1;
  255. }
  256. if ( expired != 0 ) {
  257. dsgw_closecookiedb( fp );
  258. #ifdef DSGW_DEBUG
  259. dsgw_log( "dsgw_ckdn2passwd: expired (%ld > %ld)\n", now, atoi( lifetimestr ));
  260. #endif
  261. return DSGW_CKDB_EXPIRED;
  262. }
  263. *ret_pw = dsgw_UnMungeString( pw );
  264. dsgw_closecookiedb( fp );
  265. return ( *ret_pw == NULL ) ? 1 : 0;
  266. }
  267. }
  268. /*
  269. * Store the given cookie and password into the database. The cookie
  270. * is marked to expire at the time given by "expires". Returns 0 if
  271. * successful, otherwise returns an error as given in dsgw.h.
  272. * As a side effect, if the database has not been purged of expired
  273. * entries in more than 10 minutes, the database is purged.
  274. *
  275. * Note: DNs are stored unescaped in the cookie database. Passwords
  276. * are stored as "munged" values (encrypted using a hard-coded key and
  277. * then converted to ASCII as described in RFC-1113) to make them a bit
  278. * less obvious and to avoid problems which might arise from embedded ":"
  279. * characters in the password (":" is the field separator in the database).
  280. */
  281. int
  282. dsgw_storecookie( char *rndstr, char *dn, char *password, time_t lifetime )
  283. {
  284. FILE *fp;
  285. char *epw;
  286. time_t now, lp;
  287. if (( fp = dsgw_opencookiedb()) == NULL ) {
  288. return DSGW_CKDB_CANTOPEN;
  289. }
  290. /* append record */
  291. if ( fseek( fp, 0L, SEEK_END ) < 0 ) {
  292. return DSGW_CKDB_CANTAPPEND;
  293. }
  294. if (( epw = dsgw_MungeString( password )) == NULL ) {
  295. return DSGW_CKDB_CANTAPPEND; /* error msg is close enough */
  296. }
  297. time( &now );
  298. if ( fprintf( fp, "%s:%lu:%s:%s\n", rndstr, lifetime + now, epw, dn )
  299. < 0 ) {
  300. free( epw );
  301. return DSGW_CKDB_CANTAPPEND;
  302. }
  303. fflush( fp );
  304. dsgw_closecookiedb( fp );
  305. fp = dsgw_opencookiedb();
  306. lp = dsgw_getlastpurged( fp );
  307. dsgw_closecookiedb( fp );
  308. if ( lp + DSGW_CKPURGEINTERVAL < now ) {
  309. dsgw_purgedatabase( NULL );
  310. }
  311. #ifdef DSGW_DEBUG
  312. dsgw_log( "dsgw_storecookie: stored %s:%lu:%s:%s\n", rndstr, lifetime + now, epw, dn );
  313. #endif
  314. free( epw );
  315. return 0;
  316. }
  317. /*
  318. * Remove a cookie from the database.
  319. * Format of cookie argument is "nsdsgwauth=cookie-string:escaped-dn"
  320. */
  321. int
  322. dsgw_delcookie( char *cookie )
  323. {
  324. FILE *fp;
  325. char *rndstr, *dn, *dnp, *dbdn, *p;
  326. char buf[ CKBUFSIZ ];
  327. int rc;
  328. long buflen;
  329. /* Parse the given cookie - find the random string */
  330. if (( rndstr = strchr( cookie, '=' )) == NULL ) {
  331. /* malformed cookie */
  332. return -1;
  333. } else {
  334. /* Get the escaped DN */
  335. rndstr++;
  336. if (( dn = strchr( rndstr, ':' )) == NULL ) {
  337. /* malformed cookie */
  338. return -1;
  339. } else {
  340. *dn++ = '\0';
  341. dsgw_form_unescape( dn );
  342. }
  343. }
  344. /*
  345. * Open the cookie database, find the rndstr, make sure the DNs
  346. * match, and delete that entry if found.
  347. */
  348. if (( fp = dsgw_opencookiedb()) == NULL ) {
  349. return -1;
  350. }
  351. fgets( buf, CKBUFSIZ, fp );
  352. if ( strncmp( buf, "lastpurge:", 10 )) {
  353. dsgw_closecookiedb( fp );
  354. return -1;
  355. }
  356. rc = DSGW_CKDB_KEY_NOT_PRESENT;
  357. for (;;) {
  358. if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) {
  359. break;
  360. }
  361. if ( strncmp( buf, rndstr, CKLEN )) {
  362. continue;
  363. }
  364. buflen = strlen( buf );
  365. /* Found the random string - check DN */
  366. if (( dbdn = strrchr( buf, ':' )) == NULL ) {
  367. continue;
  368. } else {
  369. dbdn++;
  370. if ( dbdn[ strlen( dbdn) - 1 ] == '\n' ) {
  371. dbdn[ strlen( dbdn) - 1 ] = '\0';
  372. }
  373. if ( strcmp( dbdn, dn )) {
  374. continue;
  375. } else {
  376. /* Found it. Set the expiration time to zero and obliterate
  377. * the password.
  378. */
  379. p = strchr( buf, ':' );
  380. for ( p++; *p != ':'; p++ ) {
  381. *p = '0'; /* yes, '0', not '\0' */
  382. }
  383. dnp = strrchr( buf, ':' );
  384. for ( p++; p < dnp; p++ ) {
  385. *p = 'x';
  386. }
  387. p++;
  388. fseek( fp, -buflen, SEEK_CUR );
  389. fputs( buf, fp );
  390. fputs( "\n", fp );
  391. fflush( fp );
  392. rc = 0;
  393. }
  394. }
  395. }
  396. dsgw_closecookiedb( fp );
  397. if ( rc == 0 ) {
  398. dsgw_purgedatabase( dn );
  399. }
  400. return rc;
  401. }
  402. /*
  403. * Retrieve the time of the last database purge. Returns zero on error.
  404. * The caller must open and lock the cookie database before calling this
  405. * routine. The file pointer's position in the file is preserved.
  406. */
  407. time_t
  408. dsgw_getlastpurged( FILE *fp )
  409. {
  410. char buf[ CKBUFSIZ ];
  411. char *p;
  412. size_t pos;
  413. time_t ret;
  414. if ( fp == NULL ) {
  415. return (time_t) 0L;
  416. }
  417. pos = ftell( fp );
  418. fseek( fp, 0L, SEEK_SET );
  419. fgets( buf, CKBUFSIZ, fp );
  420. if ( strncmp( buf, "lastpurge:", 10 )) {
  421. ret = (time_t) 0L;
  422. } else {
  423. p = buf + 10;
  424. if ( *p != '\0' ) {
  425. ret = (time_t) atol( p );
  426. } else {
  427. ret = (time_t) 0L;
  428. }
  429. }
  430. fseek( fp, pos, SEEK_SET );
  431. return ret;
  432. }
  433. /*
  434. * Purge the database of any expired entries. Returns the number of
  435. * entries purged, or -1 if an error occurred. If "dn" is non-NULL,
  436. * then this routine will also remove any entries where the DN matches
  437. * "dn".
  438. */
  439. #define DSGW_CK_DEBUG 1
  440. int
  441. dsgw_purgedatabase( char *dn )
  442. {
  443. FILE *fp, *ofp;
  444. time_t now;
  445. char buf[ CKBUFSIZ ];
  446. char *exp;
  447. char expbuf[ 32 ];
  448. char *nbuf;
  449. int purged = 0;
  450. #ifdef _WIN32
  451. int fh;
  452. #endif
  453. size_t osize; /* original size of file */
  454. size_t csize; /* current size of file */
  455. char cdb[MAXPATHLEN]; /*DSGW_COOKIEDB_FNAME + context*/
  456. sprintf(cdb, "%s.%s", DSGW_COOKIEDB_FNAME, context);
  457. if (( fp = dsgw_opencookiedb()) == NULL ) {
  458. return -1;
  459. }
  460. fseek( fp, 0L, SEEK_END );
  461. osize = ftell( fp );
  462. fseek( fp, 0L, SEEK_SET );
  463. if (( ofp = fopen( cdb, "r+" )) == NULL ) {
  464. dsgw_closecookiedb( fp );
  465. return -1;
  466. }
  467. /* re-write the last purge time */
  468. time( &now );
  469. fprintf( ofp, "lastpurge: %-20lu\n", now );
  470. for (;;) {
  471. char *p;
  472. char *dbdn;
  473. int nukeit;
  474. nukeit = 0;
  475. if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) {
  476. break;
  477. }
  478. if ( strncmp( buf, "lastpurge:", 10 ) == 0 ) {
  479. continue;
  480. }
  481. if (( p = strchr( buf, ':' )) == NULL ) {
  482. fclose( ofp );
  483. dsgw_closecookiedb( fp );
  484. return -1;
  485. }
  486. exp = ++p;
  487. if (( p = strchr( exp, ':' )) == NULL ) {
  488. fclose( ofp );
  489. dsgw_closecookiedb( fp );
  490. return -1;
  491. }
  492. strncpy( expbuf, exp, p - exp );
  493. expbuf[ p - exp ] = '\0';
  494. time( &now );
  495. /* Get the entry's DN */
  496. dbdn = strrchr( buf, ':' );
  497. dbdn++;
  498. dbdn = strdup( dbdn );
  499. if ( dbdn[ strlen( dbdn) - 1 ] == '\n' ) {
  500. dbdn[ strlen( dbdn) - 1 ] = '\0';
  501. }
  502. /* Should we delete? */
  503. if ( dn != NULL ) {
  504. if (( dbdn != NULL ) && !strcmp( dn, dbdn )) {
  505. /* Entry's DN is the same as the "dn" parameter - delete */
  506. nukeit = 1;
  507. }
  508. }
  509. free( dbdn );
  510. if ( !nukeit && ( now > atol( expbuf ))) {
  511. /* expired */
  512. nukeit = 1;
  513. }
  514. if ( !nukeit ) {
  515. /* Entry should stay */
  516. fputs( buf, ofp );
  517. } else {
  518. /* Entry should be purged */
  519. purged++;
  520. }
  521. }
  522. /*
  523. * Overwrite the rest of the file so we don't leave passwords
  524. * laying around.
  525. */
  526. csize = ftell( ofp );
  527. nbuf = dsgw_ch_malloc( osize - csize + 2 );
  528. memset( nbuf, 'x', osize - csize + 1 );
  529. nbuf[ osize - csize + 1 ] = '\0';
  530. fputs( nbuf, ofp );
  531. free( nbuf );
  532. #ifdef _WIN32
  533. dsgw_closecookiedb( fp );
  534. fflush( ofp );
  535. fclose( ofp );
  536. fh = open( cdb, _O_RDWR | _O_TEXT );
  537. chsize( fh, csize );
  538. close( fh );
  539. #else /* _WIN32 */
  540. fclose( ofp );
  541. ftruncate( fileno( fp ), csize );
  542. dsgw_closecookiedb( fp );
  543. #endif /* _WIN32 */
  544. return purged;
  545. }
  546. /*
  547. * for debugging - traverse and print the db
  548. */
  549. void
  550. dsgw_traverse_db()
  551. {
  552. FILE *fp;
  553. char *exp;
  554. int total, expired;
  555. time_t now;
  556. char buf[ CKBUFSIZ ];
  557. char expbuf[ 32 ];
  558. total = expired = 0;
  559. if (( fp = dsgw_opencookiedb()) == NULL ) {
  560. fprintf( stderr, "can't open db\n" );
  561. return;
  562. }
  563. if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) {
  564. dsgw_closecookiedb( fp );
  565. printf( "Cookie database is empty (no lastpurge line)\n" );
  566. return;
  567. }
  568. puts( buf );
  569. for (;;) {
  570. char *p;
  571. if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) {
  572. dsgw_closecookiedb( fp );
  573. printf( "%d entries, %d expired\n", total, expired );
  574. return;
  575. }
  576. if (( p = strchr( buf, ':' )) == NULL ) {
  577. dsgw_closecookiedb( fp );
  578. return;
  579. }
  580. exp = ++p;
  581. if (( p = strchr( exp, ':' )) == NULL ) {
  582. dsgw_closecookiedb( fp );
  583. return;
  584. }
  585. printf( "%s", buf );
  586. strncpy( expbuf, exp, p - exp + 1 );
  587. expbuf[ p - exp + 1 ] = '\0';
  588. time( &now );
  589. total++;
  590. if ( now > atol( expbuf )) {
  591. /* not yet expired */
  592. printf( " (expired)\n" );
  593. expired++;
  594. } else {
  595. printf( "\n" );
  596. }
  597. }
  598. }
  599. /*
  600. * Generate a complete authentication cookie header line and store
  601. * the relevant parts iit in the database.
  602. * Return a pointer to the cookie. This routine allocates memory, which
  603. * the caller is responsible for freeing.
  604. * On error, this routine returns NULL and sets err to point to an
  605. * error code.
  606. */
  607. char *
  608. dsgw_mkcookie( char *dn, char *password, time_t lifetime, int *err )
  609. {
  610. char *r;
  611. char *ckbuf;
  612. char *edn;
  613. int rc;
  614. if ( dn == NULL ) {
  615. *err = DSGW_CKDB_NODN;
  616. return NULL;
  617. }
  618. edn = dsgw_strdup_escaped( dn );
  619. if (( r = dsgw_mkrndstr()) == NULL ) {
  620. *err = DSGW_CKDB_RNDSTRFAIL;
  621. return NULL;
  622. }
  623. rc = dsgw_storecookie( r, dn, password, lifetime );
  624. if ( rc != 0 ) {
  625. free( r );
  626. free( edn );
  627. *err = rc;
  628. return NULL;
  629. }
  630. ckbuf = dsgw_ch_malloc( strlen( DSGW_CKHDR ) + strlen( r ) +
  631. strlen( edn ) + strlen( DSGW_AUTHCKNAME ) + 2 + 20 );
  632. ckbuf[ 0 ] = '\0';
  633. strcpy( ckbuf, DSGW_CKHDR );
  634. strcat( ckbuf, DSGW_AUTHCKNAME );
  635. strcat( ckbuf, "=" );
  636. strcat( ckbuf, r );
  637. strcat( ckbuf, ":" );
  638. strcat( ckbuf, edn );
  639. strcat( ckbuf, "; path=/" );
  640. free( r );
  641. free( edn );
  642. return ckbuf;
  643. }
  644. #if 0
  645. /*
  646. * Given a time_t, return a GMTString representation of that time.
  647. */
  648. char *
  649. dsgw_t2gmts( time_t cktime )
  650. {
  651. time_t tnl;
  652. struct tm *pt;
  653. #define TBUFSIZE 40
  654. char tbuf[ TBUFSIZE ];
  655. tnl = time( NULL );
  656. pt = gmtime( &tnl );
  657. (void)strftime( tbuf, (size_t)TBUFSIZE, "%A, %d-%b-%y %T GMT", pt);
  658. return( dsgw_ch_strdup( tbuf ));
  659. }
  660. #endif
  661. /*
  662. * Password obfuscation, etc.
  663. * There is no real security here -- we just encrypt using a hard-coded key.
  664. * The original functions these are based on are called SECMOZ_MungeString()
  665. * and SECMOZ_UnMungeString(). They can be found in ns/lib/libsec/secmoz.c
  666. * (they don't get built as part of the server builds). The only change I
  667. * made was to swap a few of the bytes in the secmoz_tmmdi array and add one
  668. * to all of them. -- Mark Smith <[email protected]>
  669. */
  670. static unsigned char dsgw_tmmdi[] = { /* tmmdi == They Made Me Do It */
  671. 0x87, /* repka, paquin */
  672. 0x9d, /* freier, elgamal */
  673. 0xdf, /* jonm, bobj */
  674. 0xef, /* fur, sharoni */
  675. 0xd1, /* jsw, karlton */
  676. 0xec, /* ari, sk */
  677. 0x3f, /* terry, atotic */
  678. 0xc7 /* jevering, kent */
  679. };
  680. static char *
  681. dsgw_MungeString(const char *unmunged_string)
  682. {
  683. return(dsgw_encDec(CKA_ENCRYPT, unmunged_string));
  684. }
  685. static char *
  686. dsgw_UnMungeString(const char *munged_string)
  687. {
  688. return(dsgw_encDec(CKA_DECRYPT, munged_string));
  689. }
  690. /*
  691. * key import and encryption (using RC4)
  692. */
  693. static char *
  694. dsgw_encDec(CK_ATTRIBUTE_TYPE operation, const char *msg)
  695. {
  696. CK_MECHANISM_TYPE type = CKM_RC4;
  697. PK11SlotInfo *slot = 0;
  698. PK11SymKey *key = 0;
  699. SECItem *params = 0;
  700. PK11Context *context = 0;
  701. unsigned char *output;
  702. unsigned char *input;
  703. char *edStr;
  704. int outLen;
  705. int len;
  706. SECStatus s;
  707. SECItem keyItem = { siBuffer, dsgw_tmmdi, sizeof dsgw_tmmdi };
  708. int noGood = 0;
  709. unsigned int inlen;
  710. if (msg == NULL) {
  711. return NULL;
  712. }
  713. if (*msg == '\0') {
  714. return PL_strdup(msg);
  715. }
  716. if (operation == CKA_DECRYPT) {
  717. input = ATOB_AsciiToData(msg, &inlen);
  718. if (msg == NULL)
  719. return NULL;
  720. } else {
  721. inlen = PL_strlen(msg);
  722. input = (unsigned char *) msg;
  723. }
  724. output = (unsigned char *) malloc(inlen + 65);
  725. if (output == NULL) {
  726. return NULL;
  727. }
  728. /* Initialization */
  729. /*NSS_NoDB_Init(".");*/
  730. dsgw_initNSS();
  731. /*
  732. * Choose a "slot" to use. Slots store keys (either
  733. * temporarily or permanently) and perform
  734. * cryptogrphic operations.
  735. *
  736. * Use the built-in key slot. Another way to choose
  737. * a slot is using PK11_GetBestSlot(), which chooses
  738. * based on the mechanism.
  739. */
  740. slot = PK11_GetInternalKeySlot();
  741. if (!slot)
  742. {
  743. noGood = 1;
  744. goto dsgw_encDec_done;
  745. }
  746. /*
  747. * Get the encryption key. Params may be passed in here,
  748. * but most symmetric key generation requires only the key
  749. * length.
  750. *
  751. * Warning: the key length is in bytes
  752. *
  753. * The key can also be imported (not recommended). See importKey()
  754. * below for example code.
  755. */
  756. /* This code generates a random key
  757. key = PK11_KeyGen(slot, type, 0, 128/8, 0);
  758. if (!key)
  759. {
  760. goto dsgw_encDec_done;
  761. }*/
  762. /* Here we are using a static key. This sucks, but we don't really
  763. * have much of a choice.*/
  764. key = PK11_ImportSymKey(slot, CKM_RC4, PK11_OriginGenerated, operation, &keyItem, 0);
  765. /*
  766. * Some encryption algorithms require parameters. NSS provides
  767. * a generic way to create parameters for any algorithm.
  768. */
  769. params = PK11_GenerateNewParam(type, key);
  770. if (!params)
  771. {
  772. noGood = 1;
  773. goto dsgw_encDec_done;
  774. }
  775. /*if (params->data) printBuffer(params->data, params->len);*/
  776. /*
  777. * Cryptographic operations are performed using a "context"
  778. * Create one for doing encryption using the key and parameters
  779. * generated above.
  780. */
  781. context = PK11_CreateContextBySymKey(type, operation, key, params);
  782. if (!context)
  783. {
  784. noGood = 1;
  785. goto dsgw_encDec_done;
  786. }
  787. /*
  788. * Encrypt the data. In general, the input data should be in multiples
  789. * of the cipher's block size, and the output size will match the input
  790. * size. However, this will not be true for mechanisms that provide
  791. * padding.
  792. */
  793. s = PK11_CipherOp(context, output, &outLen, inlen + 64, input, (int) inlen);
  794. if (s != SECSuccess)
  795. {
  796. noGood = 1;
  797. goto dsgw_encDec_done;
  798. }
  799. /*printBuffer(output, outLen);*/
  800. /*
  801. * When a mechanism that provides padding is used, there may be additional
  802. * data available after the last input data is processed.
  803. *
  804. * NOTE: The type of the length output here is different than in PK11_CipherOp
  805. */
  806. s = PK11_DigestFinal(context, &output[outLen], &len, sizeof output - outLen);
  807. if (s != SECSuccess)
  808. {
  809. noGood = 1;
  810. goto dsgw_encDec_done;
  811. }
  812. /*if (len != 0) printBuffer(&output[outLen], len);*/
  813. outLen += len;
  814. /*
  815. * Terminate the cryptographic operation. Destroying the
  816. * context also performs this function.
  817. */
  818. PK11_Finalize(context);
  819. /*
  820. * Delete the encryption context block, this releases the reference to the key
  821. * and frees the context's copy of the parameters, etc.
  822. *
  823. * The second argument should always be PR_TRUE to free the context structure
  824. * itself, in addition to the contents.
  825. */
  826. PK11_DestroyContext(context, PR_TRUE);
  827. context = 0;
  828. dsgw_encDec_done:
  829. if (context) PK11_DestroyContext(context, PR_TRUE); /* freeit ?? */
  830. if (params) SECITEM_ZfreeItem(params, PR_TRUE);
  831. if (key) PK11_FreeSymKey(key);
  832. if (slot) PK11_FreeSlot(slot);
  833. if (noGood == 1) {
  834. return(NULL);
  835. }
  836. if (operation == CKA_DECRYPT) {
  837. edStr = (char *) output;
  838. edStr[outLen] = '\0';
  839. } else {
  840. edStr = BTOA_DataToAscii(output, outLen);
  841. free(output);
  842. }
  843. return(edStr);
  844. }
  845. void
  846. dsgw_initNSS(void)
  847. {
  848. if (dsgw_NSSInitializedAlready == 1) {
  849. return;
  850. }
  851. if (gc->gc_ldapssl && gc->gc_securitypath != NULL ) {
  852. NSS_Init(gc->gc_securitypath);
  853. } else {
  854. NSS_NoDB_Init(NULL);
  855. }
  856. dsgw_NSSInitializedAlready = 1;
  857. }