~ubuntu-branches/ubuntu/natty/libgcrypt11/natty-proposed

« back to all changes in this revision

Viewing changes to random/rndlinux.c

  • Committer: Bazaar Package Importer
  • Author(s): Bhavani Shankar
  • Date: 2009-05-16 20:13:32 UTC
  • mfrom: (1.1.6 upstream) (2.1.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090516201332-czkobpu32w318i16
Tags: 1.4.4-2ubuntu1
* Merge from Debian unstable (LP: #364535), remaining changes:
  - Add libgcrypt11-udeb for use by cryptsetup-udeb.
  - Add clean-la.mk, and add a symlink for the .la
  - Install to /lib.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* rndlinux.c  -  raw random number for OSes with /dev/random
 
2
 * Copyright (C) 1998, 2001, 2002, 2003, 2007  Free Software Foundation, Inc.
 
3
 *
 
4
 * This file is part of Libgcrypt.
 
5
 *
 
6
 * Libgcrypt is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU Lesser General Public License as
 
8
 * published by the Free Software Foundation; either version 2.1 of
 
9
 * the License, or (at your option) any later version.
 
10
 *
 
11
 * Libgcrypt is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU Lesser General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU Lesser General Public
 
17
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
 
18
 */
 
19
 
 
20
 
 
21
#include <config.h>
 
22
#include <stdio.h>
 
23
#include <stdlib.h>
 
24
#include <errno.h>
 
25
#include <sys/time.h>
 
26
#include <sys/types.h>
 
27
#include <sys/stat.h>
 
28
#ifdef HAVE_GETTIMEOFDAY
 
29
# include <sys/times.h>
 
30
#endif
 
31
#include <string.h>
 
32
#include <unistd.h>
 
33
#include <fcntl.h>
 
34
#include "types.h"
 
35
#include "g10lib.h"
 
36
#include "rand-internal.h"
 
37
 
 
38
static int open_device ( const char *name );
 
39
 
 
40
 
 
41
static int
 
42
set_cloexec_flag (int fd)
 
43
{
 
44
  int oldflags;
 
45
 
 
46
  oldflags= fcntl (fd, F_GETFD, 0);
 
47
  if (oldflags < 0)
 
48
    return oldflags;
 
49
  oldflags |= FD_CLOEXEC;
 
50
  return fcntl (fd, F_SETFD, oldflags);
 
51
}
 
52
 
 
53
 
 
54
 
 
55
/*
 
56
 * Used to open the /dev/random devices (Linux, xBSD, Solaris (if it exists)).
 
57
 */
 
58
static int
 
59
open_device ( const char *name )
 
60
{
 
61
  int fd;
 
62
 
 
63
  fd = open ( name, O_RDONLY );
 
64
  if ( fd == -1 )
 
65
    log_fatal ("can't open %s: %s\n", name, strerror(errno) );
 
66
 
 
67
  if (set_cloexec_flag (fd))
 
68
    log_error ("error setting FD_CLOEXEC on fd %d: %s\n",
 
69
               fd, strerror (errno));
 
70
 
 
71
  /* We used to do the following check, however it turned out that this
 
72
     is not portable since more OSes provide a random device which is
 
73
     sometimes implemented as another device type. 
 
74
     
 
75
     struct stat sb;
 
76
 
 
77
     if( fstat( fd, &sb ) )
 
78
        log_fatal("stat() off %s failed: %s\n", name, strerror(errno) );
 
79
     if( (!S_ISCHR(sb.st_mode)) && (!S_ISFIFO(sb.st_mode)) )
 
80
        log_fatal("invalid random device!\n" );
 
81
  */
 
82
  return fd;
 
83
}
 
84
 
 
85
 
 
86
int
 
87
_gcry_rndlinux_gather_random (void (*add)(const void*, size_t,
 
88
                                          enum random_origins),
 
89
                              enum random_origins origin,
 
90
                              size_t length, int level )
 
91
{
 
92
  static int fd_urandom = -1;
 
93
  static int fd_random = -1;
 
94
  int fd;
 
95
  int n;
 
96
  int warn=0;
 
97
  byte buffer[768];
 
98
  size_t n_hw;
 
99
 
 
100
  /* First read from a hardware source.  However let it account only
 
101
     for up to 50% of the requested bytes.  */
 
102
  n_hw = _gcry_rndhw_poll_slow (add, origin);
 
103
  if (n_hw > length/2)
 
104
    n_hw = length/2;
 
105
  if (length > 1)
 
106
    length -= n_hw;
 
107
 
 
108
  /* Open the requested device.  */
 
109
  if (level >= 2)
 
110
    {
 
111
      if( fd_random == -1 )
 
112
        fd_random = open_device ( NAME_OF_DEV_RANDOM );
 
113
      fd = fd_random;
 
114
    }
 
115
  else
 
116
    {
 
117
      if( fd_urandom == -1 )
 
118
        fd_urandom = open_device ( NAME_OF_DEV_URANDOM );
 
119
      fd = fd_urandom;
 
120
    }
 
121
 
 
122
  /* And enter the read loop.  */
 
123
  while (length)
 
124
    {
 
125
      fd_set rfds;
 
126
      struct timeval tv;
 
127
      int rc;
 
128
      
 
129
      FD_ZERO(&rfds);
 
130
      FD_SET(fd, &rfds);
 
131
      tv.tv_sec = 3;
 
132
      tv.tv_usec = 0;
 
133
      if( !(rc=select(fd+1, &rfds, NULL, NULL, &tv)) )
 
134
        {
 
135
          if( !warn )
 
136
            {
 
137
              _gcry_random_progress ("need_entropy", 'X', 0, (int)length);
 
138
              warn = 1;
 
139
            }
 
140
          continue;
 
141
        }
 
142
        else if( rc == -1 )
 
143
          {
 
144
            log_error ("select() error: %s\n", strerror(errno));
 
145
            continue;
 
146
          }
 
147
 
 
148
        do 
 
149
          {
 
150
            int nbytes = length < sizeof(buffer)? length : sizeof(buffer);
 
151
            n = read(fd, buffer, nbytes );
 
152
            if( n >= 0 && n > nbytes ) 
 
153
              {
 
154
                log_error("bogus read from random device (n=%d)\n", n );
 
155
                n = nbytes;
 
156
              }
 
157
          } 
 
158
        while( n == -1 && errno == EINTR );
 
159
        if( n == -1 )
 
160
          log_fatal("read error on random device: %s\n", strerror(errno));
 
161
        (*add)( buffer, n, origin );
 
162
        length -= n;
 
163
    }
 
164
  memset(buffer, 0, sizeof(buffer) );
 
165
 
 
166
  return 0; /* success */
 
167
}