summaryrefslogtreecommitdiff
path: root/openbsd-compat
diff options
context:
space:
mode:
Diffstat (limited to 'openbsd-compat')
-rw-r--r--openbsd-compat/Makefile.in4
-rw-r--r--openbsd-compat/bsd-err.c6
-rw-r--r--openbsd-compat/bsd-getpagesize.c23
-rw-r--r--openbsd-compat/bsd-malloc.c55
-rw-r--r--openbsd-compat/bsd-misc.c10
-rw-r--r--openbsd-compat/bsd-misc.h4
-rw-r--r--openbsd-compat/explicit_bzero.c4
-rw-r--r--openbsd-compat/fmt_scaled.c18
-rw-r--r--openbsd-compat/freezero.c29
-rw-r--r--openbsd-compat/openbsd-compat.h12
-rw-r--r--openbsd-compat/port-tun.c93
-rw-r--r--openbsd-compat/port-tun.h5
-rw-r--r--openbsd-compat/recallocarray.c90
13 files changed, 297 insertions, 56 deletions
diff --git a/openbsd-compat/Makefile.in b/openbsd-compat/Makefile.in
index d51eacf65..ac8ae4305 100644
--- a/openbsd-compat/Makefile.in
+++ b/openbsd-compat/Makefile.in
@@ -16,9 +16,9 @@ RANLIB=@RANLIB@
16INSTALL=@INSTALL@ 16INSTALL=@INSTALL@
17LDFLAGS=-L. @LDFLAGS@ 17LDFLAGS=-L. @LDFLAGS@
18 18
19OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt_long.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o reallocarray.o realpath.o rresvport.o setenv.o setproctitle.o sha1.o sha2.o rmd160.o md5.o sigact.o strcasestr.o strlcat.o strlcpy.o strmode.o strnlen.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o strtoull.o timingsafe_bcmp.o vis.o blowfish.o bcrypt_pbkdf.o explicit_bzero.o 19OPENBSD=base64.o basename.o bcrypt_pbkdf.o bindresvport.o blowfish.o daemon.o dirname.o fmt_scaled.o getcwd.o getgrouplist.o getopt_long.o getrrsetbyname.o glob.o inet_aton.o inet_ntoa.o inet_ntop.o mktemp.o pwcache.o readpassphrase.o reallocarray.o realpath.o recallocarray.o rresvport.o setenv.o setproctitle.o sha1.o sha2.o rmd160.o md5.o sigact.o strcasestr.o strlcat.o strlcpy.o strmode.o strnlen.o strptime.o strsep.o strtonum.o strtoll.o strtoul.o strtoull.o timingsafe_bcmp.o vis.o blowfish.o bcrypt_pbkdf.o explicit_bzero.o freezero.o
20 20
21COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-err.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xcrypt.o kludge-fd_set.o 21COMPAT=arc4random.o bsd-asprintf.o bsd-closefrom.o bsd-cray.o bsd-cygwin_util.o bsd-getpeereid.o getrrsetbyname-ldns.o bsd-err.o bsd-getpagesize.o bsd-misc.o bsd-nextstep.o bsd-openpty.o bsd-poll.o bsd-malloc.o bsd-setres_id.o bsd-snprintf.o bsd-statvfs.o bsd-waitpid.o fake-rfc2553.o openssl-compat.o xcrypt.o kludge-fd_set.o
22 22
23PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o 23PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
24 24
diff --git a/openbsd-compat/bsd-err.c b/openbsd-compat/bsd-err.c
index ab10646f0..e4ed22b86 100644
--- a/openbsd-compat/bsd-err.c
+++ b/openbsd-compat/bsd-err.c
@@ -27,6 +27,12 @@
27 27
28#include "includes.h" 28#include "includes.h"
29 29
30#include <errno.h>
31#include <stdarg.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <string.h>
35
30#ifndef HAVE_ERR 36#ifndef HAVE_ERR
31void 37void
32err(int r, const char *fmt, ...) 38err(int r, const char *fmt, ...)
diff --git a/openbsd-compat/bsd-getpagesize.c b/openbsd-compat/bsd-getpagesize.c
new file mode 100644
index 000000000..9daddfbd3
--- /dev/null
+++ b/openbsd-compat/bsd-getpagesize.c
@@ -0,0 +1,23 @@
1/* Placed in the public domain */
2
3#ifndef HAVE_GETPAGESIZE
4
5#include <unistd.h>
6#include <limits.h>
7
8int
9getpagesize(void)
10{
11#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
12 long r = sysconf(_SC_PAGESIZE);
13 if (r > 0 && r < INT_MAX)
14 return (int)r;
15#endif
16 /*
17 * This is at the lower end of common values and appropriate for
18 * our current use of getpagesize() in recallocarray().
19 */
20 return 4096;
21}
22
23#endif /* HAVE_GETPAGESIZE */
diff --git a/openbsd-compat/bsd-malloc.c b/openbsd-compat/bsd-malloc.c
new file mode 100644
index 000000000..6402ab588
--- /dev/null
+++ b/openbsd-compat/bsd-malloc.c
@@ -0,0 +1,55 @@
1/*
2 * Copyright (c) 2017 Darren Tucker (dtucker at zip com au).
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "config.h"
18#undef malloc
19#undef calloc
20#undef realloc
21
22#include <sys/types.h>
23#include <stdlib.h>
24
25#if defined(HAVE_MALLOC) && HAVE_MALLOC == 0
26void *
27rpl_malloc(size_t size)
28{
29 if (size == 0)
30 size = 1;
31 return malloc(size);
32}
33#endif
34
35#if defined(HAVE_CALLOC) && HAVE_CALLOC == 0
36void *
37rpl_calloc(size_t nmemb, size_t size)
38{
39 if (nmemb == 0)
40 nmemb = 1;
41 if (size == 0)
42 size = 1;
43 return calloc(nmemb, size);
44}
45#endif
46
47#if defined (HAVE_REALLOC) && HAVE_REALLOC == 0
48void *
49rpl_realloc(void *ptr, size_t size)
50{
51 if (size == 0)
52 size = 1;
53 return realloc(ptr, size);
54}
55#endif
diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c
index cfd73260a..29f6ad38c 100644
--- a/openbsd-compat/bsd-misc.c
+++ b/openbsd-compat/bsd-misc.c
@@ -104,6 +104,16 @@ const char *strerror(int e)
104} 104}
105#endif 105#endif
106 106
107#if !defined(HAVE_STRSIGNAL)
108char *strsignal(int sig)
109{
110 static char buf[16];
111
112 (void)snprintf(buf, sizeof(buf), "%d", sig);
113 return buf;
114}
115#endif
116
107#ifndef HAVE_UTIMES 117#ifndef HAVE_UTIMES
108int utimes(char *filename, struct timeval *tvp) 118int utimes(char *filename, struct timeval *tvp)
109{ 119{
diff --git a/openbsd-compat/bsd-misc.h b/openbsd-compat/bsd-misc.h
index 70a538f04..0b1a3504f 100644
--- a/openbsd-compat/bsd-misc.h
+++ b/openbsd-compat/bsd-misc.h
@@ -49,6 +49,10 @@ int setegid(uid_t);
49const char *strerror(int); 49const char *strerror(int);
50#endif 50#endif
51 51
52#if !defined(HAVE_STRSIGNAL)
53char *strsignal(int);
54#endif
55
52#if !defined(HAVE_SETLINEBUF) 56#if !defined(HAVE_SETLINEBUF)
53#define setlinebuf(a) (setvbuf((a), NULL, _IOLBF, 0)) 57#define setlinebuf(a) (setvbuf((a), NULL, _IOLBF, 0))
54#endif 58#endif
diff --git a/openbsd-compat/explicit_bzero.c b/openbsd-compat/explicit_bzero.c
index 5078134d1..53a003472 100644
--- a/openbsd-compat/explicit_bzero.c
+++ b/openbsd-compat/explicit_bzero.c
@@ -20,6 +20,8 @@
20void 20void
21explicit_bzero(void *p, size_t n) 21explicit_bzero(void *p, size_t n)
22{ 22{
23 if (n == 0)
24 return;
23 (void)memset_s(p, n, 0, n); 25 (void)memset_s(p, n, 0, n);
24} 26}
25 27
@@ -34,6 +36,8 @@ static void (* volatile ssh_bzero)(void *, size_t) = bzero;
34void 36void
35explicit_bzero(void *p, size_t n) 37explicit_bzero(void *p, size_t n)
36{ 38{
39 if (n == 0)
40 return;
37 /* 41 /*
38 * clang -fsanitize=memory needs to intercept memset-like functions 42 * clang -fsanitize=memory needs to intercept memset-like functions
39 * to correctly detect memory initialisation. Make sure one is called 43 * to correctly detect memory initialisation. Make sure one is called
diff --git a/openbsd-compat/fmt_scaled.c b/openbsd-compat/fmt_scaled.c
index e5533b2de..7c5193e26 100644
--- a/openbsd-compat/fmt_scaled.c
+++ b/openbsd-compat/fmt_scaled.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: fmt_scaled.c,v 1.13 2017/03/11 23:37:23 djm Exp $ */ 1/* $OpenBSD: fmt_scaled.c,v 1.16 2017/03/16 02:40:46 dtucker Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved. 4 * Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved.
@@ -125,22 +125,30 @@ scan_scaled(char *scaled, long long *result)
125 /* ignore extra fractional digits */ 125 /* ignore extra fractional digits */
126 continue; 126 continue;
127 fract_digits++; /* for later scaling */ 127 fract_digits++; /* for later scaling */
128 if (fpart >= LLONG_MAX / 10) { 128 if (fpart > LLONG_MAX / 10) {
129 errno = ERANGE; 129 errno = ERANGE;
130 return -1; 130 return -1;
131 } 131 }
132 fpart *= 10; 132 fpart *= 10;
133 if (i > LLONG_MAX - fpart) {
134 errno = ERANGE;
135 return -1;
136 }
133 fpart += i; 137 fpart += i;
134 } else { /* normal digit */ 138 } else { /* normal digit */
135 if (++ndigits >= MAX_DIGITS) { 139 if (++ndigits >= MAX_DIGITS) {
136 errno = ERANGE; 140 errno = ERANGE;
137 return -1; 141 return -1;
138 } 142 }
139 if (whole >= LLONG_MAX / 10) { 143 if (whole > LLONG_MAX / 10) {
140 errno = ERANGE; 144 errno = ERANGE;
141 return -1; 145 return -1;
142 } 146 }
143 whole *= 10; 147 whole *= 10;
148 if (i > LLONG_MAX - whole) {
149 errno = ERANGE;
150 return -1;
151 }
144 whole += i; 152 whole += i;
145 } 153 }
146 } 154 }
@@ -170,7 +178,9 @@ scan_scaled(char *scaled, long long *result)
170 } 178 }
171 scale_fact = scale_factors[i]; 179 scale_fact = scale_factors[i];
172 180
173 if (whole >= LLONG_MAX / scale_fact) { 181 /* check for overflow and underflow after scaling */
182 if (whole > LLONG_MAX / scale_fact ||
183 whole < LLONG_MIN / scale_fact) {
174 errno = ERANGE; 184 errno = ERANGE;
175 return -1; 185 return -1;
176 } 186 }
diff --git a/openbsd-compat/freezero.c b/openbsd-compat/freezero.c
new file mode 100644
index 000000000..3af8f4a73
--- /dev/null
+++ b/openbsd-compat/freezero.c
@@ -0,0 +1,29 @@
1/*
2 * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek <otto@drijf.net>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "includes.h"
18
19#ifndef HAVE_FREEZERO
20
21void
22freezero(void *ptr, size_t sz)
23{
24 explicit_bzero(ptr, sz);
25 free(ptr);
26}
27
28#endif /* HAVE_FREEZERO */
29
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
index cff547745..cac799e84 100644
--- a/openbsd-compat/openbsd-compat.h
+++ b/openbsd-compat/openbsd-compat.h
@@ -60,6 +60,10 @@ int bindresvport_sa(int sd, struct sockaddr *sa);
60void closefrom(int); 60void closefrom(int);
61#endif 61#endif
62 62
63#ifndef HAVE_GETPAGESIZE
64int getpagesize(void);
65#endif
66
63#ifndef HAVE_GETCWD 67#ifndef HAVE_GETCWD
64char *getcwd(char *pt, size_t size); 68char *getcwd(char *pt, size_t size);
65#endif 69#endif
@@ -68,6 +72,10 @@ char *getcwd(char *pt, size_t size);
68void *reallocarray(void *, size_t, size_t); 72void *reallocarray(void *, size_t, size_t);
69#endif 73#endif
70 74
75#ifndef HAVE_RECALLOCARRAY
76void *recallocarray(void *, size_t, size_t, size_t);
77#endif
78
71#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) 79#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH)
72/* 80/*
73 * glibc's FORTIFY_SOURCE can redefine this and prevent us picking up the 81 * glibc's FORTIFY_SOURCE can redefine this and prevent us picking up the
@@ -296,6 +304,10 @@ int bcrypt_pbkdf(const char *, size_t, const u_int8_t *, size_t,
296void explicit_bzero(void *p, size_t n); 304void explicit_bzero(void *p, size_t n);
297#endif 305#endif
298 306
307#ifndef HAVE_FREEZERO
308void freezero(void *, size_t);
309#endif
310
299char *xcrypt(const char *password, const char *salt); 311char *xcrypt(const char *password, const char *salt);
300char *shadow_pw(struct passwd *pw); 312char *shadow_pw(struct passwd *pw);
301 313
diff --git a/openbsd-compat/port-tun.c b/openbsd-compat/port-tun.c
index a444adf1d..7579c6084 100644
--- a/openbsd-compat/port-tun.c
+++ b/openbsd-compat/port-tun.c
@@ -199,84 +199,81 @@ sys_tun_open(int tun, int mode)
199 */ 199 */
200 200
201#if defined(SSH_TUN_FILTER) 201#if defined(SSH_TUN_FILTER)
202/*
203 * The tunnel forwarding protocol prepends the address family of forwarded
204 * IP packets using OpenBSD's numbers.
205 */
202#define OPENBSD_AF_INET 2 206#define OPENBSD_AF_INET 2
203#define OPENBSD_AF_INET6 24 207#define OPENBSD_AF_INET6 24
204 208
205int 209int
206sys_tun_infilter(struct Channel *c, char *buf, int len) 210sys_tun_infilter(struct ssh *ssh, struct Channel *c, char *buf, int _len)
207{ 211{
212 int r;
213 size_t len;
214 char *ptr = buf;
208#if defined(SSH_TUN_PREPEND_AF) 215#if defined(SSH_TUN_PREPEND_AF)
209 char rbuf[CHAN_RBUF]; 216 char rbuf[CHAN_RBUF];
210 struct ip *iph; 217 struct ip iph;
211#endif 218#endif
212 u_int32_t *af; 219#if defined(SSH_TUN_PREPEND_AF) || defined(SSH_TUN_COMPAT_AF)
213 char *ptr = buf; 220 u_int32_t af;
214 int r;
215
216#if defined(SSH_TUN_PREPEND_AF)
217 if (len <= 0 || len > (int)(sizeof(rbuf) - sizeof(*af)))
218 return (-1);
219 ptr = (char *)&rbuf[0];
220 bcopy(buf, ptr + sizeof(u_int32_t), len);
221 len += sizeof(u_int32_t);
222 af = (u_int32_t *)ptr;
223
224 iph = (struct ip *)(ptr + sizeof(u_int32_t));
225 switch (iph->ip_v) {
226 case 6:
227 *af = AF_INET6;
228 break;
229 case 4:
230 default:
231 *af = AF_INET;
232 break;
233 }
234#endif 221#endif
235 222
236#if defined(SSH_TUN_COMPAT_AF) 223 /* XXX update channel input filter API to use unsigned length */
237 if (len < (int)sizeof(u_int32_t)) 224 if (_len < 0)
238 return (-1); 225 return -1;
226 len = _len;
239 227
240 af = (u_int32_t *)ptr; 228#if defined(SSH_TUN_PREPEND_AF)
241 if (*af == htonl(AF_INET6)) 229 if (len <= sizeof(iph) || len > sizeof(rbuf) - 4)
242 *af = htonl(OPENBSD_AF_INET6); 230 return -1;
243 else 231 /* Determine address family from packet IP header. */
244 *af = htonl(OPENBSD_AF_INET); 232 memcpy(&iph, buf, sizeof(iph));
233 af = iph.ip_v == 6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET;
234 /* Prepend address family to packet using OpenBSD constants */
235 memcpy(rbuf + 4, buf, len);
236 len += 4;
237 POKE_U32(rbuf, af);
238 ptr = rbuf;
239#elif defined(SSH_TUN_COMPAT_AF)
240 /* Convert existing address family header to OpenBSD value */
241 if (len <= 4)
242 return -1;
243 af = PEEK_U32(buf);
244 /* Put it back */
245 POKE_U32(buf, af == AF_INET6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET);
245#endif 246#endif
246 247
247 if ((r = sshbuf_put_string(&c->input, ptr, len)) != 0) 248 if ((r = sshbuf_put_string(c->input, ptr, len)) != 0)
248 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 249 fatal("%s: buffer error: %s", __func__, ssh_err(r));
249 return (0); 250 return (0);
250} 251}
251 252
252u_char * 253u_char *
253sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen) 254sys_tun_outfilter(struct ssh *ssh, struct Channel *c,
255 u_char **data, size_t *dlen)
254{ 256{
255 u_char *buf; 257 u_char *buf;
256 u_int32_t *af; 258 u_int32_t af;
257 int r; 259 int r;
258 size_t xxx_dlen;
259 260
260 /* XXX new API is incompatible with this signature. */ 261 /* XXX new API is incompatible with this signature. */
261 if ((r = sshbuf_get_string(&c->output, data, &xxx_dlen)) != 0) 262 if ((r = sshbuf_get_string(c->output, data, dlen)) != 0)
262 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 263 fatal("%s: buffer error: %s", __func__, ssh_err(r));
263 if (dlen != NULL) 264 if (*dlen < sizeof(af))
264 *dlen = xxx_dlen;
265 if (*dlen < sizeof(*af))
266 return (NULL); 265 return (NULL);
267 buf = *data; 266 buf = *data;
268 267
269#if defined(SSH_TUN_PREPEND_AF) 268#if defined(SSH_TUN_PREPEND_AF)
270 *dlen -= sizeof(u_int32_t); 269 /* skip address family */
271 buf = *data + sizeof(u_int32_t); 270 *dlen -= sizeof(af);
271 buf = *data + sizeof(af);
272#elif defined(SSH_TUN_COMPAT_AF) 272#elif defined(SSH_TUN_COMPAT_AF)
273 af = ntohl(*(u_int32_t *)buf); 273 /* translate address family */
274 if (*af == OPENBSD_AF_INET6) 274 af = (PEEK_U32(buf) == OPENBSD_AF_INET6) ? AF_INET6 : AF_INET;
275 *af = htonl(AF_INET6); 275 POKE_U32(buf, af);
276 else
277 *af = htonl(AF_INET);
278#endif 276#endif
279
280 return (buf); 277 return (buf);
281} 278}
282#endif /* SSH_TUN_FILTER */ 279#endif /* SSH_TUN_FILTER */
diff --git a/openbsd-compat/port-tun.h b/openbsd-compat/port-tun.h
index c53df01fc..103514370 100644
--- a/openbsd-compat/port-tun.h
+++ b/openbsd-compat/port-tun.h
@@ -18,6 +18,7 @@
18#define _PORT_TUN_H 18#define _PORT_TUN_H
19 19
20struct Channel; 20struct Channel;
21struct ssh;
21 22
22#if defined(SSH_TUN_LINUX) || defined(SSH_TUN_FREEBSD) 23#if defined(SSH_TUN_LINUX) || defined(SSH_TUN_FREEBSD)
23# define CUSTOM_SYS_TUN_OPEN 24# define CUSTOM_SYS_TUN_OPEN
@@ -26,8 +27,8 @@ int sys_tun_open(int, int);
26 27
27#if defined(SSH_TUN_COMPAT_AF) || defined(SSH_TUN_PREPEND_AF) 28#if defined(SSH_TUN_COMPAT_AF) || defined(SSH_TUN_PREPEND_AF)
28# define SSH_TUN_FILTER 29# define SSH_TUN_FILTER
29int sys_tun_infilter(struct Channel *, char *, int); 30int sys_tun_infilter(struct ssh *, struct Channel *, char *, int);
30u_char *sys_tun_outfilter(struct Channel *, u_char **, u_int *); 31u_char *sys_tun_outfilter(struct ssh *, struct Channel *, u_char **, size_t *);
31#endif 32#endif
32 33
33#endif 34#endif
diff --git a/openbsd-compat/recallocarray.c b/openbsd-compat/recallocarray.c
new file mode 100644
index 000000000..3e1156ce2
--- /dev/null
+++ b/openbsd-compat/recallocarray.c
@@ -0,0 +1,90 @@
1/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */
2/*
3 * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */
19
20#include "includes.h"
21#ifndef HAVE_RECALLOCARRAY
22
23#include <errno.h>
24#include <stdlib.h>
25#ifdef HAVE_STDINT_H
26#include <stdint.h>
27#endif
28#include <string.h>
29#include <unistd.h>
30
31/*
32 * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
33 * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
34 */
35#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
36
37void *
38recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
39{
40 size_t oldsize, newsize;
41 void *newptr;
42
43 if (ptr == NULL)
44 return calloc(newnmemb, size);
45
46 if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
47 newnmemb > 0 && SIZE_MAX / newnmemb < size) {
48 errno = ENOMEM;
49 return NULL;
50 }
51 newsize = newnmemb * size;
52
53 if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
54 oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
55 errno = EINVAL;
56 return NULL;
57 }
58 oldsize = oldnmemb * size;
59
60 /*
61 * Don't bother too much if we're shrinking just a bit,
62 * we do not shrink for series of small steps, oh well.
63 */
64 if (newsize <= oldsize) {
65 size_t d = oldsize - newsize;
66
67 if (d < oldsize / 2 && d < (size_t)getpagesize()) {
68 memset((char *)ptr + newsize, 0, d);
69 return ptr;
70 }
71 }
72
73 newptr = malloc(newsize);
74 if (newptr == NULL)
75 return NULL;
76
77 if (newsize > oldsize) {
78 memcpy(newptr, ptr, oldsize);
79 memset((char *)newptr + oldsize, 0, newsize - oldsize);
80 } else
81 memcpy(newptr, ptr, newsize);
82
83 explicit_bzero(ptr, oldsize);
84 free(ptr);
85
86 return newptr;
87}
88/* DEF_WEAK(recallocarray); */
89
90#endif /* HAVE_RECALLOCARRAY */