1 /* $NetBSD: rand-timer.c,v 1.2 2017/01/28 21:31:47 christos Exp $ */
2
3 /*
4 * Copyright (c) 1995, 1996, 1997, 1999, 2007 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <config.h>
37 #include <krb5/roken.h>
38
39 #include <rand.h>
40
41 #include "randi.h"
42
43 #ifndef WIN32 /* don't bother with this on windows */
44
45 static volatile int counter;
46 static volatile unsigned char *gdata; /* Global data */
47 static volatile int igdata; /* Index into global data */
48 static int gsize;
49
50 static
51 RETSIGTYPE
sigALRM(int sig)52 sigALRM(int sig)
53 {
54 if (igdata < gsize)
55 gdata[igdata++] ^= counter & 0xff;
56
57 #ifndef HAVE_SIGACTION
58 signal(SIGALRM, sigALRM); /* Reinstall SysV signal handler */
59 #endif
60 SIGRETURN(0);
61 }
62
63 #ifndef HAVE_SETITIMER
64 static void
pacemaker(struct timeval * tv)65 pacemaker(struct timeval *tv)
66 {
67 fd_set fds;
68 pid_t pid;
69 pid = getppid();
70 while(1){
71 FD_ZERO(&fds);
72 FD_SET(0, &fds);
73 select(1, &fds, NULL, NULL, tv);
74 kill(pid, SIGALRM);
75 }
76 }
77 #endif
78
79 #ifdef HAVE_SIGACTION
80 /* XXX ugly hack, should perhaps use function from roken */
81 static RETSIGTYPE
fake_signal(int sig,RETSIGTYPE (* f)(int))82 (*fake_signal(int sig, RETSIGTYPE (*f)(int)))(int)
83 {
84 struct sigaction sa, osa;
85 sa.sa_handler = f;
86 sa.sa_flags = 0;
87 sigemptyset(&sa.sa_mask);
88 sigaction(sig, &sa, &osa);
89 return osa.sa_handler;
90 }
91 #define signal(S, F) fake_signal((S), (F))
92 #endif
93
94 #endif /* WIN32*/
95
96 /*
97 *
98 */
99
100 static void
timer_seed(const void * indata,int size)101 timer_seed(const void *indata, int size)
102 {
103 }
104
105 static int
timer_bytes(unsigned char * outdata,int size)106 timer_bytes(unsigned char *outdata, int size)
107 {
108 #ifdef WIN32
109 return 0;
110 #else /* WIN32 */
111 struct itimerval tv, otv;
112 RETSIGTYPE (*osa)(int);
113 int i, j;
114 #ifndef HAVE_SETITIMER
115 RETSIGTYPE (*ochld)(int);
116 pid_t pid;
117 #endif
118
119 gdata = outdata;
120 gsize = size;
121 igdata = 0;
122
123 osa = signal(SIGALRM, sigALRM);
124
125 /* Start timer */
126 tv.it_value.tv_sec = 0;
127 tv.it_value.tv_usec = 10 * 1000; /* 10 ms */
128 tv.it_interval = tv.it_value;
129 #ifdef HAVE_SETITIMER
130 setitimer(ITIMER_REAL, &tv, &otv);
131 #else
132 ochld = signal(SIGCHLD, SIG_IGN);
133 pid = fork();
134 if(pid == -1){
135 signal(SIGCHLD, ochld != SIG_ERR ? ochld : SIG_DFL);
136 des_not_rand_data(data, size);
137 return;
138 }
139 if(pid == 0)
140 pacemaker(&tv.it_interval);
141 #endif
142
143 for(i = 0; i < 4; i++) {
144 for (igdata = 0; igdata < size;) /* igdata++ in sigALRM */
145 counter++;
146 for (j = 0; j < size; j++) /* Only use 2 bits each lap */
147 gdata[j] = (gdata[j]>>2) | (gdata[j]<<6);
148 }
149 #ifdef HAVE_SETITIMER
150 setitimer(ITIMER_REAL, &otv, 0);
151 #else
152 kill(pid, SIGKILL);
153 while(waitpid(pid, NULL, 0) != pid);
154 signal(SIGCHLD, ochld != SIG_ERR ? ochld : SIG_DFL);
155 #endif
156 signal(SIGALRM, osa != SIG_ERR ? osa : SIG_DFL);
157
158 return 1;
159 #endif
160 }
161
162 static void
timer_cleanup(void)163 timer_cleanup(void)
164 {
165 }
166
167 static void
timer_add(const void * indata,int size,double entropi)168 timer_add(const void *indata, int size, double entropi)
169 {
170 }
171
172 static int
timer_pseudorand(unsigned char * outdata,int size)173 timer_pseudorand(unsigned char *outdata, int size)
174 {
175 return timer_bytes(outdata, size);
176 }
177
178 static int
timer_status(void)179 timer_status(void)
180 {
181 #ifdef WIN32
182 return 0;
183 #else
184 return 1;
185 #endif
186 }
187
188 #if defined(__GNUC__) || (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901)
189 const RAND_METHOD hc_rand_timer_method = {
190 .seed = timer_seed,
191 .bytes = timer_bytes,
192 .cleanup = timer_cleanup,
193 .add = timer_add,
194 .pseudorand = timer_pseudorand,
195 .status = timer_status
196 };
197 #else
198 const RAND_METHOD hc_rand_timer_method = {
199 timer_seed,
200 timer_bytes,
201 timer_cleanup,
202 timer_add,
203 timer_pseudorand,
204 timer_status
205 };
206 #endif
207
208 const RAND_METHOD *
RAND_timer_method(void)209 RAND_timer_method(void)
210 {
211 return &hc_rand_timer_method;
212 }
213