randfile.c 9.3 KB
Newer Older
R
Rich Salz 已提交
1 2
/*
 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3
 *
R
Rich Salz 已提交
4 5 6 7
 * Licensed under the OpenSSL license (the "License").  You may not use
 * this file except in compliance with the License.  You can obtain a copy
 * in the file LICENSE in the source distribution or at
 * https://www.openssl.org/source/license.html
8 9
 */

D
Dr. Stephen Henson 已提交
10 11
#include "e_os.h"

U
Ulf Möller 已提交
12
#include <errno.h>
13
#include <stdio.h>
B
Ben Laurie 已提交
14 15
#include <stdlib.h>
#include <string.h>
16

17 18
#include <openssl/crypto.h>
#include <openssl/rand.h>
19
#include <openssl/buffer.h>
20

21
#ifdef OPENSSL_SYS_VMS
22
# include <unixio.h>
23
#endif
A
Andy Polyakov 已提交
24 25 26
#ifndef NO_SYS_TYPES_H
# include <sys/types.h>
#endif
27
#ifndef OPENSSL_NO_POSIX_IO
A
Andy Polyakov 已提交
28
# include <sys/stat.h>
29
# include <fcntl.h>
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/*
 * Following should not be needed, and we could have been stricter
 * and demand S_IS*. But some systems just don't comply... Formally
 * below macros are "anatomically incorrect", because normally they
 * would look like ((m) & MASK == TYPE), but since MASK availability
 * is as questionable, we settle for this poor-man fallback...
 */
# if !defined(S_ISBLK)
#  if defined(_S_IFBLK)
#   define S_ISBLK(m) ((m) & _S_IFBLK)
#  elif defined(S_IFBLK)
#   define S_ISBLK(m) ((m) & S_IFBLK)
#  elif defined(_WIN32)
#   define S_ISBLK(m) 0 /* no concept of block devices on Windows */
#  endif
# endif
# if !defined(S_ISCHR)
#  if defined(_S_IFCHR)
#   define S_ISCHR(m) ((m) & _S_IFCHR)
#  elif defined(S_IFCHR)
#   define S_ISCHR(m) ((m) & S_IFCHR)
#  endif
# endif
A
Andy Polyakov 已提交
53 54
#endif

55
#ifdef _WIN32
56 57 58 59
# define stat    _stat
# define chmod   _chmod
# define open    _open
# define fdopen  _fdopen
60 61
#endif

62
#undef BUFSIZE
63
#define BUFSIZE 1024
64 65
#define RAND_DATA 1024

66
#ifdef OPENSSL_SYS_VMS
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
/*
 * Misc hacks needed for specific cases.
 *
 * __FILE_ptr32 is a type provided by DEC C headers (types.h specifically)
 * to make sure the FILE* is a 32-bit pointer no matter what.  We know that
 * stdio function return this type (a study of stdio.h proves it).
 * Additionally, we create a similar char pointer type for the sake of
 * vms_setbuf below.
 */
# if __INITIAL_POINTER_SIZE == 64
#  pragma pointer_size save
#  pragma pointer_size 32
# endif
typedef char *char_ptr32;
# if __INITIAL_POINTER_SIZE == 64
#  pragma pointer_size restore
# endif

/*
 * On VMS, setbuf() will only take 32-bit pointers, and a compilation
 * with /POINTER_SIZE=64 will give off a MAYLOSEDATA2 warning here.
 * Since we know that the FILE* really is a 32-bit pointer expanded to
 * 64 bits, we also know it's safe to convert it back to a 32-bit pointer.
 * As for the buffer parameter, we only use NULL here, so that passes as
 * well...
 */
static void vms_setbuf(FILE *fp, char *buf)
{
    setbuf((__FILE_ptr32)fp, (char_ptr32)buf);
}
97 98
/*
 * This declaration is a nasty hack to get around vms' extension to fopen for
99
 * passing in sharing options being disabled by /STANDARD=ANSI89
100
 */
101 102
static __FILE_ptr32 (*const vms_fopen)(const char *, const char *, ...) =
    (__FILE_ptr32 (*)(const char *, const char *, ...))fopen;
103
# define VMS_OPEN_ATTRS "shr=get,put,upd,del","ctx=bin,stm","rfm=stm","rat=none","mrs=0"
104 105
#endif

R
Rich Salz 已提交
106
#define RFILE ".rnd"
107

108 109 110 111
/*
 * Note that these functions are intended for seed files only. Entropy
 * devices and EGD sockets are handled in rand_unix.c
 */
112

U
Ulf Möller 已提交
113
int RAND_load_file(const char *file, long bytes)
114
{
M
Matt Caswell 已提交
115 116 117 118
    /*-
     * If bytes >= 0, read up to 'bytes' bytes.
     * if bytes == -1, read complete file.
     */
119

120
    unsigned char buf[BUFSIZE];
121
#ifndef OPENSSL_NO_POSIX_IO
122
    struct stat sb;
123
#endif
124 125
    int i, ret = 0, n;
    FILE *in;
126

127 128
    if (file == NULL)
        return (0);
129

130
#ifndef OPENSSL_NO_POSIX_IO
131 132 133 134 135 136 137 138 139 140
    /*
     * struct stat can have padding and unused fields that may not be
     * initialized in the call to stat(). We need to clear the entire
     * structure before calling RAND_add() to avoid complaints from
     * applications such as Valgrind.
     */
    memset(&sb, 0, sizeof(sb));
    if (stat(file, &sb) < 0)
        return (0);
    RAND_add(&sb, sizeof(sb), 0.0);
141
#endif
142 143
    if (bytes == 0)
        return (ret);
144

145
#ifdef OPENSSL_SYS_VMS
146
    in = vms_fopen(file, "rb", VMS_OPEN_ATTRS);
147
#else
148
    in = fopen(file, "rb");
149
#endif
150 151
    if (in == NULL)
        goto err;
152 153
#if defined(S_ISBLK) && defined(S_ISCHR) && !defined(OPENSSL_NO_POSIX_IO)
    if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
154 155 156 157 158 159
        /*
         * 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? */
160 161 162 163 164 165 166

        /* don't do buffered reads */
# ifdef OPENSSL_SYS_VMS
        vms_setbuf(in, NULL);
# else
        setbuf(in, NULL);
# endif
167
    }
168
#endif
169 170 171 172 173 174 175 176
    for (;;) {
        if (bytes > 0)
            n = (bytes < BUFSIZE) ? (int)bytes : BUFSIZE;
        else
            n = BUFSIZE;
        i = fread(buf, 1, n, in);
        if (i <= 0)
            break;
E
Emilia Kasper 已提交
177

178 179 180 181 182 183 184 185 186 187 188 189 190
        RAND_add(buf, i, (double)i);
        ret += i;
        if (bytes > 0) {
            bytes -= n;
            if (bytes <= 0)
                break;
        }
    }
    fclose(in);
    OPENSSL_cleanse(buf, BUFSIZE);
 err:
    return (ret);
}
191

U
Ulf Möller 已提交
192
int RAND_write_file(const char *file)
193 194 195 196 197
{
    unsigned char buf[BUFSIZE];
    int i, ret = 0, rand_err = 0;
    FILE *out = NULL;
    int n;
198
#ifndef OPENSSL_NO_POSIX_IO
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
    struct stat sb;

    i = stat(file, &sb);
    if (i != -1) {
# if defined(S_ISBLK) && defined(S_ISCHR)
        if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
            /*
             * 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);
        }
# endif
    }
215
#endif
216

217
#if defined(O_CREAT) && !defined(OPENSSL_NO_POSIX_IO) && !defined(OPENSSL_SYS_VMS)
218 219 220 221 222 223 224 225 226 227 228 229
    {
# ifndef O_BINARY
#  define O_BINARY 0
# endif
        /*
         * chmod(..., 0600) is too late to protect the file, permissions
         * should be restrictive from the start
         */
        int fd = open(file, O_WRONLY | O_CREAT | O_BINARY, 0600);
        if (fd != -1)
            out = fdopen(fd, "wb");
    }
A
Andy Polyakov 已提交
230
#endif
231 232

#ifdef OPENSSL_SYS_VMS
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
    /*
     * VMS NOTE: Prior versions of this routine created a _new_ version of
     * the rand file for each call into this routine, then deleted all
     * existing versions named ;-1, and finally renamed the current version
     * as ';1'. Under concurrent usage, this resulted in an RMS race
     * condition in rename() which could orphan files (see vms message help
     * for RMS$_REENT). With the fopen() calls below, openssl/VMS now shares
     * the top-level version of the rand file. Note that there may still be
     * conditions where the top-level rand file is locked. If so, this code
     * will then create a new version of the rand file. Without the delete
     * and rename code, this can result in ascending file versions that stop
     * at version 32767, and this routine will then return an error. The
     * remedy for this is to recode the calling application to avoid
     * concurrent use of the rand file, or synchronize usage at the
     * application level. Also consider whether or not you NEED a persistent
     * rand file in a concurrent use situation.
     */
250

251 252 253
    out = vms_fopen(file, "rb+", VMS_OPEN_ATTRS);
    if (out == NULL)
        out = vms_fopen(file, "wb", VMS_OPEN_ATTRS);
254
#else
255 256
    if (out == NULL)
        out = fopen(file, "wb");
257
#endif
258 259
    if (out == NULL)
        goto err;
260

M
Matt Caswell 已提交
261
#if !defined(NO_CHMOD) && !defined(OPENSSL_NO_POSIX_IO)
262
    chmod(file, 0600);
A
Andy Polyakov 已提交
263
#endif
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
    n = RAND_DATA;
    for (;;) {
        i = (n > BUFSIZE) ? BUFSIZE : n;
        n -= BUFSIZE;
        if (RAND_bytes(buf, i) <= 0)
            rand_err = 1;
        i = fwrite(buf, 1, i, out);
        if (i <= 0) {
            ret = 0;
            break;
        }
        ret += i;
        if (n <= 0)
            break;
    }
279

280 281 282 283 284
    fclose(out);
    OPENSSL_cleanse(buf, BUFSIZE);
 err:
    return (rand_err ? -1 : ret);
}
285

286
const char *RAND_file_name(char *buf, size_t size)
287 288
{
    char *s = NULL;
289
#ifdef __OpenBSD__
290
    struct stat sb;
291
#endif
292

293 294 295
    if (OPENSSL_issetugid() == 0)
        s = getenv("RANDFILE");
    if (s != NULL && *s && strlen(s) + 1 < size) {
R
Rich Salz 已提交
296
        if (OPENSSL_strlcpy(buf, s, size) >= size)
297 298 299 300
            return NULL;
    } else {
        if (OPENSSL_issetugid() == 0)
            s = getenv("HOME");
301
#ifdef DEFAULT_HOME
302 303 304
        if (s == NULL) {
            s = DEFAULT_HOME;
        }
305
#endif
306
        if (s && *s && strlen(s) + strlen(RFILE) + 2 < size) {
R
Rich Salz 已提交
307
            OPENSSL_strlcpy(buf, s, size);
308
#ifndef OPENSSL_SYS_VMS
R
Rich Salz 已提交
309
            OPENSSL_strlcat(buf, "/", size);
U
Ulf Möller 已提交
310
#endif
R
Rich Salz 已提交
311
            OPENSSL_strlcat(buf, RFILE, size);
312 313 314
        } else
            buf[0] = '\0';      /* no file name */
    }
315 316

#ifdef __OpenBSD__
317 318 319 320 321 322 323
    /*
     * 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 /dev/arandom
     * instead. this allows the user to use their own source for good random
     * data, but defaults to something hopefully decent if that isn't
     * available.
     */
324

325
    if (!buf[0])
R
Rich Salz 已提交
326
        if (OPENSSL_strlcpy(buf, "/dev/arandom", size) >= size) {
327 328 329
            return (NULL);
        }
    if (stat(buf, &sb) == -1)
R
Rich Salz 已提交
330
        if (OPENSSL_strlcpy(buf, "/dev/arandom", size) >= size) {
331 332
            return (NULL);
        }
333
#endif
334 335
    return (buf);
}