chiark / gitweb /
Check for `setreuid' for changing permissions.
[become] / src / noise.c
1 /* -*-c-*-
2  *
3  * $Id: noise.c,v 1.2 1997/08/20 16:19:57 mdw Exp $
4  *
5  * Collection of environmental noise
6  *
7  * (c) 1997 EBI
8  */
9
10 /*----- Licensing notice --------------------------------------------------*
11  *
12  * This file is part of `become'
13  *
14  * `Become' is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  *
19  * `Become' is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with `become'; if not, write to the Free Software Foundation,
26  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27  */
28
29 /*----- Revision history --------------------------------------------------*
30  *
31  * $Log: noise.c,v $
32  * Revision 1.2  1997/08/20 16:19:57  mdw
33  * Fix test for `/dev/random' so that it doesn't close `stdin' if it fails!
34  *
35  * Revision 1.1  1997/08/07 09:45:26  mdw
36  * New source file added to acquire environmental noise and add it to the
37  * randomness pool (see `rand.c').
38  *
39  */
40
41 /*----- Header files ------------------------------------------------------*/
42
43 /* --- ANSI headers --- */
44
45 #include <ctype.h>
46 #include <errno.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <time.h>
51
52 /* --- Unix headers --- */
53
54 #include <sys/types.h>
55 #include <sys/time.h>
56
57 #include "config.h"
58 #if defined(HAVE_GETRUSAGE)
59 #  include <sys/resource.h>
60 #elif defined(HAVE_VTIMES)
61 #  include <sys/vtimes.h>
62 #endif
63
64 #include <sys/wait.h>
65
66 #include <fcntl.h>
67 #include <unistd.h>
68
69 /* --- Local headers --- */
70
71 #include "noise.h"
72 #include "rand.h"
73 #include "utils.h"
74
75 /*----- Main code ---------------------------------------------------------*/
76
77 /* --- @noise__shell@ --- *
78  *
79  * Arguments:   @const char *cmd@ = pointer to a shell command
80  *
81  * Returns:     ---
82  *
83  * Use:         Adds the output of the shell command to the randomness pool.
84  *              Some care is taken to do the Right Thing when running setuid.
85  */
86
87 static void noise__shell(const char *cmd)
88 {
89   int pfd[2];
90   pid_t pid;
91
92   /* --- Create a pipe for talking to the child --- */
93
94   if (pipe(pfd))
95     return;
96
97   /* --- Create the child process --- */
98
99   pid = fork();
100   if (pid < 0)
101     return;
102
103   if (pid == 0) {
104     int fd;
105     char *argv[] = { "/bin/sh", "-c", 0, 0 };
106     char *env[] = {
107       "PATH=/bin:/usr/bin:/usr/ucb:/usr/etc:/sbin:/usr/sbin",
108       0
109     };
110
111     /* --- Become whoever I'm being run as --- */
112
113     setuid(getuid());
114
115     /* --- Close the old standard streams --- */
116
117     close(0);
118     close(1);
119     close(2);
120
121     /* --- Set up stdin and stderr to be empty, and stdout as our pipe --- */
122
123     if (((fd = open("/dev/null", O_RDONLY)) != 0 &&
124          (fd = dup2(fd, 0)) != 0) ||
125         ((fd = dup2(pfd[1], 1)) != 1) ||
126         ((fd = open("/dev/null", O_WRONLY)) != 2 &&
127          (fd = dup2(fd, 2)) != 2))
128       goto child_fail;
129
130     /* --- Close the original pipe file descriptors --- */
131
132     close(pfd[0]);
133     close(pfd[1]);
134     burn(pfd);
135
136     /* --- Now run the child process --- */
137
138     argv[2] = (char *)cmd;              /* POSIX screwed up the prototype */
139     execve("/bin/sh", argv, env);
140
141     /* --- Something went horribly wrong --- */
142
143   child_fail:
144     _exit(127);
145   }
146
147   /* --- Now read from the child until it's all done --- */
148
149   {
150     char buf[1024];
151     ssize_t sz;
152
153     close(pfd[1]);
154     for (;;) {
155       sz = read(pfd[0], buf, sizeof(buf));
156       if (sz == 0 || (sz < 0 && sz != EINTR))
157         break;
158       rand_add(buf, sz);
159     }
160     close(pfd[0]);
161     rand_add(pfd, sizeof(pfd));
162     burn(buf); burn(pfd);
163   }
164
165   /* --- The child should be dead now, so wait for it --- */
166
167   {
168     int st;
169
170     wait(&st);
171     rand_add(&st, sizeof(st));
172     rand_add(&pid, sizeof(pid));
173   }
174 }
175
176 /* --- @noise_acquire@ --- *
177  *
178  * Arguments:   ---
179  *
180  * Returns:     ---
181  *
182  * Use:         Attempts to acquire an amount of random noise from the
183  *              environment.  A lot of it's not actually much good, but
184  *              it's better than nothing.  There's probably a bit or two's
185  *              worth in each item which gets added.
186  */
187
188 void noise_acquire(void)
189 {
190   /* --- Try a real random number source --- *
191    *
192    * Some operating systems (notably Linux) provide a `/dev/random' which
193    * contains distilled random numbers from the outside world.
194    */
195
196   {
197     int fd;
198     int f;
199     unsigned char buff[64];
200     ssize_t sz;
201
202     if ((fd = open("/dev/random", O_RDONLY)) >= 0 &&
203         (f = fcntl(fd, F_GETFL, 0)) >= 0 &&
204         fcntl(fd, F_SETFL, f | O_NONBLOCK) >= 0 &&
205         (sz = read(fd, buff, sizeof(buff))) > 0) {
206       rand_add(buff, sz);
207       burn(buff);
208     }
209     if (fd >= 0)
210       close(fd);
211   }
212
213   /* --- Squeeze some entropy from the current time --- */
214
215   {
216     struct timeval tv;
217     clock_t c;
218
219     gettimeofday(&tv, 0);
220     c = clock();
221     rand_add(&tv, sizeof(tv));
222     rand_add(&c, sizeof(c));
223     burn(tv); burn(c);
224   }
225
226   /* --- Try some commands which ask the outside world some questions --- */
227
228   noise__shell("ps auxww");
229   noise__shell("ps -ef");
230   noise__shell("df");
231   /* @noise__shell("netstat -a");@ -- takes too long */
232
233   /* --- Get our resource usage to see if that's at all interesting --- */
234
235 #if defined(HAVE_GETRUSAGE)
236   {
237     struct rusage ru;
238     getrusage(RUSAGE_SELF, &ru);
239     rand_add(&ru, sizeof(ru));
240     getrusage(RUSAGE_CHILDREN, &ru);
241     rand_add(&ru, sizeof(ru));
242     burn(ru);
243   }
244 #elif defined(HAVE_VTIMES)
245   {
246     struct vtimes vt, vtc;
247     vtimes(&vt, &vtc);
248     rand_add(&vt, sizeof(vt));
249     rand_add(&vtc, sizeof(vtc));
250     burn(vt); burn(vtc);
251   }
252 #endif
253
254   /* --- Squeeze some more entropy from the current time --- */
255
256   {
257     struct timeval tv;
258     clock_t c;
259
260     gettimeofday(&tv, 0);
261     c = clock();
262     rand_add(&tv, sizeof(tv));
263     rand_add(&c, sizeof(c));
264     burn(tv); burn(c);
265   }
266
267   /* --- Done -- churn the random pool --- */
268
269   rand_churn();
270 }
271
272 /*----- That's all, folks -------------------------------------------------*/