• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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
startsyslog()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 */
dropbear_close(const char * format,...)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 
dropbear_exit(const char * format,...)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 
generic_dropbear_exit(int exitcode,const char * format,va_list param)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 
fail_assert(const char * expr,const char * file,int line)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 
generic_dropbear_log(int UNUSED (priority),const char * format,va_list param)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 */
dropbear_log(int priority,const char * format,...)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
dropbear_trace(const char * format,...)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 
set_sock_priority(int sock)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.*/
dropbear_listen(const char * address,const char * port,int * socks,unsigned int sockcount,char ** errstring,int * maxfd)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 */
connect_remote(const char * remotehost,const char * remoteport,int nonblocking,char ** errstring)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() */
getaddrstring(struct sockaddr_storage * addr,int withport)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() */
getaddrhostname(struct sockaddr_storage * addr)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
printhex(const char * label,const unsigned char * buf,int len)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 */
stripcontrol(const char * text)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 */
buf_readfile(buffer * buf,const char * filename)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)
buf_getline(buffer * line,FILE * authfile)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 */
m_close(int fd)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 
m_malloc(size_t size)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 
m_strdup(const char * str)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 
__m_free(void * ptr)646 void __m_free(void* ptr) {
647 	if (ptr != NULL) {
648 		free(ptr);
649 	}
650 }
651 
m_realloc(void * ptr,size_t size)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 */
m_burn(void * data,unsigned int len)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 
setnonblocking(int fd)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 
disallow_core()697 void disallow_core() {
698 	struct rlimit lim;
699 	lim.rlim_cur = lim.rlim_max = 0;
700 	setrlimit(RLIMIT_CORE, &lim);
701 }
702