diff options
Diffstat (limited to 'ldap/clients/dsgw/cookie.c')
-rw-r--r-- | ldap/clients/dsgw/cookie.c | 990 |
1 files changed, 990 insertions, 0 deletions
diff --git a/ldap/clients/dsgw/cookie.c b/ldap/clients/dsgw/cookie.c new file mode 100644 index 00000000..97c18b0d --- /dev/null +++ b/ldap/clients/dsgw/cookie.c @@ -0,0 +1,990 @@ +/** + * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to + * license terms. Copyright © 2001 Sun Microsystems, Inc. + * Some preexisting portions Copyright © 2001 Netscape Communications Corp. + * All rights reserved. + */ +/* + * cookie.c -- routines to generate and manipulate cookies for dsgw + * + * Copyright (c) 1996 Netscape Communications Corp. + * All rights reserved. + */ + +#include "dsgw.h" + +#include "../../include/portable.h" + +#include <stdio.h> +#if !defined( XP_WIN32 ) +#include <sys/param.h> +#endif + +#include <ssl.h> +#ifdef NSS38_AND_OLDER +#include <secrng.h> +#else +#include "ecl-exp.h" +#endif +#include <nss.h> +#include <base64.h> +#include <sys/types.h> +#include <limits.h> +#include <string.h> + +#ifdef _WIN32 +#include <windows.h> +#include <time.h> +#include <io.h> +#include <fcntl.h> +#include <sys/locking.h> +#else /* _WIN32 */ +#include <unistd.h> +#endif /* _WIN32 */ + +#include <pk11func.h> +#include <pkcs11.h> +#include <pk11pqg.h> + + +static char *dsgw_MungeString(const char *unmunged_string); +static char *dsgw_UnMungeString(const char *munged_string); +static char *dsgw_encDec(CK_ATTRIBUTE_TYPE operation, const char *msg); +void dsgw_initNSS(void); + +static char tokDes[34] = "Communicator Generic Crypto Svcs"; +static char ptokDes[34] = "Internal (Software) Token "; + +int dsgw_NSSInitializedAlready = 0; + +/* Table for converting binary values to and from hexadecimal */ +static char hex[] = "0123456789abcdef"; +#if 0 +static char dec[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 37 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ' ' - '/' */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* '0' - '?' */ + 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '@' - 'O' */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 'P' - '_' */ + 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '`' - 'o' */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 'p' - DEL */ +}; +#endif + + +#define CKLEN 32 +#define RNDBUFLEN ( CKLEN / 2 ) +#define CKBUFSIZ 255 +/* + * Given a buffer buf of length len, return a pointer to a string containing + * the hex-encoded version of buf. The caller is responsible for freeing + * the memory this routine allocates. + */ +static char * +buf2str( unsigned char *buf, int len ) +{ + char *obuf; + int i; + char *p; + + if ( buf == NULL ) { + return NULL; + } + + p = obuf = dsgw_ch_malloc( CKLEN + 1 ); + for ( i = 0; i < len; i++) { + *p++ = hex[( buf[ i ] >> 4 ) & 0xf ]; + *p++ = hex[( buf[ i ]) & 0xf ]; + } + *p++ = '\0'; + return obuf; +} + + + +/* + * Generate a random string of hex-encoded digits, CKLEN characters in + * length. This routine allocates memory which the caller is responsible + * for freeing. + */ +char * +dsgw_mkrndstr() +{ + unsigned char buf[ RNDBUFLEN ]; + + PK11_ConfigurePKCS11(NULL, NULL, tokDes, ptokDes, NULL, NULL, NULL, NULL, 0, 0 ); + /*NSS_NoDB_Init(NULL);*/ + dsgw_initNSS(); + PK11_GenerateRandom(buf, RNDBUFLEN); + return( buf2str( buf, RNDBUFLEN )); +} + + +FILE * +dsgw_opencookiedb() +{ + FILE *fp; + time_t now; + int newfile = 0; + char cdb[MAXPATHLEN]; /*DSGW_COOKIEDB_FNAME + context*/ + +#ifdef XP_WIN32 +#ifndef F_OK +#define F_OK 0 +#endif +#endif + sprintf(cdb, "%s.%s", DSGW_COOKIEDB_FNAME, context); + + if ( access( cdb, F_OK ) == 0 ) { + fp = fopen( cdb, "r+" ); + } else { + newfile = 1; + fp = fopen( cdb, "w" ); + } + if ( fp == NULL ) { + return NULL; + } + /* fseek( fp, 0L, SEEK_SET ); */ +#ifdef XP_WIN32 + (void) chmod( cdb, _S_IREAD | _S_IWRITE ); +#else + (void) chmod( cdb, S_IRUSR | S_IWUSR ); +#endif + + /* acquire a lock */ +#ifdef _WIN32 + while ( _locking( _fileno( fp ), LK_NBLCK, 0xFFFFFFFF ) != 0 ) { +#else +#ifdef USE_LOCKF + while ( lockf( fileno( fp ), F_LOCK, 0 ) != 0 ) { +#else /* _WIN32 */ + while ( flock( fileno( fp ), LOCK_EX ) != 0 ) { +#endif +#endif /* _WIN32 */ + ; /* NULL */ + } + if ( newfile ) { + time( &now ); + fprintf( fp, "lastpurge: %-20lu\n", now ); + fflush( fp ); + fseek( fp, 0L, SEEK_SET ); + } + return fp; +} + + +void +dsgw_closecookiedb( FILE *fp ) +{ +#ifdef _WIN32 + _locking( _fileno( fp ), LK_UNLCK, 0xFFFFFFFF ); +#else /* _WIN32 */ +#ifdef USE_LOCKF + lockf( fileno( fp ), F_ULOCK, 0 ); +#else + flock( fileno( fp ), LOCK_UN ); +#endif +#endif /* _WIN32 */ + fclose( fp ); +} + + + +/* + * Return a pointer to the password associated with the given + * cookie and dn. If the cookie was not found in the database, + * or if the cookie has expired, 1 is returned. On success, 0 is returned + * and ret_pw is set to the password from the database. As a side effect, + * if the database has not been purged of expired entries in more than + * 10 minutes, the database is purged. + * + * As a special case, if the cookie is expired and gc->gc_mode is + * DSGW_MODE_DOMODIFY (that is, the user is saving a modified entry), then + * return 0 if the cookie has been expired for no more than 5 minutes. + * This keeps users from being frustrated by getting an editable view of + * an entry and having the cookie expire while editing. + * The caller is responsible for freeing ret_pw. + */ +int +dsgw_ckdn2passwd( char *rndstr, char *dn, char **ret_pw ) +{ + FILE *fp; + char buf[ CKBUFSIZ ]; + char *p, *pw, *lifetimestr, *cdn; + time_t now; + int expired = 0; + + if ( !strcmp( rndstr, DSGW_UNAUTHSTR )) { + *ret_pw = NULL; + return 0; + } + + if (( fp = dsgw_opencookiedb()) == NULL ) { + return DSGW_CKDB_CANTOPEN; + } + + for (;;) { + if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) { + dsgw_closecookiedb( fp ); +#ifdef DSGW_DEBUG + dsgw_log( "dsgw_ckdn2passwd: cookie <%s> not found in db\n", + rndstr ); +#endif + return DSGW_CKDB_KEY_NOT_PRESENT; + } + +#ifdef DSGW_DEBUG + dsgw_log( "dsgw_ckdn2passwd: retrieved buf from db: <%s>\n", buf ); +#endif + if ( buf[ strlen( buf ) - 1 ] == '\n' ) { + buf[ strlen( buf ) - 1 ] = '\0'; + } + + if ( strncmp( buf, rndstr, strlen( rndstr ))) { + continue; + } + + if (( p = strchr( buf, ':' )) == NULL ) { + dsgw_closecookiedb( fp ); +#ifdef DSGW_DEBUG + dsgw_log( "dsgw_ckdn2passwd: colon 1 missing\n" ); +#endif + return DSGW_CKDB_DBERROR; + } + *p++ = '\0'; + lifetimestr = p; + if (( p = strchr( lifetimestr, ':' )) == NULL ) { + dsgw_closecookiedb( fp ); +#ifdef DSGW_DEBUG + dsgw_log( "dsgw_ckdn2passwd: colon 2 missing\n" ); +#endif + return DSGW_CKDB_DBERROR; + } + *p++ = '\0'; + pw = p; + + if (( p = strchr( pw, ':' )) == NULL ) { + dsgw_closecookiedb( fp ); +#ifdef DSGW_DEBUG + dsgw_log( "dsgw_ckdn2passwd: colon 3 missing\n" ); +#endif + return DSGW_CKDB_DBERROR; + } + *p++ = '\0'; + cdn = p; + + if ( strcmp( dn, cdn )) { + dsgw_closecookiedb( fp ); +#ifdef DSGW_DEBUG + dsgw_log( "dsgw_ckdn2passwd: dn <%s> != cdn <%s>\n", dn, cdn ); +#endif + return DSGW_CKDB_KEY_NOT_PRESENT; + } + + /* expired? */ + time( &now ); + if ( gc->gc_mode == DSGW_MODE_DOMODIFY ) { + if ( now > ( atoi( lifetimestr ) + DSGW_MODIFY_GRACEPERIOD )) { + expired = 1; + } else { +#ifdef DSGW_DEBUG + dsgw_log( "dsgw_ckdn2passwd: cookie expired (%ld > %ld) but within domodify grace period\n", now, atoi( lifetimestr )); +#endif + } + } else if ( now > atoi( lifetimestr )) { + expired = 1; + } + + if ( expired != 0 ) { + dsgw_closecookiedb( fp ); +#ifdef DSGW_DEBUG + dsgw_log( "dsgw_ckdn2passwd: expired (%ld > %ld)\n", now, atoi( lifetimestr )); +#endif + return DSGW_CKDB_EXPIRED; + } + + *ret_pw = dsgw_UnMungeString( pw ); + dsgw_closecookiedb( fp ); + return ( *ret_pw == NULL ) ? 1 : 0; + } +} + + + +/* + * Store the given cookie and password into the database. The cookie + * is marked to expire at the time given by "expires". Returns 0 if + * successful, otherwise returns an error as given in dsgw.h. + * As a side effect, if the database has not been purged of expired + * entries in more than 10 minutes, the database is purged. + * + * Note: DNs are stored unescaped in the cookie database. Passwords + * are stored as "munged" values (encrypted using a hard-coded key and + * then converted to ASCII as described in RFC-1113) to make them a bit + * less obvious and to avoid problems which might arise from embedded ":" + * characters in the password (":" is the field separator in the database). + */ +int +dsgw_storecookie( char *rndstr, char *dn, char *password, time_t lifetime ) +{ + FILE *fp; + char *epw; + time_t now, lp; + + if (( fp = dsgw_opencookiedb()) == NULL ) { + return DSGW_CKDB_CANTOPEN; + } + + /* append record */ + if ( fseek( fp, 0L, SEEK_END ) < 0 ) { + return DSGW_CKDB_CANTAPPEND; + } + if (( epw = dsgw_MungeString( password )) == NULL ) { + return DSGW_CKDB_CANTAPPEND; /* error msg is close enough */ + } + + time( &now ); + if ( fprintf( fp, "%s:%lu:%s:%s\n", rndstr, lifetime + now, epw, dn ) + < 0 ) { + free( epw ); + return DSGW_CKDB_CANTAPPEND; + } + + fflush( fp ); + + dsgw_closecookiedb( fp ); + fp = dsgw_opencookiedb(); + lp = dsgw_getlastpurged( fp ); + dsgw_closecookiedb( fp ); + + if ( lp + DSGW_CKPURGEINTERVAL < now ) { + dsgw_purgedatabase( NULL ); + } +#ifdef DSGW_DEBUG + dsgw_log( "dsgw_storecookie: stored %s:%lu:%s:%s\n", rndstr, lifetime + now, epw, dn ); +#endif + free( epw ); + return 0; +} + + +/* + * Remove a cookie from the database. + * Format of cookie argument is "nsdsgwauth=cookie-string:escaped-dn" + */ +int +dsgw_delcookie( char *cookie ) +{ + FILE *fp; + char *rndstr, *dn, *dnp, *dbdn, *p; + char buf[ CKBUFSIZ ]; + int rc; + long buflen; + + /* Parse the given cookie - find the random string */ + if (( rndstr = strchr( cookie, '=' )) == NULL ) { + /* malformed cookie */ + return -1; + } else { + /* Get the escaped DN */ + rndstr++; + if (( dn = strchr( rndstr, ':' )) == NULL ) { + /* malformed cookie */ + return -1; + } else { + *dn++ = '\0'; + dsgw_form_unescape( dn ); + } + } + + /* + * Open the cookie database, find the rndstr, make sure the DNs + * match, and delete that entry if found. + */ + if (( fp = dsgw_opencookiedb()) == NULL ) { + return -1; + } + fgets( buf, CKBUFSIZ, fp ); + if ( strncmp( buf, "lastpurge:", 10 )) { + dsgw_closecookiedb( fp ); + return -1; + } + rc = DSGW_CKDB_KEY_NOT_PRESENT; + for (;;) { + if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) { + break; + } + if ( strncmp( buf, rndstr, CKLEN )) { + continue; + } + buflen = strlen( buf ); + /* Found the random string - check DN */ + if (( dbdn = strrchr( buf, ':' )) == NULL ) { + continue; + } else { + dbdn++; + if ( dbdn[ strlen( dbdn) - 1 ] == '\n' ) { + dbdn[ strlen( dbdn) - 1 ] = '\0'; + } + if ( strcmp( dbdn, dn )) { + continue; + } else { + /* Found it. Set the expiration time to zero and obliterate + * the password. + */ + p = strchr( buf, ':' ); + for ( p++; *p != ':'; p++ ) { + *p = '0'; /* yes, '0', not '\0' */ + } + dnp = strrchr( buf, ':' ); + for ( p++; p < dnp; p++ ) { + *p = 'x'; + } + p++; + fseek( fp, -buflen, SEEK_CUR ); + fputs( buf, fp ); + fputs( "\n", fp ); + fflush( fp ); + rc = 0; + } + } + } + + dsgw_closecookiedb( fp ); + + if ( rc == 0 ) { + dsgw_purgedatabase( dn ); + } + + return rc; +} + + + + + + +/* + * Retrieve the time of the last database purge. Returns zero on error. + * The caller must open and lock the cookie database before calling this + * routine. The file pointer's position in the file is preserved. + */ +time_t +dsgw_getlastpurged( FILE *fp ) +{ + char buf[ CKBUFSIZ ]; + char *p; + size_t pos; + time_t ret; + + if ( fp == NULL ) { + return (time_t) 0L; + } + + pos = ftell( fp ); + fseek( fp, 0L, SEEK_SET ); + + fgets( buf, CKBUFSIZ, fp ); + if ( strncmp( buf, "lastpurge:", 10 )) { + ret = (time_t) 0L; + } else { + p = buf + 10; + if ( *p != '\0' ) { + ret = (time_t) atol( p ); + } else { + ret = (time_t) 0L; + } + } + fseek( fp, pos, SEEK_SET ); + return ret; +} + + +/* + * Purge the database of any expired entries. Returns the number of + * entries purged, or -1 if an error occurred. If "dn" is non-NULL, + * then this routine will also remove any entries where the DN matches + * "dn". + */ +#define DSGW_CK_DEBUG 1 +int +dsgw_purgedatabase( char *dn ) +{ + FILE *fp, *ofp; + time_t now; + char buf[ CKBUFSIZ ]; + char *exp; + char expbuf[ 32 ]; + char *nbuf; + int purged = 0; +#ifdef _WIN32 + int fh; +#endif + size_t osize; /* original size of file */ + size_t csize; /* current size of file */ + char cdb[MAXPATHLEN]; /*DSGW_COOKIEDB_FNAME + context*/ + + sprintf(cdb, "%s.%s", DSGW_COOKIEDB_FNAME, context); + + if (( fp = dsgw_opencookiedb()) == NULL ) { + return -1; + } + + fseek( fp, 0L, SEEK_END ); + osize = ftell( fp ); + fseek( fp, 0L, SEEK_SET ); + + if (( ofp = fopen( cdb, "r+" )) == NULL ) { + dsgw_closecookiedb( fp ); + return -1; + } + + /* re-write the last purge time */ + time( &now ); + fprintf( ofp, "lastpurge: %-20lu\n", now ); + + for (;;) { + char *p; + char *dbdn; + int nukeit; + + nukeit = 0; + + if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) { + break; + } + if ( strncmp( buf, "lastpurge:", 10 ) == 0 ) { + continue; + } + if (( p = strchr( buf, ':' )) == NULL ) { + fclose( ofp ); + dsgw_closecookiedb( fp ); + return -1; + } + exp = ++p; + if (( p = strchr( exp, ':' )) == NULL ) { + fclose( ofp ); + dsgw_closecookiedb( fp ); + return -1; + } + strncpy( expbuf, exp, p - exp ); + expbuf[ p - exp ] = '\0'; + time( &now ); + + /* Get the entry's DN */ + dbdn = strrchr( buf, ':' ); + dbdn++; + dbdn = strdup( dbdn ); + if ( dbdn[ strlen( dbdn) - 1 ] == '\n' ) { + dbdn[ strlen( dbdn) - 1 ] = '\0'; + } + + /* Should we delete? */ + if ( dn != NULL ) { + if (( dbdn != NULL ) && !strcmp( dn, dbdn )) { + /* Entry's DN is the same as the "dn" parameter - delete */ + nukeit = 1; + } + } + + free( dbdn ); + if ( !nukeit && ( now > atol( expbuf ))) { + /* expired */ + nukeit = 1; + } + + if ( !nukeit ) { + /* Entry should stay */ + fputs( buf, ofp ); + } else { + /* Entry should be purged */ + purged++; + } + } + + /* + * Overwrite the rest of the file so we don't leave passwords + * laying around. + */ + csize = ftell( ofp ); + nbuf = dsgw_ch_malloc( osize - csize + 2 ); + memset( nbuf, 'x', osize - csize + 1 ); + nbuf[ osize - csize + 1 ] = '\0'; + fputs( nbuf, ofp ); + free( nbuf ); +#ifdef _WIN32 + dsgw_closecookiedb( fp ); + fflush( ofp ); + fclose( ofp ); + fh = open( cdb, _O_RDWR | _O_TEXT ); + chsize( fh, csize ); + close( fh ); +#else /* _WIN32 */ + fclose( ofp ); + ftruncate( fileno( fp ), csize ); + dsgw_closecookiedb( fp ); +#endif /* _WIN32 */ + return purged; +} + + + +/* + * for debugging - traverse and print the db + */ +void +dsgw_traverse_db() +{ + FILE *fp; + char *exp; + int total, expired; + time_t now; + char buf[ CKBUFSIZ ]; + char expbuf[ 32 ]; + + total = expired = 0; + + if (( fp = dsgw_opencookiedb()) == NULL ) { + fprintf( stderr, "can't open db\n" ); + return; + } + + if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) { + dsgw_closecookiedb( fp ); + printf( "Cookie database is empty (no lastpurge line)\n" ); + return; + } + puts( buf ); + + for (;;) { + char *p; + if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) { + dsgw_closecookiedb( fp ); + printf( "%d entries, %d expired\n", total, expired ); + return; + } + if (( p = strchr( buf, ':' )) == NULL ) { + dsgw_closecookiedb( fp ); + return; + } + exp = ++p; + if (( p = strchr( exp, ':' )) == NULL ) { + dsgw_closecookiedb( fp ); + return; + } + printf( "%s", buf ); + strncpy( expbuf, exp, p - exp + 1 ); + expbuf[ p - exp + 1 ] = '\0'; + time( &now ); + total++; + if ( now > atol( expbuf )) { + /* not yet expired */ + printf( " (expired)\n" ); + expired++; + } else { + printf( "\n" ); + } + } +} + + + +/* + * Generate a complete authentication cookie header line and store + * the relevant parts iit in the database. + * Return a pointer to the cookie. This routine allocates memory, which + * the caller is responsible for freeing. + * On error, this routine returns NULL and sets err to point to an + * error code. + */ +char * +dsgw_mkcookie( char *dn, char *password, time_t lifetime, int *err ) +{ + char *r; + char *ckbuf; + char *edn; + int rc; + + if ( dn == NULL ) { + *err = DSGW_CKDB_NODN; + return NULL; + } + edn = dsgw_strdup_escaped( dn ); + + if (( r = dsgw_mkrndstr()) == NULL ) { + *err = DSGW_CKDB_RNDSTRFAIL; + return NULL; + } + rc = dsgw_storecookie( r, dn, password, lifetime ); + if ( rc != 0 ) { + free( r ); + free( edn ); + *err = rc; + return NULL; + } + + ckbuf = dsgw_ch_malloc( strlen( DSGW_CKHDR ) + strlen( r ) + + strlen( edn ) + strlen( DSGW_AUTHCKNAME ) + 2 + 20 ); + ckbuf[ 0 ] = '\0'; + strcpy( ckbuf, DSGW_CKHDR ); + strcat( ckbuf, DSGW_AUTHCKNAME ); + strcat( ckbuf, "=" ); + strcat( ckbuf, r ); + strcat( ckbuf, ":" ); + strcat( ckbuf, edn ); + strcat( ckbuf, "; path=/" ); + + free( r ); + free( edn ); + return ckbuf; +} + + + +#if 0 +/* + * Given a time_t, return a GMTString representation of that time. + */ +char * +dsgw_t2gmts( time_t cktime ) +{ + time_t tnl; + struct tm *pt; +#define TBUFSIZE 40 + char tbuf[ TBUFSIZE ]; + + tnl = time( NULL ); + pt = gmtime( &tnl ); + (void)strftime( tbuf, (size_t)TBUFSIZE, "%A, %d-%b-%y %T GMT", pt); + return( dsgw_ch_strdup( tbuf )); +} +#endif + + +/* + * Password obfuscation, etc. + * There is no real security here -- we just encrypt using a hard-coded key. + * The original functions these are based on are called SECMOZ_MungeString() + * and SECMOZ_UnMungeString(). They can be found in ns/lib/libsec/secmoz.c + * (they don't get built as part of the server builds). The only change I + * made was to swap a few of the bytes in the secmoz_tmmdi array and add one + * to all of them. -- Mark Smith <mcs@netscape.com> + */ + +static unsigned char dsgw_tmmdi[] = { /* tmmdi == They Made Me Do It */ + 0x87, /* repka, paquin */ + 0x9d, /* freier, elgamal */ + 0xdf, /* jonm, bobj */ + 0xef, /* fur, sharoni */ + 0xd1, /* jsw, karlton */ + 0xec, /* ari, sk */ + 0x3f, /* terry, atotic */ + 0xc7 /* jevering, kent */ +}; + +static char * +dsgw_MungeString(const char *unmunged_string) +{ + return(dsgw_encDec(CKA_ENCRYPT, unmunged_string)); +} +static char * +dsgw_UnMungeString(const char *munged_string) +{ + return(dsgw_encDec(CKA_DECRYPT, munged_string)); +} + +/* + * key import and encryption (using RC4) + */ +static char * +dsgw_encDec(CK_ATTRIBUTE_TYPE operation, const char *msg) +{ + CK_MECHANISM_TYPE type = CKM_RC4; + PK11SlotInfo *slot = 0; + PK11SymKey *key = 0; + SECItem *params = 0; + PK11Context *context = 0; + unsigned char *output; + unsigned char *input; + char *edStr; + int outLen; + int len; + SECStatus s; + SECItem keyItem = { siBuffer, dsgw_tmmdi, sizeof dsgw_tmmdi }; + int noGood = 0; + unsigned int inlen; + FILE *pptr; + int i; + + if (msg == NULL) { + return NULL; + } + + if (*msg == '\0') { + return PL_strdup(msg); + } + + if (operation == CKA_DECRYPT) { + input = ATOB_AsciiToData(msg, &inlen); + if (msg == NULL) + return NULL; + } else { + inlen = PL_strlen(msg); + input = (unsigned char *) msg; + } + + output = (unsigned char *) malloc(inlen + 65); + if (output == NULL) { + return NULL; + } + + /* Initialization */ + /*NSS_NoDB_Init(".");*/ + dsgw_initNSS(); + + /* + * Choose a "slot" to use. Slots store keys (either + * temporarily or permanently) and perform + * cryptogrphic operations. + * + * Use the built-in key slot. Another way to choose + * a slot is using PK11_GetBestSlot(), which chooses + * based on the mechanism. + */ + slot = PK11_GetInternalKeySlot(); + if (!slot) + { + noGood = 1; + goto dsgw_encDec_done; + } + + /* + * Get the encryption key. Params may be passed in here, + * but most symmetric key generation requires only the key + * length. + * + * Warning: the key length is in bytes + * + * The key can also be imported (not recommended). See importKey() + * below for example code. + */ + /* This code generates a random key + key = PK11_KeyGen(slot, type, 0, 128/8, 0); + if (!key) + { + goto dsgw_encDec_done; + }*/ + /* Here we are using a static key. This sucks, but we don't really + * have much of a choice.*/ + key = PK11_ImportSymKey(slot, CKM_RC4, PK11_OriginGenerated, operation, &keyItem, 0); + + /* + * Some encryption algorithms require parameters. NSS provides + * a generic way to create parameters for any algorithm. + */ + params = PK11_GenerateNewParam(type, key); + if (!params) + { + noGood = 1; + goto dsgw_encDec_done; + } + + /*if (params->data) printBuffer(params->data, params->len);*/ + + /* + * Cryptographic operations are performed using a "context" + * Create one for doing encryption using the key and parameters + * generated above. + */ + context = PK11_CreateContextBySymKey(type, operation, key, params); + if (!context) + { + noGood = 1; + goto dsgw_encDec_done; + } + + /* + * Encrypt the data. In general, the input data should be in multiples + * of the cipher's block size, and the output size will match the input + * size. However, this will not be true for mechanisms that provide + * padding. + */ + s = PK11_CipherOp(context, output, &outLen, inlen + 64, input, (int) inlen); + if (s != SECSuccess) + { + noGood = 1; + goto dsgw_encDec_done; + } + + /*printBuffer(output, outLen);*/ + + /* + * When a mechanism that provides padding is used, there may be additional + * data available after the last input data is processed. + * + * NOTE: The type of the length output here is different than in PK11_CipherOp + */ + s = PK11_DigestFinal(context, &output[outLen], &len, sizeof output - outLen); + if (s != SECSuccess) + { + noGood = 1; + goto dsgw_encDec_done; + } + + /*if (len != 0) printBuffer(&output[outLen], len);*/ + + outLen += len; + + /* + * Terminate the cryptographic operation. Destroying the + * context also performs this function. + */ + PK11_Finalize(context); + + /* + * Delete the encryption context block, this releases the reference to the key + * and frees the context's copy of the parameters, etc. + * + * The second argument should always be PR_TRUE to free the context structure + * itself, in addition to the contents. + */ + PK11_DestroyContext(context, PR_TRUE); + context = 0; + +dsgw_encDec_done: + if (context) PK11_DestroyContext(context, PR_TRUE); /* freeit ?? */ + if (params) SECITEM_ZfreeItem(params, PR_TRUE); + if (key) PK11_FreeSymKey(key); + if (slot) PK11_FreeSlot(slot); + + if (noGood == 1) { + return(NULL); + } + + if (operation == CKA_DECRYPT) { + edStr = (char *) output; + edStr[outLen] = '\0'; + } else { + edStr = BTOA_DataToAscii(output, outLen); + free(output); + } + + return(edStr); +} + + +void +dsgw_initNSS(void) +{ + if (dsgw_NSSInitializedAlready == 1) { + return; + } + + if (gc->gc_ldapssl && gc->gc_securitypath != NULL ) { + NSS_Init(gc->gc_securitypath); + } else { + NSS_NoDB_Init(NULL); + } + dsgw_NSSInitializedAlready = 1; +} |