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 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 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 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 101 timer_seed(const void *indata, int size) 102 { 103 } 104 105 static int 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 163 timer_cleanup(void) 164 { 165 } 166 167 static void 168 timer_add(const void *indata, int size, double entropi) 169 { 170 } 171 172 static int 173 timer_pseudorand(unsigned char *outdata, int size) 174 { 175 return timer_bytes(outdata, size); 176 } 177 178 static int 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 * 209 RAND_timer_method(void) 210 { 211 return &hc_rand_timer_method; 212 } 213