Home | History | Annotate | Download | only in dropbear
      1 /*
      2  * Dropbear - a SSH2 server
      3  *
      4  * Copyright (c) 2002,2003 Matt Johnston
      5  * All rights reserved.
      6  *
      7  * Permission is hereby granted, free of charge, to any person obtaining a copy
      8  * of this software and associated documentation files (the "Software"), to deal
      9  * in the Software without restriction, including without limitation the rights
     10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11  * copies of the Software, and to permit persons to whom the Software is
     12  * furnished to do so, subject to the following conditions:
     13  *
     14  * The above copyright notice and this permission notice shall be included in
     15  * all copies or substantial portions of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23  * SOFTWARE.
     24  *
     25  * strlcat() is copyright as follows:
     26  * Copyright (c) 1998 Todd C. Miller <Todd.Miller (at) courtesan.com>
     27  * All rights reserved.
     28  *
     29  * Redistribution and use in source and binary forms, with or without
     30  * modification, are permitted provided that the following conditions
     31  * are met:
     32  * 1. Redistributions of source code must retain the above copyright
     33  *    notice, this list of conditions and the following disclaimer.
     34  * 2. Redistributions in binary form must reproduce the above copyright
     35  *    notice, this list of conditions and the following disclaimer in the
     36  *    documentation and/or other materials provided with the distribution.
     37  * 3. The name of the author may not be used to endorse or promote products
     38  *    derived from this software without specific prior written permission.
     39  *
     40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
     41  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
     42  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
     43  * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     44  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     45  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     46  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     47  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     48  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     49  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
     50 
     51 #include "includes.h"
     52 #include "dbutil.h"
     53 #include "buffer.h"
     54 #include "session.h"
     55 #include "atomicio.h"
     56 
     57 #define MAX_FMT 100
     58 
     59 static void generic_dropbear_exit(int exitcode, const char* format,
     60 		va_list param);
     61 static void generic_dropbear_log(int priority, const char* format,
     62 		va_list param);
     63 
     64 void (*_dropbear_exit)(int exitcode, const char* format, va_list param)
     65 						= generic_dropbear_exit;
     66 void (*_dropbear_log)(int priority, const char* format, va_list param)
     67 						= generic_dropbear_log;
     68 
     69 #ifdef DEBUG_TRACE
     70 int debug_trace = 0;
     71 #endif
     72 
     73 #ifndef DISABLE_SYSLOG
     74 void startsyslog() {
     75 
     76 	openlog(PROGNAME, LOG_PID, LOG_AUTHPRIV);
     77 
     78 }
     79 #endif /* DISABLE_SYSLOG */
     80 
     81 /* the "format" string must be <= 100 characters */
     82 void dropbear_close(const char* format, ...) {
     83 
     84 	va_list param;
     85 
     86 	va_start(param, format);
     87 	_dropbear_exit(EXIT_SUCCESS, format, param);
     88 	va_end(param);
     89 
     90 }
     91 
     92 void dropbear_exit(const char* format, ...) {
     93 
     94 	va_list param;
     95 
     96 	va_start(param, format);
     97 	_dropbear_exit(EXIT_FAILURE, format, param);
     98 	va_end(param);
     99 }
    100 
    101 static void generic_dropbear_exit(int exitcode, const char* format,
    102 		va_list param) {
    103 
    104 	char fmtbuf[300];
    105 
    106 	snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s", format);
    107 
    108 	_dropbear_log(LOG_INFO, fmtbuf, param);
    109 
    110 	exit(exitcode);
    111 }
    112 
    113 void fail_assert(const char* expr, const char* file, int line) {
    114 	dropbear_exit("failed assertion (%s:%d): `%s'", file, line, expr);
    115 }
    116 
    117 static void generic_dropbear_log(int UNUSED(priority), const char* format,
    118 		va_list param) {
    119 
    120 	char printbuf[1024];
    121 
    122 	vsnprintf(printbuf, sizeof(printbuf), format, param);
    123 
    124 	fprintf(stderr, "%s\n", printbuf);
    125 
    126 }
    127 
    128 /* this is what can be called to write arbitrary log messages */
    129 void dropbear_log(int priority, const char* format, ...) {
    130 
    131 	va_list param;
    132 
    133 	va_start(param, format);
    134 	_dropbear_log(priority, format, param);
    135 	va_end(param);
    136 }
    137 
    138 
    139 #ifdef DEBUG_TRACE
    140 void dropbear_trace(const char* format, ...) {
    141 
    142 	va_list param;
    143 
    144 	if (!debug_trace) {
    145 		return;
    146 	}
    147 
    148 	va_start(param, format);
    149 	fprintf(stderr, "TRACE: ");
    150 	vfprintf(stderr, format, param);
    151 	fprintf(stderr, "\n");
    152 	va_end(param);
    153 }
    154 #endif /* DEBUG_TRACE */
    155 
    156 static void set_sock_priority(int sock) {
    157 
    158 	int val;
    159 
    160 	/* disable nagle */
    161 	val = 1;
    162 	setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
    163 
    164 	/* set the TOS bit. note that this will fail for ipv6, I can't find any
    165 	 * equivalent. */
    166 #ifdef IPTOS_LOWDELAY
    167 	val = IPTOS_LOWDELAY;
    168 	setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val));
    169 #endif
    170 
    171 #ifdef SO_PRIORITY
    172 	/* linux specific, sets QoS class.
    173 	 * 6 looks to be optimal for interactive traffic (see tc-prio(8) ). */
    174 	val = 6;
    175 	setsockopt(sock, SOL_SOCKET, SO_PRIORITY, (void*) &val, sizeof(val));
    176 #endif
    177 
    178 }
    179 
    180 /* Listen on address:port.
    181  * Special cases are address of "" listening on everything,
    182  * and address of NULL listening on localhost only.
    183  * Returns the number of sockets bound on success, or -1 on failure. On
    184  * failure, if errstring wasn't NULL, it'll be a newly malloced error
    185  * string.*/
    186 int dropbear_listen(const char* address, const char* port,
    187 		int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
    188 
    189 	struct addrinfo hints, *res = NULL, *res0 = NULL;
    190 	int err;
    191 	unsigned int nsock;
    192 	struct linger linger;
    193 	int val;
    194 	int sock;
    195 
    196 	TRACE(("enter dropbear_listen"))
    197 
    198 	memset(&hints, 0, sizeof(hints));
    199 	hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
    200 	hints.ai_socktype = SOCK_STREAM;
    201 
    202 	/* for calling getaddrinfo:
    203 	 address == NULL and !AI_PASSIVE: local loopback
    204 	 address == NULL and AI_PASSIVE: all interfaces
    205 	 address != NULL: whatever the address says */
    206 	if (!address) {
    207 		TRACE(("dropbear_listen: local loopback"))
    208 	} else {
    209 		if (address[0] == '\0') {
    210 			TRACE(("dropbear_listen: all interfaces"))
    211 			address = NULL;
    212 		}
    213 		hints.ai_flags = AI_PASSIVE;
    214 	}
    215 	err = getaddrinfo(address, port, &hints, &res0);
    216 
    217 	if (err) {
    218 		if (errstring != NULL && *errstring == NULL) {
    219 			int len;
    220 			len = 20 + strlen(gai_strerror(err));
    221 			*errstring = (char*)m_malloc(len);
    222 			snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
    223 		}
    224 		if (res0) {
    225 			freeaddrinfo(res0);
    226 			res0 = NULL;
    227 		}
    228 		TRACE(("leave dropbear_listen: failed resolving"))
    229 		return -1;
    230 	}
    231 
    232 
    233 	nsock = 0;
    234 	for (res = res0; res != NULL && nsock < sockcount;
    235 			res = res->ai_next) {
    236 
    237 		/* Get a socket */
    238 		socks[nsock] = socket(res->ai_family, res->ai_socktype,
    239 				res->ai_protocol);
    240 
    241 		sock = socks[nsock]; /* For clarity */
    242 
    243 		if (sock < 0) {
    244 			err = errno;
    245 			TRACE(("socket() failed"))
    246 			continue;
    247 		}
    248 
    249 		/* Various useful socket options */
    250 		val = 1;
    251 		/* set to reuse, quick timeout */
    252 		setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
    253 		linger.l_onoff = 1;
    254 		linger.l_linger = 5;
    255 		setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
    256 
    257 		set_sock_priority(sock);
    258 
    259 		if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
    260 			err = errno;
    261 			close(sock);
    262 			TRACE(("bind(%s) failed", port))
    263 			continue;
    264 		}
    265 
    266 		if (listen(sock, 20) < 0) {
    267 			err = errno;
    268 			close(sock);
    269 			TRACE(("listen() failed"))
    270 			continue;
    271 		}
    272 
    273 		*maxfd = MAX(*maxfd, sock);
    274 
    275 		nsock++;
    276 	}
    277 
    278 	if (res0) {
    279 		freeaddrinfo(res0);
    280 		res0 = NULL;
    281 	}
    282 
    283 	if (nsock == 0) {
    284 		if (errstring != NULL && *errstring == NULL) {
    285 			int len;
    286 			len = 20 + strlen(strerror(err));
    287 			*errstring = (char*)m_malloc(len);
    288 			snprintf(*errstring, len, "Error listening: %s", strerror(err));
    289 		}
    290 		TRACE(("leave dropbear_listen: failure, %s", strerror(err)))
    291 		return -1;
    292 	}
    293 
    294 	TRACE(("leave dropbear_listen: success, %d socks bound", nsock))
    295 	return nsock;
    296 }
    297 
    298 /* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
    299  * return immediately if nonblocking is set. On failure, if errstring
    300  * wasn't null, it will be a newly malloced error message */
    301 
    302 /* TODO: maxfd */
    303 int connect_remote(const char* remotehost, const char* remoteport,
    304 		int nonblocking, char ** errstring) {
    305 
    306 	struct addrinfo *res0 = NULL, *res = NULL, hints;
    307 	int sock;
    308 	int err;
    309 
    310 	TRACE(("enter connect_remote"))
    311 
    312 	if (errstring != NULL) {
    313 		*errstring = NULL;
    314 	}
    315 
    316 	memset(&hints, 0, sizeof(hints));
    317 	hints.ai_socktype = SOCK_STREAM;
    318 	hints.ai_family = PF_UNSPEC;
    319 
    320 	err = getaddrinfo(remotehost, remoteport, &hints, &res0);
    321 	if (err) {
    322 		if (errstring != NULL && *errstring == NULL) {
    323 			int len;
    324 			len = 20 + strlen(gai_strerror(err));
    325 			*errstring = (char*)m_malloc(len);
    326 			snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
    327 		}
    328 		TRACE(("Error resolving: %s", gai_strerror(err)))
    329 		return -1;
    330 	}
    331 
    332 	sock = -1;
    333 	err = EADDRNOTAVAIL;
    334 	for (res = res0; res; res = res->ai_next) {
    335 
    336 		sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    337 		if (sock < 0) {
    338 			err = errno;
    339 			continue;
    340 		}
    341 
    342 		if (nonblocking) {
    343 			if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
    344 				close(sock);
    345 				sock = -1;
    346 				if (errstring != NULL && *errstring == NULL) {
    347 					*errstring = m_strdup("Failed non-blocking");
    348 				}
    349 				TRACE(("Failed non-blocking: %s", strerror(errno)))
    350 				continue;
    351 			}
    352 		}
    353 
    354 		if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) {
    355 			if (errno == EINPROGRESS && nonblocking) {
    356 				TRACE(("Connect in progress"))
    357 				break;
    358 			} else {
    359 				err = errno;
    360 				close(sock);
    361 				sock = -1;
    362 				continue;
    363 			}
    364 		}
    365 
    366 		break; /* Success */
    367 	}
    368 
    369 	if (sock < 0 && !(errno == EINPROGRESS && nonblocking)) {
    370 		/* Failed */
    371 		if (errstring != NULL && *errstring == NULL) {
    372 			int len;
    373 			len = 20 + strlen(strerror(err));
    374 			*errstring = (char*)m_malloc(len);
    375 			snprintf(*errstring, len, "Error connecting: %s", strerror(err));
    376 		}
    377 		TRACE(("Error connecting: %s", strerror(err)))
    378 	} else {
    379 		/* Success */
    380 		set_sock_priority(sock);
    381 	}
    382 
    383 	freeaddrinfo(res0);
    384 	if (sock > 0 && errstring != NULL && *errstring != NULL) {
    385 		m_free(*errstring);
    386 	}
    387 
    388 	TRACE(("leave connect_remote: sock %d\n", sock))
    389 	return sock;
    390 }
    391 
    392 /* Return a string representation of the socket address passed. The return
    393  * value is allocated with malloc() */
    394 unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
    395 
    396 	char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
    397 	char *retstring = NULL;
    398 	int ret;
    399 	unsigned int len;
    400 
    401 	len = sizeof(struct sockaddr_storage);
    402 	/* Some platforms such as Solaris 8 require that len is the length
    403 	 * of the specific structure. Some older linux systems (glibc 2.1.3
    404 	 * such as debian potato) have sockaddr_storage.__ss_family instead
    405 	 * but we'll ignore them */
    406 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
    407 	if (addr->ss_family == AF_INET) {
    408 		len = sizeof(struct sockaddr_in);
    409 	}
    410 #ifdef AF_INET6
    411 	if (addr->ss_family == AF_INET6) {
    412 		len = sizeof(struct sockaddr_in6);
    413 	}
    414 #endif
    415 #endif
    416 
    417 	ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
    418 			sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST);
    419 
    420 	if (ret != 0) {
    421 		/* This is a fairly bad failure - it'll fallback to IP if it
    422 		 * just can't resolve */
    423 		dropbear_exit("failed lookup (%d, %d)", ret, errno);
    424 	}
    425 
    426 	if (withport) {
    427 		len = strlen(hbuf) + 2 + strlen(sbuf);
    428 		retstring = (char*)m_malloc(len);
    429 		snprintf(retstring, len, "%s:%s", hbuf, sbuf);
    430 	} else {
    431 		retstring = m_strdup(hbuf);
    432 	}
    433 
    434 	return retstring;
    435 
    436 }
    437 
    438 /* Get the hostname corresponding to the address addr. On failure, the IP
    439  * address is returned. The return value is allocated with strdup() */
    440 char* getaddrhostname(struct sockaddr_storage * addr) {
    441 
    442 	char hbuf[NI_MAXHOST];
    443 	char sbuf[NI_MAXSERV];
    444 	int ret;
    445 	unsigned int len;
    446 #ifdef DO_HOST_LOOKUP
    447 	const int flags = NI_NUMERICSERV;
    448 #else
    449 	const int flags = NI_NUMERICHOST | NI_NUMERICSERV;
    450 #endif
    451 
    452 	len = sizeof(struct sockaddr_storage);
    453 	/* Some platforms such as Solaris 8 require that len is the length
    454 	 * of the specific structure. */
    455 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
    456 	if (addr->ss_family == AF_INET) {
    457 		len = sizeof(struct sockaddr_in);
    458 	}
    459 #ifdef AF_INET6
    460 	if (addr->ss_family == AF_INET6) {
    461 		len = sizeof(struct sockaddr_in6);
    462 	}
    463 #endif
    464 #endif
    465 
    466 
    467 	ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
    468 			sbuf, sizeof(sbuf), flags);
    469 
    470 	if (ret != 0) {
    471 		/* On some systems (Darwin does it) we get EINTR from getnameinfo
    472 		 * somehow. Eew. So we'll just return the IP, since that doesn't seem
    473 		 * to exhibit that behaviour. */
    474 		return getaddrstring(addr, 0);
    475 	}
    476 
    477 	return m_strdup(hbuf);
    478 }
    479 
    480 #ifdef DEBUG_TRACE
    481 void printhex(const char * label, const unsigned char * buf, int len) {
    482 
    483 	int i;
    484 
    485 	fprintf(stderr, "%s\n", label);
    486 	for (i = 0; i < len; i++) {
    487 		fprintf(stderr, "%02x", buf[i]);
    488 		if (i % 16 == 15) {
    489 			fprintf(stderr, "\n");
    490 		}
    491 		else if (i % 2 == 1) {
    492 			fprintf(stderr, " ");
    493 		}
    494 	}
    495 	fprintf(stderr, "\n");
    496 }
    497 #endif
    498 
    499 /* Strip all control characters from text (a null-terminated string), except
    500  * for '\n', '\r' and '\t'.
    501  * The result returned is a newly allocated string, this must be free()d after
    502  * use */
    503 char * stripcontrol(const char * text) {
    504 
    505 	char * ret;
    506 	int len, pos;
    507 	int i;
    508 
    509 	len = strlen(text);
    510 	ret = m_malloc(len+1);
    511 
    512 	pos = 0;
    513 	for (i = 0; i < len; i++) {
    514 		if ((text[i] <= '~' && text[i] >= ' ') /* normal printable range */
    515 				|| text[i] == '\n' || text[i] == '\r' || text[i] == '\t') {
    516 			ret[pos] = text[i];
    517 			pos++;
    518 		}
    519 	}
    520 	ret[pos] = 0x0;
    521 	return ret;
    522 }
    523 
    524 
    525 /* reads the contents of filename into the buffer buf, from the current
    526  * position, either to the end of the file, or the buffer being full.
    527  * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
    528 int buf_readfile(buffer* buf, const char* filename) {
    529 
    530 	int fd = -1;
    531 	int len;
    532 	int maxlen;
    533 	int ret = DROPBEAR_FAILURE;
    534 
    535 	fd = open(filename, O_RDONLY);
    536 
    537 	if (fd < 0) {
    538 		goto out;
    539 	}
    540 
    541 	do {
    542 		maxlen = buf->size - buf->pos;
    543 		len = read(fd, buf_getwriteptr(buf, maxlen), maxlen);
    544 		if (len < 0) {
    545 			if (errno == EINTR || errno == EAGAIN) {
    546 				continue;
    547 			}
    548 			goto out;
    549 		}
    550 		buf_incrwritepos(buf, len);
    551 	} while (len < maxlen && len > 0);
    552 
    553 	ret = DROPBEAR_SUCCESS;
    554 
    555 out:
    556 	if (fd >= 0) {
    557 		m_close(fd);
    558 	}
    559 	return ret;
    560 }
    561 
    562 /* get a line from the file into buffer in the style expected for an
    563  * authkeys file.
    564  * Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/
    565 /* Only used for ~/.ssh/known_hosts and ~/.ssh/authorized_keys */
    566 #if defined(DROPBEAR_CLIENT) || defined(ENABLE_SVR_PUBKEY_AUTH)
    567 int buf_getline(buffer * line, FILE * authfile) {
    568 
    569 	int c = EOF;
    570 
    571 	TRACE(("enter buf_getline"))
    572 
    573 	buf_setpos(line, 0);
    574 	buf_setlen(line, 0);
    575 
    576 	while (line->pos < line->size) {
    577 
    578 		c = fgetc(authfile); /*getc() is weird with some uClibc systems*/
    579 		if (c == EOF || c == '\n' || c == '\r') {
    580 			goto out;
    581 		}
    582 
    583 		buf_putbyte(line, (unsigned char)c);
    584 	}
    585 
    586 	TRACE(("leave getauthline: line too long"))
    587 	/* We return success, but the line length will be zeroed - ie we just
    588 	 * ignore that line */
    589 	buf_setlen(line, 0);
    590 
    591 out:
    592 
    593 
    594 	/* if we didn't read anything before EOF or error, exit */
    595 	if (c == EOF && line->pos == 0) {
    596 		TRACE(("leave buf_getline: failure"))
    597 		return DROPBEAR_FAILURE;
    598 	} else {
    599 		TRACE(("leave buf_getline: success"))
    600 		buf_setpos(line, 0);
    601 		return DROPBEAR_SUCCESS;
    602 	}
    603 
    604 }
    605 #endif
    606 
    607 /* make sure that the socket closes */
    608 void m_close(int fd) {
    609 
    610 	int val;
    611 	do {
    612 		val = close(fd);
    613 	} while (val < 0 && errno == EINTR);
    614 
    615 	if (val < 0 && errno != EBADF) {
    616 		/* Linux says EIO can happen */
    617 		dropbear_exit("Error closing fd %d, %s", fd, strerror(errno));
    618 	}
    619 }
    620 
    621 void * m_malloc(size_t size) {
    622 
    623 	void* ret;
    624 
    625 	if (size == 0) {
    626 		dropbear_exit("m_malloc failed");
    627 	}
    628 	ret = calloc(1, size);
    629 	if (ret == NULL) {
    630 		dropbear_exit("m_malloc failed");
    631 	}
    632 	return ret;
    633 
    634 }
    635 
    636 void * m_strdup(const char * str) {
    637 	char* ret;
    638 
    639 	ret = strdup(str);
    640 	if (ret == NULL) {
    641 		dropbear_exit("m_strdup failed");
    642 	}
    643 	return ret;
    644 }
    645 
    646 void __m_free(void* ptr) {
    647 	if (ptr != NULL) {
    648 		free(ptr);
    649 	}
    650 }
    651 
    652 void * m_realloc(void* ptr, size_t size) {
    653 
    654 	void *ret;
    655 
    656 	if (size == 0) {
    657 		dropbear_exit("m_realloc failed");
    658 	}
    659 	ret = realloc(ptr, size);
    660 	if (ret == NULL) {
    661 		dropbear_exit("m_realloc failed");
    662 	}
    663 	return ret;
    664 }
    665 
    666 /* Clear the data, based on the method in David Wheeler's
    667  * "Secure Programming for Linux and Unix HOWTO" */
    668 /* Beware of calling this from within dbutil.c - things might get
    669  * optimised away */
    670 void m_burn(void *data, unsigned int len) {
    671 	volatile char *p = data;
    672 
    673 	if (data == NULL)
    674 		return;
    675 	while (len--) {
    676 		*p++ = 0x66;
    677 	}
    678 }
    679 
    680 
    681 void setnonblocking(int fd) {
    682 
    683 	TRACE(("setnonblocking: %d", fd))
    684 
    685 	if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
    686 		if (errno == ENODEV) {
    687 			/* Some devices (like /dev/null redirected in)
    688 			 * can't be set to non-blocking */
    689 			TRACE(("ignoring ENODEV for setnonblocking"))
    690 		} else {
    691 			dropbear_exit("Couldn't set nonblocking");
    692 		}
    693 	}
    694 	TRACE(("leave setnonblocking"))
    695 }
    696 
    697 void disallow_core() {
    698 	struct rlimit lim;
    699 	lim.rlim_cur = lim.rlim_max = 0;
    700 	setrlimit(RLIMIT_CORE, &lim);
    701 }
    702