redo 1.1 -> 1.2. on RAND_file_name(), return /dev/urandom by default.

RAND_{load,write}_file() takes care of device file case.  from openbsd.
This commit is contained in:
itojun 2001-03-26 18:08:25 +00:00
parent 07c471d18e
commit 0265b9e0c2

View File

@ -60,22 +60,35 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "openssl/e_os.h"
#ifdef VMS
#include <unixio.h>
#endif
#ifndef NO_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef MAC_OS_pre_X
# include <stat.h>
#else
# include <sys/stat.h>
#endif
#include <openssl/crypto.h>
#include <openssl/rand.h>
#undef BUFSIZE
#define BUFSIZE 1024
#define RAND_DATA 1024
/* #define RFILE ".rand" - defined in ../../e_os.h */
/* #define RFILE ".rnd" - defined in ../../e_os.h */
int RAND_load_file(const char *file, long bytes)
{
/* If bytes >= 0, read up to 'bytes' bytes.
* if bytes == -1, read complete file. */
MS_STATIC unsigned char buf[BUFSIZE];
struct stat sb;
int i,ret=0,n;
@ -85,23 +98,37 @@ int RAND_load_file(const char *file, long bytes)
i=stat(file,&sb);
/* If the state fails, put some crap in anyway */
RAND_seed(&sb,sizeof(sb));
ret+=sizeof(sb);
RAND_add(&sb,sizeof(sb),0);
if (i < 0) return(0);
if (bytes <= 0) return(ret);
if (bytes == 0) return(ret);
in=fopen(file,"rb");
if (in == NULL) goto err;
if (sb.st_mode & (S_IFBLK | S_IFCHR)) {
/*
* this file is a device. we don't want read an infinite number
* of bytes from a random device, nor do we want to use buffered
* I/O because we will waste system entropy.
*/
bytes = (bytes == -1) ? 2048 : bytes; /* ok, is 2048 enough? */
setvbuf(in, NULL, _IONBF, 0); /* don't do buffered reads */
}
for (;;)
{
n=(bytes < BUFSIZE)?(int)bytes:BUFSIZE;
if (bytes > 0)
n = (bytes < BUFSIZE)?(int)bytes:BUFSIZE;
else
n = BUFSIZE;
i=fread(buf,1,n,in);
if (i <= 0) break;
/* even if n != i, use the full array */
RAND_seed(buf,n);
RAND_add(buf,n,i);
ret+=i;
bytes-=n;
if (bytes <= 0) break;
if (bytes > 0)
{
bytes-=n;
if (bytes == 0) break;
}
}
fclose(in);
memset(buf,0,BUFSIZE);
@ -112,29 +139,47 @@ err:
int RAND_write_file(const char *file)
{
unsigned char buf[BUFSIZE];
int i,ret=0;
FILE *out;
int i,ret=0,err=0;
FILE *out = NULL;
int n;
struct stat sb;
/* Under VMS, fopen(file, "wb") will craete a new version of the
same file. This is not good, so let's try updating an existing
one, and create file only if it doesn't already exist. This
should be completely harmless on system that have no file
versions. -- Richard Levitte */
out=fopen(file,"rb+");
if (out == NULL && errno == ENOENT)
{
errno = 0;
out=fopen(file,"wb");
i=stat(file,&sb);
if (i != -1) {
if (sb.st_mode & (S_IFBLK | S_IFCHR)) {
/*
* this file is a device. we don't write back to it.
* we "succeed" on the assumption this is some sort
* of random device. Otherwise attempting to write to
* and chmod the device causes problems.
*/
return(1);
}
if (out == NULL) goto err;
}
#if defined(O_CREAT) && defined(O_EXCL) && !defined(WIN32)
/* For some reason Win32 can't write to files created this way */
/* chmod(..., 0600) is too late to protect the file,
* permissions should be restrictive from the start */
int fd = open(file, O_CREAT | O_EXCL, 0600);
if (fd != -1)
out = fdopen(fd, "wb");
#endif
if (out == NULL)
out = fopen(file,"wb");
if (out == NULL) goto err;
#ifndef NO_CHMOD
chmod(file,0600);
#endif
n=RAND_DATA;
for (;;)
{
i=(n > BUFSIZE)?BUFSIZE:n;
n-=BUFSIZE;
RAND_bytes(buf,i);
if (RAND_bytes(buf,i) <= 0)
err=1;
i=fwrite(buf,1,i,out);
if (i <= 0)
{
@ -143,37 +188,78 @@ int RAND_write_file(const char *file)
}
ret+=i;
if (n <= 0) break;
}
#ifdef VMS
/* Try to delete older versions of the file, until there aren't
any */
{
char *tmpf;
tmpf = Malloc(strlen(file) + 4); /* to add ";-1" and a nul */
if (tmpf)
{
strcpy(tmpf, file);
strcat(tmpf, ";-1");
while(delete(tmpf) == 0)
;
rename(file,";1"); /* Make sure it's version 1, or we
will reach the limit (32767) at
some point... */
}
}
#endif /* VMS */
fclose(out);
memset(buf,0,BUFSIZE);
err:
return(ret);
return(err ? -1 : ret);
}
const char *RAND_file_name(char *buf, int size)
{
char *s;
char *s = NULL;
char *ret=NULL;
struct stat sb;
s=getenv("RANDFILE");
if (s != NULL)
if (issetugid() == 0)
s = getenv("RANDFILE");
if (s != NULL && *s && strlen(s) + 1 < size)
{
strncpy(buf,s,size-1);
buf[size-1]='\0';
strlcpy(buf,s,size);
ret=buf;
}
else
{
s=getenv("HOME");
if (s == NULL) return(RFILE);
if (((int)(strlen(s)+strlen(RFILE)+2)) > size)
return(RFILE);
strcpy(buf,s);
if (issetugid() == 0)
s=getenv("HOME");
if (s && *s && strlen(s)+strlen(RFILE)+2 < size)
{
strlcpy(buf,s,size);
#ifndef VMS
strcat(buf,"/");
strlcat(buf,"/",size);
#endif
strcat(buf,RFILE);
ret=buf;
strlcat(buf,RFILE,size);
ret=buf;
}
}
#ifdef DEVRANDOM
/* given that all random loads just fail if the file can't be
* seen on a stat, we stat the file we're returning, if it
* fails, use DEVRANDOM instead. the allows the user to
* use their own source for good random data, but defaults
* to something hopefully decent if that isn't available.
*/
if (ret == NULL)
ret = DEVRANDOM;
if (stat(ret,&sb) == -1)
ret = DEVRANDOM;
#else
/* old behavior */
if (ret == NULL)
ret = RFILE;
#endif
return(ret);
}