diff options
| author | Sam Varshavchik | 2013-08-19 16:39:41 -0400 | 
|---|---|---|
| committer | Sam Varshavchik | 2013-08-25 14:43:51 -0400 | 
| commit | 9c45d9ad13fdf439d44d7443ae75da15ea0223ed (patch) | |
| tree | 7a81a04cb51efb078ee350859a64be2ebc6b8813 /tcpd/tlspasswordcache.c | |
| parent | a9520698b770168d1f33d6301463bb70a19655ec (diff) | |
| download | courier-libs-9c45d9ad13fdf439d44d7443ae75da15ea0223ed.tar.bz2 | |
Initial checkin
Imported from subversion report, converted to git. Updated all paths in
scripts and makefiles, reflecting the new directory hierarchy.
Diffstat (limited to 'tcpd/tlspasswordcache.c')
| -rw-r--r-- | tcpd/tlspasswordcache.c | 954 | 
1 files changed, 954 insertions, 0 deletions
| diff --git a/tcpd/tlspasswordcache.c b/tcpd/tlspasswordcache.c new file mode 100644 index 0000000..5f3ca2b --- /dev/null +++ b/tcpd/tlspasswordcache.c @@ -0,0 +1,954 @@ +/* +** Copyright 2003-2007 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#include "config.h" +#include "tlspasswordcache.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <md5/md5.h> + +#define PASSFILEFORMAT 1 + +#if HAVE_OPENSSL097 +#include <openssl/ssl.h> +#include <openssl/err.h> +#include <openssl/rand.h> + +static void sslerror(EVP_CIPHER_CTX *ctx, const char *pfix) +{ +        char errmsg[256]; +        int errnum=ERR_get_error(); +  +        ERR_error_string_n(errnum, errmsg, sizeof(errmsg)-1); + +	fprintf(stderr, "%s: %s\n", pfix, errmsg); +} + + +#endif + +#if HAVE_GCRYPT + +#include <gcrypt.h> + +#define RAND_pseudo_bytes(a,b) (gcry_create_nonce((a),(b)), 0) + +typedef struct { +	enum gcry_cipher_algos algo; +	enum gcry_cipher_modes mode; +} EVP_CIPHER; + +#define EVP_MAX_IV_LENGTH 256 + +const EVP_CIPHER *EVP_des_cbc() +{ +	static const EVP_CIPHER des_cbc={GCRY_CIPHER_DES, +					 GCRY_CIPHER_MODE_CBC}; + +	return &des_cbc; +} + +typedef struct { +	const EVP_CIPHER *cipher; +	gcry_error_t err; +	gcry_cipher_hd_t handle; + +	int padding; +	char *blkbuf; +	size_t blksize; + +	size_t blkptr; + +} EVP_CIPHER_CTX; + +static void sslerror(EVP_CIPHER_CTX *ctx, const char *pfix) +{ +	fprintf(stderr, "%s: %s\n", pfix, gcry_strerror(ctx->err)); +} + +static void EVP_CIPHER_CTX_init(EVP_CIPHER_CTX *ctx) +{ +	memset(ctx, 0, sizeof(*ctx)); +} + +static void EVP_CIPHER_CTX_cleanup(EVP_CIPHER_CTX *ctx) +{ +	if (ctx->handle) +	{ +		gcry_cipher_close(ctx->handle); +		ctx->handle=NULL; +	} + +	if (ctx->blkbuf) +	{ +		free(ctx->blkbuf); +		ctx->blkbuf=NULL; +	} +} + +static int EVP_CIPHER_iv_length(const EVP_CIPHER *cipher) +{ +	size_t l=0; + +	gcry_cipher_algo_info(cipher->algo, GCRYCTL_GET_BLKLEN, NULL, &l); +	return l; +} + +static int EVP_CIPHER_key_length(const EVP_CIPHER *cipher) +{ +	size_t l=0; + +	gcry_cipher_algo_info(cipher->algo, GCRYCTL_GET_KEYLEN, NULL, &l); +	return l; +} + +static int EVP_EncryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *cipher, +			      void *impl, unsigned char *key, unsigned char *iv) +{ +	EVP_CIPHER_CTX_cleanup(ctx); +	ctx->cipher=cipher; +	ctx->err=gcry_cipher_open(&ctx->handle, +				  cipher->algo, +				  cipher->mode, 0); + +	if (!ctx->err) +		ctx->err=gcry_cipher_setkey(ctx->handle, key, +					    EVP_CIPHER_key_length(cipher)); + +	if (!ctx->err) +		ctx->err=gcry_cipher_setiv(ctx->handle, iv, +					   (ctx->blksize= +					    EVP_CIPHER_iv_length(cipher))); + +	if (!ctx->err) +		if ((ctx->blkbuf=malloc(ctx->blksize)) == NULL) +			ctx->err=gpg_err_code_from_errno(errno); + +	ctx->blkptr=0; +	ctx->padding=1; + +	return ctx->err == 0; +} + +static int EVP_EncryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, +			     int *outl, unsigned char *in, int inl) +{ +	*outl=0; + +	while (inl > 0) +	{ +		size_t cp= (size_t)inl < (ctx->blksize - ctx->blkptr) +			? (size_t)inl:(ctx->blksize - ctx->blkptr); + +		if (ctx->blkptr == 0 && inl > ctx->blksize*2) +		{ +			cp=(inl / ctx->blksize - 1) * ctx->blksize; + +			if ((ctx->err=gcry_cipher_encrypt(ctx->handle, +							  out, cp, +							  in, cp)) +			    != 0) +				return 0; + +			out += cp; +			*outl += cp; +			in += cp; +			inl -= cp; +			continue; +		} + +		memcpy(ctx->blkbuf + ctx->blkptr, in, cp); + +		in += cp; +		inl -= cp; + +		ctx->blkptr += cp; + +		if (ctx->blkptr == ctx->blksize) +		{ +			if ((ctx->err=gcry_cipher_encrypt(ctx->handle, +							  out, ctx->blksize, +							  ctx->blkbuf, +							  ctx->blksize)) != 0) +				return 0; +			out += ctx->blksize; +			*outl += ctx->blksize; +			ctx->blkptr=0; +		} +	} +	return 1; +} + +static int EVP_EncryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *out, +			       int *outl) +{ +	if (ctx->padding) +	{ +		unsigned char pad=ctx->blksize - ctx->blkptr; + +		*outl=0; + +		if (pad == 0) +			pad=ctx->blksize; + +		do +		{ +			int n_outl; + +			if (!EVP_EncryptUpdate(ctx, out, &n_outl, &pad, 1)) +				return 0; +				 +			out += n_outl; +			*outl += n_outl; +		} +		while (ctx->blkptr); +	} +	else if (ctx->blksize != ctx->blkptr) +	{ +		ctx->err=GPG_ERR_BAD_DATA; +		return 0; +	} + +	return 1; +} + +static int EVP_DecryptInit_ex(EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, +			      void *impl, unsigned char *key, +			      unsigned char *iv) +{ +	return EVP_EncryptInit_ex(ctx, type, impl, key, iv); +} + +static int EVP_DecryptUpdate(EVP_CIPHER_CTX *ctx, unsigned char *out, +			     int *outl, unsigned char *in, int inl) +{ +	*outl=0; + +	while (inl > 0) +	{ +		size_t cp; + +		if (ctx->blkptr == 0 && inl > ctx->blksize * 3) +		{ +			cp=(inl / ctx->blksize - 2) * ctx->blksize; + +			if ((ctx->err=gcry_cipher_decrypt(ctx->handle, +							  out, cp, +							  in, cp)) +			    != 0) +				return 0; + +			out += cp; +			*outl += cp; +			in += cp; +			inl -= cp; +			continue; +		} + +		if (ctx->blkptr == ctx->blksize) +		{ +			if ((ctx->err=gcry_cipher_decrypt(ctx->handle, +							  out, ctx->blksize, +							  ctx->blkbuf, +							  ctx->blksize)) != 0) +				return 0; +			out += ctx->blksize; +			*outl += ctx->blksize; +			ctx->blkptr=0; +		} + +		cp= (size_t)inl < (ctx->blksize - ctx->blkptr) +			? (size_t)inl:(ctx->blksize - ctx->blkptr); + +		memcpy(ctx->blkbuf + ctx->blkptr, in, cp); + +		in += cp; +		inl -= cp; + +		ctx->blkptr += cp; + +	} +	return 1; +} + +static int EVP_DecryptFinal_ex(EVP_CIPHER_CTX *ctx, unsigned char *outm, +			       int *outl) +{ +	unsigned char lastval; +	int cnt; + +	if (ctx->blkptr != ctx->blksize) +	{ +		ctx->err=GPG_ERR_BAD_DATA; +		return 0; +	} + +	if ((ctx->err=gcry_cipher_decrypt(ctx->handle, +					  ctx->blkbuf, +					  ctx->blksize, +					  NULL, 0)) != 0) +		return 0; + +	if (ctx->padding) +	{ +		lastval=ctx->blkbuf[ctx->blksize-1]; + +		if (lastval > 0 && lastval <= ctx->blksize) +		{ +			char n; + +			for (n=0; n<lastval; n++) +				if (ctx->blkbuf[ctx->blksize-1-n] != lastval) +					lastval=0; +		} +		else +			lastval=0; + +		if (!lastval) +		{ +			ctx->err=GPG_ERR_BAD_DATA; +			return 0; +		} +	} +	else +	{ +		lastval=0; +	} + +	cnt=ctx->blksize-lastval; +	if (cnt) +		memcpy(outm, ctx->blkbuf, cnt); +	*outl=cnt; +	return 1; +} + + +#define HAVE_OPENSSL097 1 +#endif + +#if HAVE_OPENSSL097 + +#if BUFSIZ < 8192 +#undef BUFSIZ +#define BUFSIZ 8192 +#endif + +int tlspassword_init() +{ +	return 1; +} + +static int save_string(EVP_CIPHER_CTX *, +		       const char *, char *, +		       int (*)(const char *, size_t, void *), +		       void *); + +int tlspassword_save( const char * const *urls, +		      const char * const *pwds, +		      const char *mpw, +		      int (*writefunc)(const char *, size_t, void *), +		      void *writefuncarg) +{ +	char buf[BUFSIZ]; +	char *p; +	int l; +	int wl; + +	unsigned char iv1_buf[16]; +	unsigned char iv2_buf[16]; +	MD5_DIGEST md5_password; +	int iv_len, key_len; +	EVP_CIPHER_CTX ctx; +	const EVP_CIPHER *des=EVP_des_cbc(); + +	md5_digest(mpw, strlen(mpw), md5_password); + +	EVP_CIPHER_CTX_init(&ctx); +	iv_len=EVP_CIPHER_iv_length(des); +	key_len=EVP_CIPHER_key_length(des); + +	if (RAND_pseudo_bytes(iv1_buf, sizeof(iv1_buf)) < 0 || +	    RAND_pseudo_bytes(iv2_buf, sizeof(iv2_buf)) < 0) +	{ +		fprintf(stderr, +			"tlspassword_save: internal error - " +			"RAND_pseudo_bytes() failed.\n"); +		EVP_CIPHER_CTX_cleanup(&ctx); +		errno=EIO; +		return -1; +	} + +	if (iv_len + key_len > sizeof(iv1_buf) +	    || iv_len + key_len != sizeof(iv2_buf) +	    || key_len != sizeof(md5_password)/2) +	{ +		fprintf(stderr, +			"tlspassword_save: internal error - " +			"unexpected key sizes.\n"); +		EVP_CIPHER_CTX_cleanup(&ctx); +		errno=EIO; +		return -1; +	} + +	p=buf+3; + +	if (!EVP_EncryptInit_ex(&ctx, des, NULL, +				(unsigned char *)md5_password, +				iv1_buf) || +	    !EVP_EncryptUpdate(&ctx, (unsigned char *)p, &l, +			       (unsigned char *)md5_password + key_len, +			       sizeof(md5_password)-key_len) || +	    !EVP_EncryptUpdate(&ctx, (unsigned char *)(p += l), &l, +			       iv2_buf, +			       iv_len + key_len) || +	    !EVP_EncryptFinal_ex(&ctx, (unsigned char *)(p += l), &l)) + +	{ +		sslerror(&ctx, "EVP_EncryptInit_ex"); +		EVP_CIPHER_CTX_cleanup(&ctx); +		errno=EIO; +		return -1; +	} + +	p += l; + +	wl= p - buf - 3; + +	buf[0]=PASSFILEFORMAT; +	buf[1]= wl / 256; +	buf[2]= wl % 256; + +	l=(*writefunc)(buf, 3, writefuncarg); + +	if (l == 0) +		l=(*writefunc)((const char *)iv1_buf, iv_len, writefuncarg); + +	if (l == 0) +		l=(*writefunc)(buf+3, wl, writefuncarg); + +	if (l) +		return l; + +#if 0 +	{ +		int i; + +		printf("KEY: "); + +		for (i=0; i<key_len + iv_len; i++) +			printf("%02X", (int)(unsigned char)iv2_buf[i]); +		printf("\n"); +	} +#endif + +	if (!EVP_EncryptInit_ex(&ctx, des, NULL, +				(unsigned char *)&iv2_buf, +				(unsigned char *)&iv2_buf + key_len)) +	{ +		sslerror(&ctx, "EVP_EncryptInit_ex"); +		EVP_CIPHER_CTX_cleanup(&ctx); +		errno=EIO; +		return -1; +	} + +	for (l=0; urls[l]; l++) +	{ +		int n=save_string(&ctx, urls[l], buf, writefunc, writefuncarg); + +		if (n) +			return n; + +		n=save_string(&ctx, pwds[l], buf, writefunc, writefuncarg); + +		if (n) +			return n; +	} + +	if (!EVP_EncryptFinal_ex(&ctx, (unsigned char *)buf, &l)) +	{ +		sslerror(&ctx, "EVP_EncryptInit_ex"); +		EVP_CIPHER_CTX_cleanup(&ctx); +		errno=EIO; +		return -1; +	} + +	if (l) +		l=(*writefunc)(buf, l, writefuncarg); + +	EVP_CIPHER_CTX_cleanup(&ctx); +	return l; +} + +static int save_string(EVP_CIPHER_CTX *ctx, +		       const char *str, char *buf, +		       int (*writefunc)(const char *, size_t, void *), +		       void *writefuncarg) +{ +	int l; +	size_t len=strlen(str); +	unsigned char b[2]; + +	if (len >= 256 * 256) +	{ +		fprintf(stderr, +			"tlspassword_save: internal error - " +			"key sizes too large.\n"); +		errno=EINVAL; +		return -1; +	} + +	b[0]=len / 256; +	b[1]=len % 256; + +	if (!EVP_EncryptUpdate(ctx, (unsigned char *)buf, &l, b, 2)) +	{ +		sslerror(ctx, "EVP_EncryptUpdate"); +		return -1; +	} + +	if (l) +	{ +		l=(*writefunc)(buf, l, writefuncarg); + +		if (l) +			return l; +	} + +	while (len) +	{ +		size_t n=len; + +		if (n > BUFSIZ / 4) +			n=BUFSIZ/4; + +		if (!EVP_EncryptUpdate(ctx, (unsigned char *)buf, &l, +				       (unsigned char *)str, n)) +		{ +			sslerror(ctx, "EVP_EncryptUpdate"); +			return -1; +		} + +		if (l) +		{ +			l=(*writefunc)(buf, l, writefuncarg); + +			if (l) +				return l; +		} + +		str += n; +		len -= n; +	} + +	return 0; +} + +struct tempstring_list { +	struct tempstring_list *next; +	char *url; +	char *pw; +}; + +struct tlspassword_readinfo { +	char buf[BUFSIZ / 2]; +	char *bufptr; +	size_t bufleft; + +	int (*readfunc)(char *, size_t, void *); +	void *readfuncarg; + +	struct tempstring_list *tl_list, *tl_last; + +	int (*readhandler)(struct tlspassword_readinfo *, char *, int); + +	unsigned int stringhi; +	char *stringptr; +	size_t stringleft; +	size_t nstrings; +}; + + +static int tlspassword_read(struct tlspassword_readinfo *p, +			    char *buf, +			    size_t nbytes) +{ +	while (nbytes) +	{ +		size_t c; + +		if (p->bufleft == 0) +		{ +			int n= (*p->readfunc)(p->buf, sizeof(p->buf), +					      p->readfuncarg); + +			if (n <= 0) +				return -1; +			p->bufptr=p->buf; +			p->bufleft=n; +		} + +		c=nbytes; + +		if (c > p->bufleft) +			c=p->bufleft; + +		memcpy(buf, p->bufptr, c); +		p->bufptr += c; +		p->bufleft -= c; +		nbytes -= c; +	} + +	return 0; +} + +static void tlspassword_readcleanup(struct tlspassword_readinfo *p) +{ +	while (p->tl_list) +	{ +		struct tempstring_list *t=p->tl_list; + +		p->tl_list=t->next; +		if (t->url) +			free(t->url); +		if (t->pw) +			free(t->pw); +		free(t); +	} +} + +static int read_stringhi(struct tlspassword_readinfo *, char *, int); + +int tlspassword_load( int (*callback)(char *, size_t, void *), +		      void *callback_arg, + +		      const char *mpw, + +		      void (*readfunc)(const char * const *, +				       const char * const *, +				       void *), +		      void *readfunc_arg) +{ +	char buf[BUFSIZ]; +	int outl; +	char *p; + +	MD5_DIGEST md5_password; +	int iv_len, key_len; +	EVP_CIPHER_CTX ctx; +	const EVP_CIPHER *des=EVP_des_cbc(); +	struct tlspassword_readinfo readinfo; +	char header[3]; +	size_t l; +	char iv1_buf[EVP_MAX_IV_LENGTH]; +	struct tempstring_list *tl; +	const char **urls, **pws; + +	readinfo.bufleft=0; +	readinfo.readfunc=callback; +	readinfo.readfuncarg=callback_arg; +	readinfo.tl_list=NULL; +	readinfo.tl_last=NULL; + +	md5_digest(mpw, strlen(mpw), md5_password); + +	EVP_CIPHER_CTX_init(&ctx); +	iv_len=EVP_CIPHER_iv_length(des); +	key_len=EVP_CIPHER_key_length(des); + +	if (tlspassword_read(&readinfo, header, 3) || +	    tlspassword_read(&readinfo, iv1_buf, iv_len)) +	{ +		EVP_CIPHER_CTX_cleanup(&ctx); +		return -1; +	} +	if (header[0] != PASSFILEFORMAT) +	{ +		errno=EINVAL; +		EVP_CIPHER_CTX_cleanup(&ctx); +		return -1; +	} + +	if ((l=(size_t)(unsigned char)header[1] * 256 +	     + (unsigned char)header[2]) > sizeof(buf) / 4) +	{ +		errno=EINVAL; +		EVP_CIPHER_CTX_cleanup(&ctx); +		return -1; +	} + +	if (tlspassword_read(&readinfo, buf, l)) +		return -1; + +	p=buf + sizeof(buf)/2; +	if (!EVP_DecryptInit_ex(&ctx, des, NULL, +				(unsigned char *)md5_password, +				(unsigned char *)&iv1_buf) || +	    !EVP_DecryptUpdate(&ctx, (unsigned char *)p, &outl, +			       (unsigned char *)buf, l) || +	    !EVP_DecryptFinal_ex(&ctx, (unsigned char *)(p += outl), &outl)) +	{ +		errno=EINVAL; +		EVP_CIPHER_CTX_cleanup(&ctx); +		return -1; +	} + +	p += outl; + +	if (p - (buf +sizeof(buf)/2) != sizeof(md5_password) + iv_len +	    || memcmp(buf + sizeof(buf)/2, (char *)(&md5_password) + key_len, +		      sizeof(md5_password)-key_len)) +	{ +		errno=EINVAL; +		EVP_CIPHER_CTX_cleanup(&ctx); +		return -1; +	} + +#if 0 +	{ +		int i; + +		printf("KEY: "); + +		for (i=0; i<key_len + iv_len; i++) +			printf("%02X", (int)(unsigned char)(p-iv_len-key_len)[i]); +		printf("\n"); +	} +#endif + +	if (!EVP_DecryptInit_ex(&ctx, des, NULL, +				(unsigned char *)(p-iv_len-key_len), +				(unsigned char *)(p-iv_len))) +	{ +		errno=EINVAL; +		EVP_CIPHER_CTX_cleanup(&ctx); +		return -1; +	} + +	readinfo.nstrings=0; +	readinfo.readhandler= &read_stringhi; +	for (;;) +	{ +		if (readinfo.bufleft == 0) +		{ +			outl= (*readinfo.readfunc)(readinfo.buf, +						   sizeof(readinfo.buf), +						   readinfo.readfuncarg); + +			if (outl == 0) +				break; + +			if (outl < 0) +			{ +				tlspassword_readcleanup(&readinfo); +				errno=EINVAL; +				EVP_CIPHER_CTX_cleanup(&ctx); +				return -1; +			} + +			readinfo.bufptr=readinfo.buf; +			readinfo.bufleft=outl; +		} + +		if (!EVP_DecryptUpdate(&ctx, (unsigned char *)buf, &outl, +				       (unsigned char *) +				       readinfo.bufptr, readinfo.bufleft)) +		{ +			tlspassword_readcleanup(&readinfo); +			errno=EINVAL; +			EVP_CIPHER_CTX_cleanup(&ctx); +			return -1; +		} +		readinfo.bufleft=0; + +		p=buf; +		while (outl) +		{ +			int n= (*readinfo.readhandler)(&readinfo, p, outl); + +			if (n < 0) +			{ +				tlspassword_readcleanup(&readinfo); +				EVP_CIPHER_CTX_cleanup(&ctx); +				return -1; +			} + +			p += n; +			outl -= n; +		} +	} + +	if (!EVP_DecryptFinal_ex(&ctx, (unsigned char *)buf, &outl)) +	{ +		tlspassword_readcleanup(&readinfo); +		errno=EINVAL; +		EVP_CIPHER_CTX_cleanup(&ctx); +		return -1; +	} + +	p=buf; +	while (outl) +	{ +		int n= (*readinfo.readhandler)(&readinfo, p, outl); + +		if (n < 0) +		{ +			tlspassword_readcleanup(&readinfo); +			errno=EINVAL; +			EVP_CIPHER_CTX_cleanup(&ctx); +			return -1; +		} + +		p += n; +		outl -= n; +	} + +	if (readinfo.tl_list && readinfo.tl_list->pw == NULL) +		/* Odd # of strings -- no good */ +	{ +		tlspassword_readcleanup(&readinfo); +		errno=EINVAL; +		EVP_CIPHER_CTX_cleanup(&ctx); +		return (-1); +	} + +	if ((urls=malloc((readinfo.nstrings+1) * sizeof(char *))) == NULL || +	    (pws=malloc((readinfo.nstrings+1) * sizeof(char *))) == NULL) +	{ +		if (urls) +			free(urls); + +		tlspassword_readcleanup(&readinfo); +		EVP_CIPHER_CTX_cleanup(&ctx); +		return (-1); +	} + +	l=0; +	for (tl=readinfo.tl_list; tl; tl=tl->next) +	{ +		urls[l]=tl->url; +		pws[l]=tl->pw; +		l++; +	} + +	urls[l]=NULL; +	pws[l]=NULL; + +	(*readfunc)(urls, pws, readfunc_arg); + +	free(urls); +	free(pws); + +	tlspassword_readcleanup(&readinfo); +	EVP_CIPHER_CTX_cleanup(&ctx); +	return 0; +} + +static int read_stringlo(struct tlspassword_readinfo *info, +			 char *p, int n); + +static int read_string(struct tlspassword_readinfo *info, +		       char *p, int n); + +static int read_stringhi(struct tlspassword_readinfo *info, +			 char *p, int n) +{ +	info->stringhi=(unsigned char)*p; +	info->stringhi *= 256; + +	info->readhandler=read_stringlo; +	return 1; +} + +static int read_stringlo(struct tlspassword_readinfo *info, +			 char *p, int n) +{ +	struct tempstring_list *t; + +	info->readhandler=read_string; +	info->stringleft=info->stringhi + (unsigned char)*p; + +	if (info->tl_last && +	    info->tl_last->pw == NULL) /* This string is the pw */ +	{ +		info->tl_last->pw=malloc(info->stringleft+1); +		if (!info->tl_last->pw) +			return -1; + +		info->stringptr=info->tl_last->pw; +		return 1; +	} + +	if ((t=(struct tempstring_list *)malloc(sizeof(struct tempstring_list)) +	     ) == NULL || (t->url=malloc(info->stringleft+1)) == NULL) +	{ +		if (t) free(t); +		return -1; +	} + +	if (info->tl_last) +		info->tl_last->next=t; +	else +		info->tl_list=t; +	info->tl_last=t; +	info->stringptr=t->url; +	t->next=NULL; +	t->pw=NULL; +	++info->nstrings; +	return 1; +} + +static int read_string(struct tlspassword_readinfo *info, char *p, int n) +{ +	if (n > info->stringleft) +		n=info->stringleft; + +	memcpy(info->stringptr, p, n); +	info->stringptr += n; +	info->stringleft -= n; + +	if (info->stringleft == 0) +	{ +		info->readhandler=read_stringhi; +		*info->stringptr=0; +	} + +	return n; +} + +#else + + +int tlspassword_init() +{ +	return 0; +} + + +int tlspassword_save( const char * const *urls, +		      const char * const *pwds, +		      const char *mpw, +		      int (*writefunc)(const char *, size_t, void *), +		      void *writefuncarg) +{ +	errno=EIO; +	return -1; +} + +int tlspassword_load( int (*readfunc)(char *, size_t, void *), +		      void *readfuncarg, + +		      const char *mpw, +		      void (*callback)(const char * const *, +				       const char * const *, +				       void *), +		      void *callback_arg) +{ +	errno=EIO; +	return -1; +} +#endif | 
