util.crand: Silence compiler warning
[prosody.git] / util-src / crand.c
1 /* Prosody IM
2 -- Copyright (C) 2008-2016 Matthew Wild
3 -- Copyright (C) 2008-2016 Waqas Hussain
4 -- Copyright (C) 2016 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 */
10
11 /*
12 * crand.c
13 * C PRNG interface
14 */
15
16 #include "lualib.h"
17 #include "lauxlib.h"
18
19 #include <string.h>
20 #include <errno.h>
21
22 /*
23  * TODO: Decide on fixed size or dynamically allocated buffer
24  */
25 #if 1
26 #include <stdlib.h>
27 #else
28 #define BUFLEN 256
29 #endif
30
31 #if defined(WITH_GETRANDOM)
32 #include <unistd.h>
33 #include <sys/syscall.h>
34 #include <linux/random.h>
35
36 #ifndef SYS_getrandom
37 #error getrandom() requires Linux 3.17 or later
38 #endif
39
40 /* Was this not supposed to be a function? */
41 int getrandom(char *buf, size_t len, int flags) {
42         return syscall(SYS_getrandom, buf, len, flags);
43 }
44
45 #elif defined(WITH_ARC4RANDOM)
46 #include <stdlib.h>
47 #elif defined(WITH_OPENSSL)
48 #include <openssl/rand.h>
49 #else
50 #error util.crand compiled without a random source
51 #endif
52
53 int Lrandom(lua_State *L) {
54 #ifdef BUFLEN
55         unsigned char buf[BUFLEN];
56 #else
57         unsigned char *buf;
58 #endif
59         int ret = 0;
60         size_t len = (size_t)luaL_checkint(L, 1);
61 #ifdef BUFLEN
62         len = len > BUFLEN ? BUFLEN : len;
63 #else
64         buf = malloc(len);
65
66         if(buf == NULL) {
67                 lua_pushnil(L);
68                 lua_pushstring(L, "out of memory");
69                 /* or it migth be better to
70                  * return lua_error(L);
71                  */
72                 return 2;
73         }
74 #endif
75
76 #if defined(WITH_GETRANDOM)
77         ret = getrandom(buf, len, 0);
78
79         if(ret < 0) {
80 #ifndef BUFLEN
81                 free(buf);
82 #endif
83                 lua_pushnil(L);
84                 lua_pushstring(L, strerror(errno));
85                 lua_pushinteger(L, errno);
86                 return 3;
87         }
88
89 #elif defined(WITH_ARC4RANDOM)
90         arc4random_buf(buf, len);
91         ret = len;
92 #elif defined(WITH_OPENSSL)
93         ret = RAND_bytes(buf, len);
94
95         if(ret == 1) {
96                 ret = len;
97         } else {
98 #ifndef BUFLEN
99                 free(buf);
100 #endif
101                 lua_pushnil(L);
102                 lua_pushstring(L, "failed");
103                 /* lua_pushinteger(L, ERR_get_error()); */
104                 return 2;
105         }
106
107 #endif
108
109         lua_pushlstring(L, (const char *)buf, ret);
110 #ifndef BUFLEN
111         free(buf);
112 #endif
113         return 1;
114 }
115
116 #ifdef ENABLE_SEEDING
117 int Lseed(lua_State *L) {
118         size_t len;
119         const char *seed = lua_tolstring(L, 1, &len);
120
121 #if defined(WITH_OPENSSL)
122         RAND_add(seed, len, len);
123         return 0;
124 #else
125         lua_pushnil(L);
126         lua_pushliteral(L, "not-supported");
127         return 2;
128 #endif
129 }
130 #endif
131
132 int luaopen_util_crand(lua_State *L) {
133         lua_newtable(L);
134         lua_pushcfunction(L, Lrandom);
135         lua_setfield(L, -2, "bytes");
136 #ifdef ENABLE_SEEDING
137         lua_pushcfunction(L, Lseed);
138         lua_setfield(L, -2, "seed");
139 #endif
140
141 #if defined(WITH_GETRANDOM)
142         lua_pushstring(L, "Linux");
143 #elif defined(WITH_ARC4RANDOM)
144         lua_pushstring(L, "arc4random()");
145 #elif defined(WITH_OPENSSL)
146         lua_pushstring(L, "OpenSSL");
147 #endif
148         lua_setfield(L, -2, "_source");
149
150 #if defined(WITH_OPENSSL) && defined(_WIN32)
151         /* Do we need to seed this on Windows? */
152 #endif
153
154         return 1;
155 }
156