s4:heimdal: import lorikeet-heimdal-200906080040 (commit 904d0124b46eed7a8ad6e5b73e89...
[samba.git] / source4 / heimdal / lib / hcrypto / rand-unix.c
index 0c2185776c873700fc0db73e40ecd28b4de00acb..07d81eb62041a45ec150da1ec45a3829a1a2e508 100644 (file)
@@ -40,11 +40,15 @@ RCSID("$Id$");
 #include <stdio.h>
 #include <stdlib.h>
 #include <rand.h>
+#include <heim_threads.h>
 
 #include <roken.h>
 
 #include "randi.h"
 
+static int random_fd = -1;
+static HEIMDAL_MUTEX random_mutex = HEIMDAL_MUTEX_INITIALIZER;
+
 /*
  * Unix /dev/random
  */
@@ -88,31 +92,47 @@ unix_seed(const void *indata, int size)
 
 }
 
+
 static int
 unix_bytes(unsigned char *outdata, int size)
 {
     ssize_t count;
-    int fd;
+    int once = 0;
 
     if (size <= 0)
        return 0;
 
-    fd = get_device_fd(O_RDONLY);
-    if (fd < 0)
-       return 0;
+    HEIMDAL_MUTEX_lock(&random_mutex);
+    if (random_fd == -1) {
+    retry:
+       random_fd = get_device_fd(O_RDONLY);
+       if (random_fd < 0) {
+           HEIMDAL_MUTEX_unlock(&random_mutex);
+           return 0;
+       }
+    }
 
     while (size > 0) {
-       count = read (fd, outdata, size);
-       if (count < 0 && errno == EINTR)
-           continue;
-       else if (count <= 0) {
-           close(fd);
+       HEIMDAL_MUTEX_unlock(&random_mutex);
+       count = read (random_fd, outdata, size);
+       HEIMDAL_MUTEX_lock(&random_mutex);
+       if (random_fd < 0) {
+           if (errno == EINTR)
+               continue;
+           else if (errno == EBADF && once++ == 0) {
+               close(random_fd);
+               random_fd = -1;
+               goto retry;
+           }
+           return 0;
+       } else if (count <= 0) {
+           HEIMDAL_MUTEX_unlock(&random_mutex);
            return 0;
        }
        outdata += count;
        size -= count;
     }
-    close(fd);
+    HEIMDAL_MUTEX_unlock(&random_mutex);
 
     return 1;
 }