cookie.c 24 KB

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