1/* rndegd.c - interface to the EGD 2 * Copyright (C) 1999, 2000, 2002, 2003 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, write to the Free Software 18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 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/stat.h> 27#include <string.h> 28#include <unistd.h> 29#include <sys/types.h> 30#include <sys/socket.h> 31#include <sys/un.h> 32#include "types.h" 33#include "g10lib.h" 34#include "cipher.h" 35#include "rand-internal.h" 36 37#ifndef offsetof 38#define offsetof(type, member) ((size_t) &((type *)0)->member) 39#endif 40 41static int egd_socket = -1; 42 43/* Allocated name of the socket if supplied at runtime. */ 44static char *user_socket_name; 45 46 47/* Allocate a new filename from FIRST_PART and SECOND_PART and to 48 tilde expansion for first_part. SECOND_PART might be NULL. 49 */ 50static char * 51my_make_filename (const char *first_part, const char *second_part) 52{ 53 size_t n; 54 char *name, *home, *p; 55 56 n = strlen(first_part)+1; 57 if (second_part) 58 n += strlen (second_part) + 1; 59 60 home = NULL; 61 if( *first_part == '~' && first_part[1] == '/' 62 && (home = getenv("HOME")) && *home ) 63 n += strlen(home); 64 65 name = gcry_xmalloc(n); 66 p = (home 67 ? stpcpy (stpcpy (name, home), first_part+1 ) 68 : stpcpy (name, first_part) ); 69 70 if (second_part) 71 strcpy (stpcpy(p,"/"), second_part); 72 73 return name; 74} 75 76 77static int 78do_write( int fd, void *buf, size_t nbytes ) 79{ 80 size_t nleft = nbytes; 81 int nwritten; 82 83 while( nleft > 0 ) 84 { 85 nwritten = write( fd, buf, nleft); 86 if( nwritten < 0 ) 87 { 88 if( errno == EINTR ) 89 continue; 90 return -1; 91 } 92 nleft -= nwritten; 93 buf = (char*)buf + nwritten; 94 } 95 return 0; 96} 97 98static int 99do_read( int fd, void *buf, size_t nbytes ) 100{ 101 int n, nread = 0; 102 103 do 104 { 105 do 106 { 107 n = read(fd, (char*)buf + nread, nbytes ); 108 } 109 while( n == -1 && errno == EINTR ); 110 if( n == -1) 111 return nread? nread:-1; 112 if( n == 0) 113 return -1; 114 nread += n; 115 nbytes -= n; 116 } 117 while( nread < nbytes ); 118 return nread; 119} 120 121 122/* Note that his function is not thread-safe. */ 123gpg_error_t 124_gcry_rndegd_set_socket_name (const char *name) 125{ 126 char *newname; 127 struct sockaddr_un addr; 128 129 newname = my_make_filename (name, NULL); 130 if (strlen (newname)+1 >= sizeof addr.sun_path) 131 { 132 gcry_free (newname); 133 return gpg_error_from_syserror (); 134 } 135 gcry_free (user_socket_name); 136 user_socket_name = newname; 137 return 0; 138} 139 140 141/* Connect to the EGD and return the file descriptor. Return -1 on 142 error. With NOFAIL set to true, silently fail and return the 143 error, otherwise print an error message and die. */ 144int 145_gcry_rndegd_connect_socket (int nofail) 146{ 147 int fd; 148 const char *bname = NULL; 149 char *name; 150 struct sockaddr_un addr; 151 int addr_len; 152 153 if (egd_socket != -1) 154 { 155 close (egd_socket); 156 egd_socket = -1; 157 } 158 159#ifdef EGD_SOCKET_NAME 160 bname = EGD_SOCKET_NAME; 161#endif 162 if (user_socket_name) 163 { 164 name = gcry_strdup (user_socket_name); 165 if (!name) 166 { 167 if (!nofail) 168 log_fatal ("error allocating memory in rndegd: %s\n", 169 strerror(errno) ); 170 return -1; 171 } 172 } 173 else if ( !bname || !*bname ) 174 name = my_make_filename ("~/.gnupg", "entropy"); 175 else 176 name = my_make_filename (bname, NULL); 177 178 if (strlen(name)+1 >= sizeof addr.sun_path) 179 log_fatal ("EGD socketname is too long\n"); 180 181 memset( &addr, 0, sizeof addr ); 182 addr.sun_family = AF_UNIX; 183 strcpy( addr.sun_path, name ); 184 addr_len = (offsetof( struct sockaddr_un, sun_path ) 185 + strlen( addr.sun_path )); 186 187 fd = socket(AF_UNIX, SOCK_STREAM, 0); 188 if (fd == -1 && !nofail) 189 log_fatal("can't create unix domain socket: %s\n", strerror(errno) ); 190 else if (connect (fd, (struct sockaddr*)&addr, addr_len) == -1) 191 { 192 if (!nofail) 193 log_fatal("can't connect to EGD socket `%s': %s\n", 194 name, strerror(errno) ); 195 close (fd); 196 fd = -1; 197 } 198 gcry_free(name); 199 if (fd != -1) 200 egd_socket = fd; 201 return fd; 202} 203 204/**************** 205 * Note: We always use the highest level. 206 * To boost the performance we may want to add some 207 * additional code for level 1 208 * 209 * Using a level of 0 should never block and better add nothing 210 * to the pool. So this is just a dummy for EGD. 211 */ 212int 213_gcry_rndegd_gather_random (void (*add)(const void*, size_t, 214 enum random_origins), 215 enum random_origins origin, 216 size_t length, int level ) 217{ 218 int fd = egd_socket; 219 int n; 220 byte buffer[256+2]; 221 int nbytes; 222 int do_restart = 0; 223 224 if( !length ) 225 return 0; 226 if( !level ) 227 return 0; 228 229 restart: 230 if (fd == -1 || do_restart) 231 fd = _gcry_rndegd_connect_socket (0); 232 233 do_restart = 0; 234 235 nbytes = length < 255? length : 255; 236 /* First time we do it with a non blocking request */ 237 buffer[0] = 1; /* non blocking */ 238 buffer[1] = nbytes; 239 if( do_write( fd, buffer, 2 ) == -1 ) 240 log_fatal("can't write to the EGD: %s\n", strerror(errno) ); 241 n = do_read( fd, buffer, 1 ); 242 if( n == -1 ) 243 { 244 log_error("read error on EGD: %s\n", strerror(errno)); 245 do_restart = 1; 246 goto restart; 247 } 248 n = buffer[0]; 249 if( n ) 250 { 251 n = do_read( fd, buffer, n ); 252 if( n == -1 ) 253 { 254 log_error("read error on EGD: %s\n", strerror(errno)); 255 do_restart = 1; 256 goto restart; 257 } 258 (*add)( buffer, n, origin ); 259 length -= n; 260 } 261 262 if( length ) 263 { 264 log_info ( 265 _("Please wait, entropy is being gathered. Do some work if it would\n" 266 "keep you from getting bored, because it will improve the quality\n" 267 "of the entropy.\n") ); 268 } 269 while( length ) 270 { 271 nbytes = length < 255? length : 255; 272 273 buffer[0] = 2; /* blocking */ 274 buffer[1] = nbytes; 275 if( do_write( fd, buffer, 2 ) == -1 ) 276 log_fatal("can't write to the EGD: %s\n", strerror(errno) ); 277 n = do_read( fd, buffer, nbytes ); 278 if( n == -1 ) 279 { 280 log_error("read error on EGD: %s\n", strerror(errno)); 281 do_restart = 1; 282 goto restart; 283 } 284 (*add)( buffer, n, origin ); 285 length -= n; 286 } 287 memset(buffer, 0, sizeof(buffer) ); 288 289 return 0; /* success */ 290} 291