mod_s2s: Remove warning about hostname mismatch
[prosody.git] / util-src / crand.c
blob160ac1f68753ae99fa6bd8ec577c130fa9447e97
1 /* Prosody IM
2 -- Copyright (C) 2008-2017 Matthew Wild
3 -- Copyright (C) 2008-2017 Waqas Hussain
4 -- Copyright (C) 2016-2017 Kim Alvefur
5 --
6 -- This project is MIT/X11 licensed. Please see the
7 -- COPYING file in the source package for more information.
8 --
9 */
12 * crand.c
13 * C PRNG interface
15 * The purpose of this module is to provide access to a PRNG in
16 * environments without /dev/urandom
18 * Caution! This has not been extensively tested.
22 #define _DEFAULT_SOURCE
24 #include <stdlib.h>
25 #include <string.h>
26 #include <errno.h>
28 #include "lualib.h"
29 #include "lauxlib.h"
31 #if defined(WITH_GETRANDOM)
33 #ifndef __GLIBC_PREREQ
34 /* Not compiled with glibc at all */
35 #define __GLIBC_PREREQ(a,b) 0
36 #endif
38 #if ! __GLIBC_PREREQ(2,25)
39 /* Not compiled with a glibc that provides getrandom() */
40 #include <unistd.h>
41 #include <sys/syscall.h>
43 #ifndef SYS_getrandom
44 #error getrandom() requires Linux 3.17 or later
45 #endif
47 /* This wasn't present before glibc 2.25 */
48 int getrandom(void *buf, size_t buflen, unsigned int flags) {
49 return syscall(SYS_getrandom, buf, buflen, flags);
51 #else
52 #include <sys/random.h>
53 #endif
55 #elif defined(WITH_OPENSSL)
56 #include <openssl/rand.h>
57 #elif defined(WITH_ARC4RANDOM)
58 #ifdef __linux__
59 #include <bsd/stdlib.h>
60 #endif
61 #else
62 #error util.crand compiled without a random source
63 #endif
65 #ifndef SMALLBUFSIZ
66 #define SMALLBUFSIZ 32
67 #endif
69 int Lrandom(lua_State *L) {
70 char smallbuf[SMALLBUFSIZ];
71 char *buf = &smallbuf[0];
72 const lua_Integer l = luaL_checkinteger(L, 1);
73 const size_t len = l;
74 luaL_argcheck(L, l >= 0, 1, "must be > 0");
76 if(len == 0) {
77 lua_pushliteral(L, "");
78 return 1;
81 if(len > SMALLBUFSIZ) {
82 buf = lua_newuserdata(L, len);
85 #if defined(WITH_GETRANDOM)
87 * This acts like a read from /dev/urandom with the exception that it
88 * *does* block if the entropy pool is not yet initialized.
90 int left = len;
91 char *p = buf;
93 do {
94 int ret = getrandom(p, left, 0);
96 if(ret < 0) {
97 lua_pushstring(L, strerror(errno));
98 return lua_error(L);
101 p += ret;
102 left -= ret;
103 } while(left > 0);
105 #elif defined(WITH_ARC4RANDOM)
106 arc4random_buf(buf, len);
107 #elif defined(WITH_OPENSSL)
109 if(!RAND_status()) {
110 lua_pushliteral(L, "OpenSSL PRNG not seeded");
111 return lua_error(L);
114 if(RAND_bytes((unsigned char *)buf, len) != 1) {
115 /* TODO ERR_get_error() */
116 lua_pushstring(L, "RAND_bytes() failed");
117 return lua_error(L);
120 #endif
122 lua_pushlstring(L, buf, len);
123 return 1;
126 int luaopen_util_crand(lua_State *L) {
127 #if (LUA_VERSION_NUM > 501)
128 luaL_checkversion(L);
129 #endif
131 lua_createtable(L, 0, 2);
132 lua_pushcfunction(L, Lrandom);
133 lua_setfield(L, -2, "bytes");
135 #if defined(WITH_GETRANDOM)
136 lua_pushstring(L, "Linux");
137 #elif defined(WITH_ARC4RANDOM)
138 lua_pushstring(L, "arc4random()");
139 #elif defined(WITH_OPENSSL)
140 lua_pushstring(L, "OpenSSL");
141 #endif
142 lua_setfield(L, -2, "_source");
144 return 1;