]> granicus.if.org Git - neomutt/commitdiff
Bye srandom() and random()
authorSami Farin <hvtaifwkbgefbaei@gmail.com>
Wed, 16 Oct 2013 18:34:57 +0000 (11:34 -0700)
committerRichard Russon <rich@flatcap.org>
Fri, 26 Feb 2016 16:36:03 +0000 (16:36 +0000)
Prefer getrandom on Linux, use /dev/urandom otherwise to
get entropy for MIME boundaries, message-id, Maildir filename,
temporary filename.  Using MUTT_RANDTAG_LEN (currently 16) base32
characters for boundaries and message-id.

globals.h
init.c
main.c
mh.c
muttlib.c
protos.h
sendlib.c

index e77030c71e252d8256d4e0a1d467cf7ae8a48a46..ceffe94b40d9b20951b8475c430eaa49996fd62b 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -191,8 +191,6 @@ unsigned char QuadOptions[(OPT_MAX*2 + 7) / 8];
 extern unsigned char QuadOptions[];
 #endif
 
-WHERE unsigned short Counter INITVAL (0);
-
 WHERE short ConnectTimeout;
 WHERE short HistSize;
 WHERE short MenuContext;
diff --git a/init.c b/init.c
index 118f06f534075562dbdfdc815936b7664329cdd3..8b0cfa83c962e60468da4d104405309d2bbf59c1 100644 (file)
--- a/init.c
+++ b/init.c
@@ -2867,23 +2867,6 @@ static int mutt_execute_commands (LIST *p)
   return 0;
 }
 
-static void mutt_srandom (void)
-{
-  struct timeval tv;
-  unsigned seed;
-
-  gettimeofday(&tv, NULL);
-  /* POSIX.1-2008 states that seed is 'unsigned' without specifying its width.
-   * Use as many of the lower order bits from the current time of day as the seed.
-   * If the upper bound is truncated, that is fine.
-   *
-   * tv_sec is integral of type integer or float.  Cast to 'long long' before
-   * bitshift in case it is a float.
-   */
-  seed = ((LONGLONG) tv.tv_sec << 20) | tv.tv_usec;
-  srandom(seed);
-}
-
 void mutt_init (int skip_sys_rc, LIST *commands)
 {
   struct passwd *pw;
@@ -2901,13 +2884,9 @@ void mutt_init (int skip_sys_rc, LIST *commands)
   ReverseAlias = hash_create (1031, 1);
   
   mutt_menu_init ();
-  mutt_srandom ();
 
-  /* 
-   * XXX - use something even more difficult to predict?
-   */
   snprintf (AttachmentMarker, sizeof (AttachmentMarker),
-           "\033]9;%ld\a", (long) time (NULL));
+           "\033]9;%" PRIu64 "\a", mutt_rand64());
   
   /* on one of the systems I use, getcwd() does not return the same prefix
      as is listed in the passwd file */
diff --git a/main.c b/main.c
index 17e8bf4cacad22a140f529f94d533b18a1209ca6..3b2d600c5933a3ff909991512662453fd8814005 100644 (file)
--- a/main.c
+++ b/main.c
@@ -595,7 +595,7 @@ int main (int argc, char **argv)
 
   mutt_error = mutt_nocurses_error;
   mutt_message = mutt_nocurses_error;
-  SRAND (time (NULL));
+  (void)mutt_rand32();
   umask (077);
 
   memset (Options, 0, sizeof (Options));
diff --git a/mh.c b/mh.c
index 63e12d2fb22a34137184f0314567381f413520b8..a0b529fccc0a86036c9ef142cf487a488f00916a 100644 (file)
--- a/mh.c
+++ b/mh.c
@@ -304,8 +304,8 @@ static int mh_mkstemp (CONTEXT * dest, FILE ** fp, char **tgt)
   omask = umask (mh_umask (dest));
   FOREVER
   {
-    snprintf (path, _POSIX_PATH_MAX, "%s/.mutt-%s-%d-%d",
-             dest->path, NONULL (Hostname), (int) getpid (), Counter++);
+    snprintf (path, _POSIX_PATH_MAX, "%s/.mutt-%s-%d-%" PRIu64,
+             dest->path, NONULL (Hostname), (int) getpid (), mutt_rand64());
     if ((fd = open (path, O_WRONLY | O_EXCL | O_CREAT, 0666)) == -1)
     {
       if (errno != EEXIST)
@@ -1313,9 +1313,9 @@ int maildir_open_new_message (MESSAGE * msg, CONTEXT * dest, HEADER * hdr)
   omask = umask (mh_umask (dest));
   FOREVER
   {
-    snprintf (path, _POSIX_PATH_MAX, "%s/tmp/%s.%lld.%u_%d.%s%s",
-             dest->path, subdir, (long long)time (NULL), (unsigned int)getpid (),
-             Counter++, NONULL (Hostname), suffix);
+    snprintf (path, _POSIX_PATH_MAX, "%s/tmp/%s.%lld.R%" PRIu64 ".%s%s",
+             dest->path, subdir, (long long)time (NULL), mutt_rand64(),
+              NONULL (Hostname), suffix);
 
     dprint (2, (debugfile, "maildir_open_new_message (): Trying %s.\n",
                path));
@@ -1399,8 +1399,8 @@ int maildir_commit_message (CONTEXT * ctx, MESSAGE * msg, HEADER * hdr)
   /* construct a new file name. */
   FOREVER
   {
-    snprintf (path, _POSIX_PATH_MAX, "%s/%lld.%u_%d.%s%s", subdir,
-             (long long)time (NULL), (unsigned int)getpid (), Counter++,
+    snprintf (path, _POSIX_PATH_MAX, "%s/%lld.R%" PRIu64 ".%s%s", subdir,
+             (long long)time (NULL), mutt_rand64(),
              NONULL (Hostname), suffix);
     snprintf (full, _POSIX_PATH_MAX, "%s/%s", ctx->path, path);
 
index 02067cce2ecf9bc79c69bf8a36bbeb3abdab0db9..ba51a34fc08422c6069dbd2f301b5c23511bd17d 100644 (file)
--- a/muttlib.c
+++ b/muttlib.c
@@ -37,6 +37,7 @@
 #include <string.h>
 #include <ctype.h>
 #include <unistd.h>
+#include <sys/syscall.h>
 #include <stdlib.h>
 #include <sys/wait.h>
 #include <errno.h>
@@ -771,12 +772,79 @@ void mutt_merge_envelopes(ENVELOPE* base, ENVELOPE** extra)
   mutt_free_envelope(extra);
 }
 
+static FILE *frandom;
+
+void mutt_randbuf(void *out, size_t len)
+{
+  if (len > 1048576) {
+    mutt_error (_("mutt_randbuf len=%zu"), len);
+    exit(1);
+  }
+  /* XXX switch to HAVE_GETRANDOM and getrandom() in about 2017 */
+#if defined(SYS_getrandom) && defined(__linux__)
+  static int whined;
+  long ret;
+  do {
+    ret = syscall(SYS_getrandom, out, len, 0, 0, 0, 0);
+  } while ((ret == -1) && (errno == EINTR));
+  if (ret == len) return;
+  if (!whined) {
+    mutt_error (_("getrandom failed: %s"), strerror(errno));
+    mutt_sleep (1);
+    whined = 1;
+  }
+  /* let's try urandom in case user has configured selinux or something
+   * to not allow getrandom */
+#endif
+  if (frandom == NULL) {
+    frandom = fopen("/dev/urandom", "rb");
+    if (frandom == NULL) {
+      mutt_error (_("open /dev/urandom: %s"), strerror(errno));
+      exit(1);
+    }
+    setbuf(frandom, NULL);
+  }
+  if (fread(out, 1, len, frandom) != len) {
+    mutt_error (_("read /dev/urandom: %s"), strerror(errno));
+    exit(1);
+  }
+}
+
+static const unsigned char base32[] = "abcdefghijklmnopqrstuvwxyz234567";
+
+void mutt_rand_base32(void *out, size_t len)
+{
+  size_t pos;
+  uint8_t *p = out;
+
+  mutt_randbuf(p, len);
+  for (pos = 0; pos < len; pos++)
+    p[pos] = base32[p[pos] % 32];
+}
+
+uint32_t mutt_rand32(void)
+{
+  uint32_t ret;
+
+  mutt_randbuf(&ret, sizeof(ret));
+  return ret;
+}
+
+uint64_t mutt_rand64(void)
+{
+  uint64_t ret;
+
+  mutt_randbuf(&ret, sizeof(ret));
+  return ret;
+}
+
+
 void _mutt_mktemp (char *s, size_t slen, const char *prefix, const char *suffix,
                    const char *src, int line)
 {
-  size_t n = snprintf (s, slen, "%s/%s-%s-%d-%d-%ld%ld%s%s",
+  size_t n = snprintf (s, slen, "%s/%s-%s-%d-%d-%" PRIu64 "%s%s",
       NONULL (Tempdir), NONULL (prefix), NONULL (Hostname),
-      (int) getuid (), (int) getpid (), random (), random (),
+      (int) getuid (), (int) getpid (), mutt_rand64(),
       suffix ? "." : "", NONULL (suffix));
   if (n >= slen)
     dprint (1, (debugfile, "%s:%d: ERROR: insufficient buffer space to hold temporary filename! slen=%zu but need %zu\n",
index b21ef2976e3dee1795d2ea2a93d72ed499b0b875..04a797288b46b34b857d68ac0932067fc71d8573 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -375,6 +375,11 @@ int mutt_yesorno (const char *, int);
 void mutt_set_header_color(CONTEXT *, HEADER *);
 void mutt_sleep (short);
 int mutt_save_confirm (const char  *, struct stat *);
+void mutt_randbuf(void *out, size_t len);
+#define MUTT_RANDTAG_LEN (16)
+void mutt_rand_base32(void *out, size_t len);
+uint32_t mutt_rand32(void);
+uint64_t mutt_rand64(void);
 
 int mh_valid_message (const char *);
 
@@ -422,16 +427,6 @@ void mutt_pattern_free (pattern_t **pat);
 #define LONGLONG long
 #endif
 
-#ifdef HAVE_SRAND48
-#define LRAND lrand48
-#define SRAND srand48
-#define DRAND drand48
-#else
-#define LRAND rand
-#define SRAND srand
-#define DRAND (double)rand
-#endif /* HAVE_SRAND48 */
-
 /* HP-UX, ConvexOS and UNIXware don't have this macro */
 #ifndef S_ISLNK
 #define S_ISLNK(x) (((x) & S_IFMT) == S_IFLNK ? 1 : 0)
index 14a58b54c437baca5bb1eab3228d8a98552b659f..446f6146d11dc5ae2ab7e7e144aecfb9afa867d1 100644 (file)
--- a/sendlib.c
+++ b/sendlib.c
@@ -73,8 +73,6 @@ const char B64Chars[64] = {
   '8', '9', '+', '/'
 };
 
-static char MsgIdPfx = 'A';
-
 static void transform_to_7bit (BODY *a, FILE *fpin);
 
 static void encode_quoted (FGETCONV * fc, FILE *fout, int istext)
@@ -480,18 +478,12 @@ int mutt_write_mime_body (BODY *a, FILE *f)
 
 #undef write_as_text_part
 
-#define BOUNDARYLEN 16
 void mutt_generate_boundary (PARAMETER **parm)
 {
-  char rs[BOUNDARYLEN + 1];
-  char *p = rs;
-  int i;
-
-  rs[BOUNDARYLEN] = 0;
-  for (i=0;i<BOUNDARYLEN;i++)
-    *p++ = B64Chars[LRAND() % sizeof (B64Chars)];
-  *p = 0;
+  char rs[MUTT_RANDTAG_LEN + 1];
 
+  mutt_rand_base32(rs, sizeof(rs) - 1);
+  rs[MUTT_RANDTAG_LEN] = 0;
   mutt_set_parameter ("boundary", rs, parm);
 }
 
@@ -2133,16 +2125,18 @@ char *mutt_gen_msgid (void)
   time_t now;
   struct tm *tm;
   const char *fqdn;
+  unsigned char rndid[MUTT_RANDTAG_LEN + 1];
 
+  mutt_rand_base32(rndid, sizeof(rndid) - 1);
+  rndid[MUTT_RANDTAG_LEN] = 0;
   now = time (NULL);
   tm = gmtime (&now);
   if(!(fqdn = mutt_fqdn(0)))
     fqdn = NONULL(Hostname);
 
-  snprintf (buf, sizeof (buf), "<%d%02d%02d%02d%02d%02d.G%c%u@%s>",
+  snprintf (buf, sizeof (buf), "<%d%02d%02d%02d%02d%02d.%s@%s>",
            tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour,
-           tm->tm_min, tm->tm_sec, MsgIdPfx, (unsigned int)getpid (), fqdn);
-  MsgIdPfx = (MsgIdPfx == 'Z') ? 'A' : MsgIdPfx + 1;
+           tm->tm_min, tm->tm_sec, rndid, fqdn);
   return (safe_strdup (buf));
 }