summaryrefslogtreecommitdiff
path: root/openbsd-compat
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2018-05-06 12:24:45 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2018-05-06 12:24:45 +0000
commit20adc8f2a99cd37b64a80ef63dfc5ba6627d4dfb (patch)
treead57ce9ac9538c780c802adbdfc4c581f9100310 /openbsd-compat
parent343d57711556d429eda777ab259ff924acbd6b34 (diff)
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 d51eacf6562a3..ac8ae4305d0bc 100644
--- a/openbsd-compat/Makefile.in
+++ b/openbsd-compat/Makefile.in
@@ -16,9 +16,9 @@ RANLIB=@RANLIB@
INSTALL=@INSTALL@
LDFLAGS=-L. @LDFLAGS@
-OPENBSD=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
+OPENBSD=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
-COMPAT=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
+COMPAT=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
PORTS=port-aix.o port-irix.o port-linux.o port-solaris.o port-tun.o port-uw.o
diff --git a/openbsd-compat/bsd-err.c b/openbsd-compat/bsd-err.c
index ab10646f023ad..e4ed22b86a259 100644
--- a/openbsd-compat/bsd-err.c
+++ b/openbsd-compat/bsd-err.c
@@ -27,6 +27,12 @@
#include "includes.h"
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
#ifndef HAVE_ERR
void
err(int r, const char *fmt, ...)
diff --git a/openbsd-compat/bsd-getpagesize.c b/openbsd-compat/bsd-getpagesize.c
new file mode 100644
index 0000000000000..9daddfbd38655
--- /dev/null
+++ b/openbsd-compat/bsd-getpagesize.c
@@ -0,0 +1,23 @@
+/* Placed in the public domain */
+
+#ifndef HAVE_GETPAGESIZE
+
+#include <unistd.h>
+#include <limits.h>
+
+int
+getpagesize(void)
+{
+#if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
+ long r = sysconf(_SC_PAGESIZE);
+ if (r > 0 && r < INT_MAX)
+ return (int)r;
+#endif
+ /*
+ * This is at the lower end of common values and appropriate for
+ * our current use of getpagesize() in recallocarray().
+ */
+ return 4096;
+}
+
+#endif /* HAVE_GETPAGESIZE */
diff --git a/openbsd-compat/bsd-malloc.c b/openbsd-compat/bsd-malloc.c
new file mode 100644
index 0000000000000..6402ab588b095
--- /dev/null
+++ b/openbsd-compat/bsd-malloc.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2017 Darren Tucker (dtucker at zip com au).
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+#undef malloc
+#undef calloc
+#undef realloc
+
+#include <sys/types.h>
+#include <stdlib.h>
+
+#if defined(HAVE_MALLOC) && HAVE_MALLOC == 0
+void *
+rpl_malloc(size_t size)
+{
+ if (size == 0)
+ size = 1;
+ return malloc(size);
+}
+#endif
+
+#if defined(HAVE_CALLOC) && HAVE_CALLOC == 0
+void *
+rpl_calloc(size_t nmemb, size_t size)
+{
+ if (nmemb == 0)
+ nmemb = 1;
+ if (size == 0)
+ size = 1;
+ return calloc(nmemb, size);
+}
+#endif
+
+#if defined (HAVE_REALLOC) && HAVE_REALLOC == 0
+void *
+rpl_realloc(void *ptr, size_t size)
+{
+ if (size == 0)
+ size = 1;
+ return realloc(ptr, size);
+}
+#endif
diff --git a/openbsd-compat/bsd-misc.c b/openbsd-compat/bsd-misc.c
index cfd73260ae187..29f6ad38c5a1a 100644
--- a/openbsd-compat/bsd-misc.c
+++ b/openbsd-compat/bsd-misc.c
@@ -104,6 +104,16 @@ const char *strerror(int e)
}
#endif
+#if !defined(HAVE_STRSIGNAL)
+char *strsignal(int sig)
+{
+ static char buf[16];
+
+ (void)snprintf(buf, sizeof(buf), "%d", sig);
+ return buf;
+}
+#endif
+
#ifndef HAVE_UTIMES
int utimes(char *filename, struct timeval *tvp)
{
diff --git a/openbsd-compat/bsd-misc.h b/openbsd-compat/bsd-misc.h
index 70a538f04e2d6..0b1a3504f2cc6 100644
--- a/openbsd-compat/bsd-misc.h
+++ b/openbsd-compat/bsd-misc.h
@@ -49,6 +49,10 @@ int setegid(uid_t);
const char *strerror(int);
#endif
+#if !defined(HAVE_STRSIGNAL)
+char *strsignal(int);
+#endif
+
#if !defined(HAVE_SETLINEBUF)
#define setlinebuf(a) (setvbuf((a), NULL, _IOLBF, 0))
#endif
diff --git a/openbsd-compat/explicit_bzero.c b/openbsd-compat/explicit_bzero.c
index 5078134d137a8..53a003472721d 100644
--- a/openbsd-compat/explicit_bzero.c
+++ b/openbsd-compat/explicit_bzero.c
@@ -20,6 +20,8 @@
void
explicit_bzero(void *p, size_t n)
{
+ if (n == 0)
+ return;
(void)memset_s(p, n, 0, n);
}
@@ -34,6 +36,8 @@ static void (* volatile ssh_bzero)(void *, size_t) = bzero;
void
explicit_bzero(void *p, size_t n)
{
+ if (n == 0)
+ return;
/*
* clang -fsanitize=memory needs to intercept memset-like functions
* 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 e5533b2de90ce..7c5193e26d959 100644
--- a/openbsd-compat/fmt_scaled.c
+++ b/openbsd-compat/fmt_scaled.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fmt_scaled.c,v 1.13 2017/03/11 23:37:23 djm Exp $ */
+/* $OpenBSD: fmt_scaled.c,v 1.16 2017/03/16 02:40:46 dtucker Exp $ */
/*
* Copyright (c) 2001, 2002, 2003 Ian F. Darwin. All rights reserved.
@@ -125,22 +125,30 @@ scan_scaled(char *scaled, long long *result)
/* ignore extra fractional digits */
continue;
fract_digits++; /* for later scaling */
- if (fpart >= LLONG_MAX / 10) {
+ if (fpart > LLONG_MAX / 10) {
errno = ERANGE;
return -1;
}
fpart *= 10;
+ if (i > LLONG_MAX - fpart) {
+ errno = ERANGE;
+ return -1;
+ }
fpart += i;
} else { /* normal digit */
if (++ndigits >= MAX_DIGITS) {
errno = ERANGE;
return -1;
}
- if (whole >= LLONG_MAX / 10) {
+ if (whole > LLONG_MAX / 10) {
errno = ERANGE;
return -1;
}
whole *= 10;
+ if (i > LLONG_MAX - whole) {
+ errno = ERANGE;
+ return -1;
+ }
whole += i;
}
}
@@ -170,7 +178,9 @@ scan_scaled(char *scaled, long long *result)
}
scale_fact = scale_factors[i];
- if (whole >= LLONG_MAX / scale_fact) {
+ /* check for overflow and underflow after scaling */
+ if (whole > LLONG_MAX / scale_fact ||
+ whole < LLONG_MIN / scale_fact) {
errno = ERANGE;
return -1;
}
diff --git a/openbsd-compat/freezero.c b/openbsd-compat/freezero.c
new file mode 100644
index 0000000000000..3af8f4a733e96
--- /dev/null
+++ b/openbsd-compat/freezero.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2008, 2010, 2011, 2016 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "includes.h"
+
+#ifndef HAVE_FREEZERO
+
+void
+freezero(void *ptr, size_t sz)
+{
+ explicit_bzero(ptr, sz);
+ free(ptr);
+}
+
+#endif /* HAVE_FREEZERO */
+
diff --git a/openbsd-compat/openbsd-compat.h b/openbsd-compat/openbsd-compat.h
index cff547745b885..cac799e8446ff 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);
void closefrom(int);
#endif
+#ifndef HAVE_GETPAGESIZE
+int getpagesize(void);
+#endif
+
#ifndef HAVE_GETCWD
char *getcwd(char *pt, size_t size);
#endif
@@ -68,6 +72,10 @@ char *getcwd(char *pt, size_t size);
void *reallocarray(void *, size_t, size_t);
#endif
+#ifndef HAVE_RECALLOCARRAY
+void *recallocarray(void *, size_t, size_t, size_t);
+#endif
+
#if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH)
/*
* 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,
void explicit_bzero(void *p, size_t n);
#endif
+#ifndef HAVE_FREEZERO
+void freezero(void *, size_t);
+#endif
+
char *xcrypt(const char *password, const char *salt);
char *shadow_pw(struct passwd *pw);
diff --git a/openbsd-compat/port-tun.c b/openbsd-compat/port-tun.c
index a444adf1d5934..7579c6084a1f8 100644
--- a/openbsd-compat/port-tun.c
+++ b/openbsd-compat/port-tun.c
@@ -199,84 +199,81 @@ sys_tun_open(int tun, int mode)
*/
#if defined(SSH_TUN_FILTER)
+/*
+ * The tunnel forwarding protocol prepends the address family of forwarded
+ * IP packets using OpenBSD's numbers.
+ */
#define OPENBSD_AF_INET 2
#define OPENBSD_AF_INET6 24
int
-sys_tun_infilter(struct Channel *c, char *buf, int len)
+sys_tun_infilter(struct ssh *ssh, struct Channel *c, char *buf, int _len)
{
+ int r;
+ size_t len;
+ char *ptr = buf;
#if defined(SSH_TUN_PREPEND_AF)
char rbuf[CHAN_RBUF];
- struct ip *iph;
+ struct ip iph;
#endif
- u_int32_t *af;
- char *ptr = buf;
- int r;
-
-#if defined(SSH_TUN_PREPEND_AF)
- if (len <= 0 || len > (int)(sizeof(rbuf) - sizeof(*af)))
- return (-1);
- ptr = (char *)&rbuf[0];
- bcopy(buf, ptr + sizeof(u_int32_t), len);
- len += sizeof(u_int32_t);
- af = (u_int32_t *)ptr;
-
- iph = (struct ip *)(ptr + sizeof(u_int32_t));
- switch (iph->ip_v) {
- case 6:
- *af = AF_INET6;
- break;
- case 4:
- default:
- *af = AF_INET;
- break;
- }
+#if defined(SSH_TUN_PREPEND_AF) || defined(SSH_TUN_COMPAT_AF)
+ u_int32_t af;
#endif
-#if defined(SSH_TUN_COMPAT_AF)
- if (len < (int)sizeof(u_int32_t))
- return (-1);
+ /* XXX update channel input filter API to use unsigned length */
+ if (_len < 0)
+ return -1;
+ len = _len;
- af = (u_int32_t *)ptr;
- if (*af == htonl(AF_INET6))
- *af = htonl(OPENBSD_AF_INET6);
- else
- *af = htonl(OPENBSD_AF_INET);
+#if defined(SSH_TUN_PREPEND_AF)
+ if (len <= sizeof(iph) || len > sizeof(rbuf) - 4)
+ return -1;
+ /* Determine address family from packet IP header. */
+ memcpy(&iph, buf, sizeof(iph));
+ af = iph.ip_v == 6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET;
+ /* Prepend address family to packet using OpenBSD constants */
+ memcpy(rbuf + 4, buf, len);
+ len += 4;
+ POKE_U32(rbuf, af);
+ ptr = rbuf;
+#elif defined(SSH_TUN_COMPAT_AF)
+ /* Convert existing address family header to OpenBSD value */
+ if (len <= 4)
+ return -1;
+ af = PEEK_U32(buf);
+ /* Put it back */
+ POKE_U32(buf, af == AF_INET6 ? OPENBSD_AF_INET6 : OPENBSD_AF_INET);
#endif
- if ((r = sshbuf_put_string(&c->input, ptr, len)) != 0)
+ if ((r = sshbuf_put_string(c->input, ptr, len)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
return (0);
}
u_char *
-sys_tun_outfilter(struct Channel *c, u_char **data, u_int *dlen)
+sys_tun_outfilter(struct ssh *ssh, struct Channel *c,
+ u_char **data, size_t *dlen)
{
u_char *buf;
- u_int32_t *af;
+ u_int32_t af;
int r;
- size_t xxx_dlen;
/* XXX new API is incompatible with this signature. */
- if ((r = sshbuf_get_string(&c->output, data, &xxx_dlen)) != 0)
+ if ((r = sshbuf_get_string(c->output, data, dlen)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r));
- if (dlen != NULL)
- *dlen = xxx_dlen;
- if (*dlen < sizeof(*af))
+ if (*dlen < sizeof(af))
return (NULL);
buf = *data;
#if defined(SSH_TUN_PREPEND_AF)
- *dlen -= sizeof(u_int32_t);
- buf = *data + sizeof(u_int32_t);
+ /* skip address family */
+ *dlen -= sizeof(af);
+ buf = *data + sizeof(af);
#elif defined(SSH_TUN_COMPAT_AF)
- af = ntohl(*(u_int32_t *)buf);
- if (*af == OPENBSD_AF_INET6)
- *af = htonl(AF_INET6);
- else
- *af = htonl(AF_INET);
+ /* translate address family */
+ af = (PEEK_U32(buf) == OPENBSD_AF_INET6) ? AF_INET6 : AF_INET;
+ POKE_U32(buf, af);
#endif
-
return (buf);
}
#endif /* SSH_TUN_FILTER */
diff --git a/openbsd-compat/port-tun.h b/openbsd-compat/port-tun.h
index c53df01fceb60..103514370fd39 100644
--- a/openbsd-compat/port-tun.h
+++ b/openbsd-compat/port-tun.h
@@ -18,6 +18,7 @@
#define _PORT_TUN_H
struct Channel;
+struct ssh;
#if defined(SSH_TUN_LINUX) || defined(SSH_TUN_FREEBSD)
# define CUSTOM_SYS_TUN_OPEN
@@ -26,8 +27,8 @@ int sys_tun_open(int, int);
#if defined(SSH_TUN_COMPAT_AF) || defined(SSH_TUN_PREPEND_AF)
# define SSH_TUN_FILTER
-int sys_tun_infilter(struct Channel *, char *, int);
-u_char *sys_tun_outfilter(struct Channel *, u_char **, u_int *);
+int sys_tun_infilter(struct ssh *, struct Channel *, char *, int);
+u_char *sys_tun_outfilter(struct ssh *, struct Channel *, u_char **, size_t *);
#endif
#endif
diff --git a/openbsd-compat/recallocarray.c b/openbsd-compat/recallocarray.c
new file mode 100644
index 0000000000000..3e1156ce2d959
--- /dev/null
+++ b/openbsd-compat/recallocarray.c
@@ -0,0 +1,90 @@
+/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */
+/*
+ * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* OPENBSD ORIGINAL: lib/libc/stdlib/recallocarray.c */
+
+#include "includes.h"
+#ifndef HAVE_RECALLOCARRAY
+
+#include <errno.h>
+#include <stdlib.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
+void *
+recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
+{
+ size_t oldsize, newsize;
+ void *newptr;
+
+ if (ptr == NULL)
+ return calloc(newnmemb, size);
+
+ if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ newnmemb > 0 && SIZE_MAX / newnmemb < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ newsize = newnmemb * size;
+
+ if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
+ errno = EINVAL;
+ return NULL;
+ }
+ oldsize = oldnmemb * size;
+
+ /*
+ * Don't bother too much if we're shrinking just a bit,
+ * we do not shrink for series of small steps, oh well.
+ */
+ if (newsize <= oldsize) {
+ size_t d = oldsize - newsize;
+
+ if (d < oldsize / 2 && d < (size_t)getpagesize()) {
+ memset((char *)ptr + newsize, 0, d);
+ return ptr;
+ }
+ }
+
+ newptr = malloc(newsize);
+ if (newptr == NULL)
+ return NULL;
+
+ if (newsize > oldsize) {
+ memcpy(newptr, ptr, oldsize);
+ memset((char *)newptr + oldsize, 0, newsize - oldsize);
+ } else
+ memcpy(newptr, ptr, newsize);
+
+ explicit_bzero(ptr, oldsize);
+ free(ptr);
+
+ return newptr;
+}
+/* DEF_WEAK(recallocarray); */
+
+#endif /* HAVE_RECALLOCARRAY */