wipememory: use one-byte aligned type for unaligned memory accesses
[libgcrypt.git] / src / getrandom.c
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
38 static void
39 logit (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. */
53 static int
54 writen (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
77 static void
78 print_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
107 static int
108 print_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
116 int
117 main (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 }