tom 2009/10/16 10:10:40 BST
Modified files:
exim-src/src expand.c functions.h host.c tls-openssl.c
Log:
Bugzilla #722
Revision Changes Path
1.104 +86 -0 exim/exim-src/src/expand.c
1.46 +1 -0 exim/exim-src/src/functions.h
1.30 +5 -0 exim/exim-src/src/host.c
1.17 +71 -3 exim/exim-src/src/tls-openssl.c
Index: expand.c
===================================================================
RCS file: /home/cvs/exim/exim-src/src/expand.c,v
retrieving revision 1.103
retrieving revision 1.104
diff -u -r1.103 -r1.104
--- expand.c 15 Oct 2009 08:27:37 -0000 1.103
+++ expand.c 16 Oct 2009 09:10:40 -0000 1.104
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/exim-src/src/expand.c,v 1.103 2009/10/15 08:27:37 tom Exp $ */
+/* $Cambridge: exim/exim-src/src/expand.c,v 1.104 2009/10/16 09:10:40 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -187,6 +187,7 @@
US"nh",
US"nhash",
US"quote",
+ US"randint",
US"rfc2047",
US"rfc2047d",
US"rxquote",
@@ -219,6 +220,7 @@
EOP_NH,
EOP_NHASH,
EOP_QUOTE,
+ EOP_RANDINT,
EOP_RFC2047,
EOP_RFC2047D,
EOP_RXQUOTE,
@@ -760,6 +762,75 @@
/*************************************************
+* Pseudo-random number generation *
+*************************************************/
+
+/* Pseudo-random number generation. The result is not "expected" to be
+cryptographically strong but not so weak that someone will shoot themselves
+in the foot using it as a nonce in some email header scheme or whatever
+weirdness they'll twist this into. The result should ideally handle fork().
+
+However, if we're stuck unable to provide this, then we'll fall back to
+appallingly bad randomness.
+
+If SUPPORT_TLS is defined and OpenSSL is used, then this will not be used.
+The GNUTLS randomness functions found do not seem amenable to extracting
+random numbers outside of a TLS context. Any volunteers?
+
+Arguments:
+ max range maximum
+Returns a random number in range [0, max-1]
+*/
+
+#if !defined(SUPPORT_TLS) || defined(USE_GNUTLS)
+int
+pseudo_random_number(int max)
+{
+ static pid_t pid = 0;
+ pid_t p2;
+#if defined(HAVE_SRANDOM) && !defined(HAVE_SRANDOMDEV)
+ struct timeval tv;
+#endif
+
+ p2 = getpid();
+ if (p2 != pid)
+ {
+ if (pid != 0)
+ {
+
+#ifdef HAVE_ARC4RANDOM
+ /* cryptographically strong randomness, common on *BSD platforms, not
+ so much elsewhere. Alas. */
+ arc4random_stir();
+#elif defined(HAVE_SRANDOM) || defined(HAVE_SRANDOMDEV)
+#ifdef HAVE_SRANDOMDEV
+ /* uses random(4) for seeding */
+ srandomdev();
+#else
+ gettimeofday(&tv, NULL);
+ srandom(tv.tv_sec | tv.tv_usec | getpid());
+#endif
+#else
+ /* Poor randomness and no seeding here */
+#endif
+
+ }
+ pid = p2;
+ }
+
+#ifdef HAVE_ARC4RANDOM
+ return arc4random() % max;
+#elif defined(HAVE_SRANDOM) || defined(HAVE_SRANDOMDEV)
+ return random() % max;
+#else
+ /* This one returns a 16-bit number, definitely not crypto-strong */
+ return random_number(max);
+#endif
+}
+
+#endif
+
+/*************************************************
* Pick out a name from a string *
*************************************************/
@@ -5704,6 +5775,21 @@
continue;
}
+ /* pseudo-random number less than N */
+
+ case EOP_RANDINT:
+ {
+ int max;
+ uschar *s;
+
+ max = expand_string_integer(sub, TRUE);
+ if (expand_string_message != NULL)
+ goto EXPAND_FAILED;
+ s = string_sprintf("%d", pseudo_random_number(max));
+ yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
+ continue;
+ }
+
/* Unknown operator */
default:
Index: functions.h
===================================================================
RCS file: /home/cvs/exim/exim-src/src/functions.h,v
retrieving revision 1.45
retrieving revision 1.46
diff -u -r1.45 -r1.46
--- functions.h 14 Oct 2009 13:52:48 -0000 1.45
+++ functions.h 16 Oct 2009 09:10:40 -0000 1.46
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/exim-src/src/functions.h,v 1.45 2009/10/14 13:52:48 nm4 Exp $ */
+/* $Cambridge: exim/exim-src/src/functions.h,v 1.46 2009/10/16 09:10:40 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -190,6 +190,7 @@
extern uschar *parse_message_id(uschar *, uschar **, uschar **);
extern uschar *parse_quote_2047(uschar *, int, uschar *, uschar *, int, BOOL);
extern uschar *parse_date_time(uschar *str, time_t *t);
+extern int pseudo_random_number(int);
extern BOOL queue_action(uschar *, int, uschar **, int, int);
extern void queue_check_only(void);
Index: host.c
===================================================================
RCS file: /home/cvs/exim/exim-src/src/host.c,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -r1.29 -r1.30
--- host.c 18 Oct 2007 12:01:00 -0000 1.29
+++ host.c 16 Oct 2009 09:10:40 -0000 1.30
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/exim-src/src/host.c,v 1.29 2007/10/18 12:01:00 nm4 Exp $ */
+/* $Cambridge: exim/exim-src/src/host.c,v 1.30 2009/10/16 09:10:40 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -70,6 +70,9 @@
very good for the uses to which it is put. When running the regression tests,
start with a fixed seed.
+If you need better, see pseudo_random_number() which is potentially stronger,
+if a crypto library is available, but might end up just calling this instead.
+
Arguments:
limit: one more than the largest number required
@@ -79,6 +82,8 @@
int
random_number(int limit)
{
+if (limit < 1)
+ return 0;
if (random_seed == 0)
{
if (running_in_test_harness) random_seed = 42; else
Index: tls-openssl.c
===================================================================
RCS file: /home/cvs/exim/exim-src/src/tls-openssl.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -r1.16 -r1.17
--- tls-openssl.c 16 Oct 2009 08:34:50 -0000 1.16
+++ tls-openssl.c 16 Oct 2009 09:10:40 -0000 1.17
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/exim-src/src/tls-openssl.c,v 1.16 2009/10/16 08:34:50 tom Exp $ */
+/* $Cambridge: exim/exim-src/src/tls-openssl.c,v 1.17 2009/10/16 09:10:40 tom Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -26,8 +26,8 @@
/* Structure for collecting random data for seeding. */
typedef struct randstuff {
- time_t t;
- pid_t p;
+ struct timeval tv;
+ pid_t p;
} randstuff;
/* Local static variables */
@@ -327,7 +327,7 @@
if (!RAND_status())
{
randstuff r;
- r.t = time(NULL);
+ gettimeofday(&r.tv, NULL);
r.p = getpid();
RAND_seed((uschar *)(&r), sizeof(r));
@@ -1053,4 +1053,72 @@
fprintf(f, "OpenSSL runtime version: %s\n", SSLeay_version(SSLEAY_VERSION));
}
+
+
+
+/*************************************************
+* Pseudo-random number generation *
+*************************************************/
+
+/* Pseudo-random number generation. The result is not expected to be
+cryptographically strong but not so weak that someone will shoot themselves
+in the foot using it as a nonce in input in some email header scheme or
+whatever weirdness they'll twist this into. The result should handle fork()
+and avoid repeating sequences. OpenSSL handles that for us.
+
+Arguments:
+ max range maximum
+Returns a random number in range [0, max-1]
+*/
+
+int
+pseudo_random_number(int max)
+{
+unsigned int r;
+int i, needed_len;
+uschar *p;
+uschar smallbuf[sizeof(r)];
+
+if (max <= 1)
+ return 0;
+
+/* OpenSSL auto-seeds from /dev/random, etc, but this a double-check. */
+if (!RAND_status())
+ {
+ randstuff r;
+ gettimeofday(&r.tv, NULL);
+ r.p = getpid();
+
+ RAND_seed((uschar *)(&r), sizeof(r));
+ }
+/* We're after pseudo-random, not random; if we still don't have enough data
+in the internal PRNG then our options are limited. We could sleep and hope
+for entropy to come along (prayer technique) but if the system is so depleted
+in the first place then something is likely to just keep taking it. Instead,
+we'll just take whatever little bit of pseudo-random we can still manage to
+get. */
+
+needed_len = sizeof(r);
+/* Don't take 8 times more entropy than needed if int is 8 octets and we were
+asked for a number less than 10. */
+for (r = max, i = 0; r; ++i)
+ r >>= 1;
+i = (i + 7) / 8;
+if (i < needed_len)
+ needed_len = i;
+
+/* We do not care if crypto-strong */
+(void) RAND_pseudo_bytes(smallbuf, needed_len);
+r = 0;
+for (p = smallbuf; needed_len; --needed_len, ++p)
+ {
+ r *= 256;
+ r += *p;
+ }
+
+/* We don't particularly care about weighted results; if someone wants
+smooth distribution and cares enough then they should submit a patch then. */
+return r % max;
+}
+
/* End of tls-openssl.c */