1/* getrandom.c - Libgcrypt Random Number client 2 * Copyright (C) 2006 Free Software Foundation, Inc. 3 * 4 * Getrandom is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published 6 * by the Free Software Foundation; either version 2 of the License, 7 * or (at your option) any later version. 8 * 9 * Getrandom is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 17 * 02110-1301, USA. 18 */ 19 20#include <config.h> 21#include <stdio.h> 22#include <stddef.h> 23#include <stdlib.h> 24#include <assert.h> 25#include <sys/types.h> 26#include <sys/stat.h> 27#include <stdarg.h> 28#include <sys/socket.h> 29#include <sys/un.h> 30#include <unistd.h> 31#include <errno.h> 32 33#define PGM "getrandom" 34#define MYVERSION_LINE PGM " (Libgcrypt) " VERSION 35#define BUGREPORT_LINE "\nReport bugs to <bug-libgcrypt@gnupg.org>.\n" 36 37 38static void 39logit (const char *format, ...) 40{ 41 va_list arg_ptr; 42 43 va_start (arg_ptr, format) ; 44 fputs (PGM ": ", stderr); 45 vfprintf (stderr, format, arg_ptr); 46 putc ('\n', stderr); 47 va_end (arg_ptr); 48} 49 50 51/* Send LENGTH bytes of BUFFER to file descriptor FD. Returns 0 on 52 success or another value on write error. */ 53static int 54writen (int fd, const void *buffer, size_t length) 55{ 56 while (length) 57 { 58 ssize_t n; 59 60 do 61 n = write (fd, buffer, length); 62 while (n < 0 && errno == EINTR); 63 if (n < 0) 64 { 65 logit ("write error: %s", strerror (errno)); 66 return -1; /* write error */ 67 } 68 length -= n; 69 buffer = (const char *)buffer + n; 70 } 71 return 0; /* Okay */ 72} 73 74 75 76 77static void 78print_version (int with_help) 79{ 80 fputs (MYVERSION_LINE "\n" 81 "Copyright (C) 2006 Free Software Foundation, Inc.\n" 82 "License GPLv2+: GNU GPL version 2 or later " 83 "<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>\n" 84 "This is free software: you are free to change and redistribute it.\n" 85 "There is NO WARRANTY, to the extent permitted by law.\n", 86 stdout); 87 88 if (with_help) 89 fputs ("\n" 90 "Usage: " PGM " [OPTIONS] NBYTES\n" 91 "Connect to libgcrypt's random number daemon and " 92 "return random numbers" 93 "\n" 94 " --nonce Return weak random suitable for a nonce\n" 95 " --very-strong Return very strong random\n" 96 " --ping Send a ping\n" 97 " --socket NAME Name of sockket to connect to\n" 98 " --hex Return result as a hex dump\n" 99 " --verbose Show what we are doing\n" 100 " --version Print version of the program and exit\n" 101 " --help Display this help and exit\n" 102 BUGREPORT_LINE, stdout ); 103 104 exit (0); 105} 106 107static int 108print_usage (void) 109{ 110 fputs ("usage: " PGM " [OPTIONS] NBYTES\n", stderr); 111 fputs (" (use --help to display options)\n", stderr); 112 exit (1); 113} 114 115 116int 117main (int argc, char **argv) 118{ 119 struct sockaddr_un *srvr_addr; 120 socklen_t addrlen; 121 int fd; 122 int rc; 123 unsigned char buffer[300]; 124 int nleft, nread; 125 const char *socketname = "/var/run/libgcrypt/S.gcryptrnd"; 126 int do_ping = 0; 127 int get_nonce = 0; 128 int get_very_strong = 0; 129 int req_nbytes, nbytes, n; 130 int verbose = 0; 131 int fail = 0; 132 int do_hex = 0; 133 134 if (argc) 135 { 136 argc--; argv++; 137 } 138 while (argc && **argv == '-' && (*argv)[1] == '-') 139 { 140 if (!(*argv)[2]) 141 { 142 argc--; argv++; 143 break; 144 } 145 else if (!strcmp (*argv, "--version")) 146 print_version (0); 147 else if (!strcmp (*argv, "--help")) 148 print_version (1); 149 else if (!strcmp (*argv, "--socket") && argc > 1 ) 150 { 151 argc--; argv++; 152 socketname = *argv; 153 argc--; argv++; 154 } 155 else if (!strcmp (*argv, "--nonce")) 156 { 157 argc--; argv++; 158 get_nonce = 1; 159 } 160 else if (!strcmp (*argv, "--very-strong")) 161 { 162 argc--; argv++; 163 get_very_strong = 1; 164 } 165 else if (!strcmp (*argv, "--ping")) 166 { 167 argc--; argv++; 168 do_ping = 1; 169 } 170 else if (!strcmp (*argv, "--hex")) 171 { 172 argc--; argv++; 173 do_hex = 1; 174 } 175 else if (!strcmp (*argv, "--verbose")) 176 { 177 argc--; argv++; 178 verbose = 1; 179 } 180 else 181 print_usage (); 182 } 183 184 185 if (!argc && do_ping) 186 ; /* This is allowed. */ 187 else if (argc != 1) 188 print_usage (); 189 req_nbytes = argc? atoi (*argv) : 0; 190 191 if (req_nbytes < 0) 192 print_usage (); 193 194 /* Create a socket. */ 195 fd = socket (AF_UNIX, SOCK_STREAM, 0); 196 if (fd == -1) 197 { 198 logit ("can't create socket: %s", strerror (errno)); 199 exit (1); 200 } 201 srvr_addr = malloc (sizeof *srvr_addr); 202 if (!srvr_addr) 203 { 204 logit ("malloc failed: %s", strerror (errno)); 205 exit (1); 206 } 207 memset (srvr_addr, 0, sizeof *srvr_addr); 208 srvr_addr->sun_family = AF_UNIX; 209 if (strlen (socketname) + 1 >= sizeof (srvr_addr->sun_path)) 210 { 211 logit ("socket name `%s' too long", socketname); 212 exit (1); 213 } 214 strcpy (srvr_addr->sun_path, socketname); 215 addrlen = (offsetof (struct sockaddr_un, sun_path) 216 + strlen (srvr_addr->sun_path) + 1); 217 rc = connect (fd, (struct sockaddr*) srvr_addr, addrlen); 218 if (rc == -1) 219 { 220 logit ("error connecting socket `%s': %s", 221 srvr_addr->sun_path, strerror (errno)); 222 close (fd); 223 exit (1); 224 } 225 226 do 227 { 228 nbytes = req_nbytes > 255? 255 : req_nbytes; 229 req_nbytes -= nbytes; 230 231 buffer[0] = 3; 232 if (do_ping) 233 buffer[1] = 0; 234 else if (get_nonce) 235 buffer[1] = 10; 236 else if (get_very_strong) 237 buffer[1] = 12; 238 else 239 buffer[1] = 11; 240 buffer[2] = nbytes; 241 if (writen (fd, buffer, 3)) 242 fail = 1; 243 else 244 { 245 for (nleft=2, nread=0; nleft > 0; ) 246 { 247 do 248 n = read (fd, buffer+nread, nleft); 249 while (n < 0 && errno == EINTR); 250 if (n < 0) 251 { 252 logit ("read error: %s", strerror (errno)); 253 exit (1); 254 } 255 nleft -= n; 256 nread += n; 257 if (nread && buffer[0]) 258 { 259 logit ("server returned error code %d", buffer[0]); 260 exit (1); 261 } 262 } 263 if (verbose) 264 logit ("received response with %d bytes of data", buffer[1]); 265 if (buffer[1] < nbytes) 266 { 267 logit ("warning: server returned less bytes than requested"); 268 fail = 1; 269 } 270 else if (buffer[1] > nbytes && !do_ping) 271 { 272 logit ("warning: server returned more bytes than requested"); 273 fail = 1; 274 } 275 nbytes = buffer[1]; 276 if (nbytes > sizeof buffer) 277 { 278 logit ("buffer too short to receive data"); 279 exit (1); 280 } 281 282 for (nleft=nbytes, nread=0; nleft > 0; ) 283 { 284 do 285 n = read (fd, buffer+nread, nleft); 286 while (n < 0 && errno == EINTR); 287 if (n < 0) 288 { 289 logit ("read error: %s", strerror (errno)); 290 exit (1); 291 } 292 nleft -= n; 293 nread += n; 294 } 295 296 if (do_hex) 297 { 298 for (n=0; n < nbytes; n++) 299 { 300 if (!n) 301 ; 302 else if (!(n % 16)) 303 putchar ('\n'); 304 else 305 putchar (' '); 306 printf ("%02X", buffer[n]); 307 } 308 if (nbytes) 309 putchar ('\n'); 310 } 311 else 312 { 313 if (fwrite (buffer, nbytes, 1, stdout) != 1) 314 { 315 logit ("error writing to stdout: %s", strerror (errno)); 316 fail = 1; 317 } 318 } 319 } 320 } 321 while (!fail && req_nbytes); 322 323 close (fd); 324 free (srvr_addr); 325 return fail? 1 : 0; 326} 327