Mercurial > dropbear
comparison dbutil.c @ 285:1b9e69c058d2
propagate from branch 'au.asn.ucc.matt.ltc.dropbear' (head 20dccfc09627970a312d77fb41dc2970b62689c3)
to branch 'au.asn.ucc.matt.dropbear' (head fdf4a7a3b97ae5046139915de7e40399cceb2c01)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Wed, 08 Mar 2006 13:23:58 +0000 |
parents | 044bc108b9b3 |
children | 79bf1023cf11 973fccb59ea4 e17f0333c21e 28b10e93685c |
comparison
equal
deleted
inserted
replaced
281:997e6f7dc01e | 285:1b9e69c058d2 |
---|---|
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 <[email protected]> | |
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 TRACE(("leave dropbear_listen: failure, %s", strerror(err))) | |
290 return -1; | |
291 } | |
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. */ | |
404 if (addr->ss_family == AF_INET) { | |
405 len = sizeof(struct sockaddr_in); | |
406 } | |
407 #ifdef AF_INET6 | |
408 if (addr->ss_family == AF_INET6) { | |
409 len = sizeof(struct sockaddr_in6); | |
410 } | |
411 #endif | |
412 | |
413 ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf), | |
414 sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST); | |
415 | |
416 if (ret != 0) { | |
417 /* This is a fairly bad failure - it'll fallback to IP if it | |
418 * just can't resolve */ | |
419 dropbear_exit("failed lookup (%d, %d)", ret, errno); | |
420 } | |
421 | |
422 if (withport) { | |
423 len = strlen(hbuf) + 2 + strlen(sbuf); | |
424 retstring = (char*)m_malloc(len); | |
425 snprintf(retstring, len, "%s:%s", hbuf, sbuf); | |
426 } else { | |
427 retstring = m_strdup(hbuf); | |
428 } | |
429 | |
430 return retstring; | |
431 | |
432 } | |
433 | |
434 /* Get the hostname corresponding to the address addr. On failure, the IP | |
435 * address is returned. The return value is allocated with strdup() */ | |
436 char* getaddrhostname(struct sockaddr_storage * addr) { | |
437 | |
438 char hbuf[NI_MAXHOST]; | |
439 char sbuf[NI_MAXSERV]; | |
440 int ret; | |
441 unsigned int len; | |
442 #ifdef DO_HOST_LOOKUP | |
443 const int flags = NI_NUMERICSERV; | |
444 #else | |
445 const int flags = NI_NUMERICHOST | NI_NUMERICSERV; | |
446 #endif | |
447 | |
448 len = sizeof(struct sockaddr_storage); | |
449 /* Some platforms such as Solaris 8 require that len is the length | |
450 * of the specific structure. */ | |
451 if (addr->ss_family == AF_INET) { | |
452 len = sizeof(struct sockaddr_in); | |
453 } | |
454 #ifdef AF_INET6 | |
455 if (addr->ss_family == AF_INET6) { | |
456 len = sizeof(struct sockaddr_in6); | |
457 } | |
458 #endif | |
459 | |
460 | |
461 ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf), | |
462 sbuf, sizeof(sbuf), flags); | |
463 | |
464 if (ret != 0) { | |
465 /* On some systems (Darwin does it) we get EINTR from getnameinfo | |
466 * somehow. Eew. So we'll just return the IP, since that doesn't seem | |
467 * to exhibit that behaviour. */ | |
468 return getaddrstring(addr, 0); | |
469 } | |
470 | |
471 return m_strdup(hbuf); | |
472 } | |
473 | |
474 #ifdef DEBUG_TRACE | |
475 void printhex(const char * label, const unsigned char * buf, int len) { | |
476 | |
477 int i; | |
478 | |
479 fprintf(stderr, "%s\n", label); | |
480 for (i = 0; i < len; i++) { | |
481 fprintf(stderr, "%02x", buf[i]); | |
482 if (i % 16 == 15) { | |
483 fprintf(stderr, "\n"); | |
484 } | |
485 else if (i % 2 == 1) { | |
486 fprintf(stderr, " "); | |
487 } | |
488 } | |
489 fprintf(stderr, "\n"); | |
490 } | |
491 #endif | |
492 | |
493 /* Strip all control characters from text (a null-terminated string), except | |
494 * for '\n', '\r' and '\t'. | |
495 * The result returned is a newly allocated string, this must be free()d after | |
496 * use */ | |
497 char * stripcontrol(const char * text) { | |
498 | |
499 char * ret; | |
500 int len, pos; | |
501 int i; | |
502 | |
503 len = strlen(text); | |
504 ret = m_malloc(len+1); | |
505 | |
506 pos = 0; | |
507 for (i = 0; i < len; i++) { | |
508 if ((text[i] <= '~' && text[i] >= ' ') /* normal printable range */ | |
509 || text[i] == '\n' || text[i] == '\r' || text[i] == '\t') { | |
510 ret[pos] = text[i]; | |
511 pos++; | |
512 } | |
513 } | |
514 ret[pos] = 0x0; | |
515 return ret; | |
516 } | |
517 | |
518 | |
519 /* reads the contents of filename into the buffer buf, from the current | |
520 * position, either to the end of the file, or the buffer being full. | |
521 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ | |
522 int buf_readfile(buffer* buf, const char* filename) { | |
523 | |
524 int fd; | |
525 int len; | |
526 int maxlen; | |
527 | |
528 fd = open(filename, O_RDONLY); | |
529 | |
530 if (fd < 0) { | |
531 close(fd); | |
532 return DROPBEAR_FAILURE; | |
533 } | |
534 | |
535 do { | |
536 maxlen = buf->size - buf->pos; | |
537 len = read(fd, buf_getwriteptr(buf, maxlen), | |
538 maxlen); | |
539 buf_incrwritepos(buf, len); | |
540 } while (len < maxlen && len > 0); | |
541 | |
542 close(fd); | |
543 return DROPBEAR_SUCCESS; | |
544 } | |
545 | |
546 /* get a line from the file into buffer in the style expected for an | |
547 * authkeys file. | |
548 * Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/ | |
549 /* Only used for ~/.ssh/known_hosts and ~/.ssh/authorized_keys */ | |
550 #if defined(DROPBEAR_CLIENT) || defined(ENABLE_SVR_PUBKEY_AUTH) | |
551 int buf_getline(buffer * line, FILE * authfile) { | |
552 | |
553 int c = EOF; | |
554 | |
555 TRACE(("enter buf_getline")) | |
556 | |
557 buf_setpos(line, 0); | |
558 buf_setlen(line, 0); | |
559 | |
560 while (line->pos < line->size) { | |
561 | |
562 c = fgetc(authfile); /*getc() is weird with some uClibc systems*/ | |
563 if (c == EOF || c == '\n' || c == '\r') { | |
564 goto out; | |
565 } | |
566 | |
567 buf_putbyte(line, (unsigned char)c); | |
568 } | |
569 | |
570 TRACE(("leave getauthline: line too long")) | |
571 /* We return success, but the line length will be zeroed - ie we just | |
572 * ignore that line */ | |
573 buf_setlen(line, 0); | |
574 | |
575 out: | |
576 | |
577 | |
578 /* if we didn't read anything before EOF or error, exit */ | |
579 if (c == EOF && line->pos == 0) { | |
580 TRACE(("leave buf_getline: failure")) | |
581 return DROPBEAR_FAILURE; | |
582 } else { | |
583 TRACE(("leave buf_getline: success")) | |
584 buf_setpos(line, 0); | |
585 return DROPBEAR_SUCCESS; | |
586 } | |
587 | |
588 } | |
589 #endif | |
590 | |
591 /* make sure that the socket closes */ | |
592 void m_close(int fd) { | |
593 | |
594 int val; | |
595 do { | |
596 val = close(fd); | |
597 } while (val < 0 && errno == EINTR); | |
598 | |
599 if (val < 0 && errno != EBADF) { | |
600 /* Linux says EIO can happen */ | |
601 dropbear_exit("Error closing fd %d, %s", fd, strerror(errno)); | |
602 } | |
603 } | |
604 | |
605 void * m_malloc(size_t size) { | |
606 | |
607 void* ret; | |
608 | |
609 if (size == 0) { | |
610 dropbear_exit("m_malloc failed"); | |
611 } | |
612 ret = calloc(1, size); | |
613 if (ret == NULL) { | |
614 dropbear_exit("m_malloc failed"); | |
615 } | |
616 return ret; | |
617 | |
618 } | |
619 | |
620 void * m_strdup(const char * str) { | |
621 char* ret; | |
622 | |
623 ret = strdup(str); | |
624 if (ret == NULL) { | |
625 dropbear_exit("m_strdup failed"); | |
626 } | |
627 return ret; | |
628 } | |
629 | |
630 void __m_free(void* ptr) { | |
631 if (ptr != NULL) { | |
632 free(ptr); | |
633 } | |
634 } | |
635 | |
636 void * m_realloc(void* ptr, size_t size) { | |
637 | |
638 void *ret; | |
639 | |
640 if (size == 0) { | |
641 dropbear_exit("m_realloc failed"); | |
642 } | |
643 ret = realloc(ptr, size); | |
644 if (ret == NULL) { | |
645 dropbear_exit("m_realloc failed"); | |
646 } | |
647 return ret; | |
648 } | |
649 | |
650 /* Clear the data, based on the method in David Wheeler's | |
651 * "Secure Programming for Linux and Unix HOWTO" */ | |
652 /* Beware of calling this from within dbutil.c - things might get | |
653 * optimised away */ | |
654 void m_burn(void *data, unsigned int len) { | |
655 volatile char *p = data; | |
656 | |
657 if (data == NULL) | |
658 return; | |
659 while (len--) { | |
660 *p++ = 0x66; | |
661 } | |
662 } | |
663 | |
664 | |
665 void setnonblocking(int fd) { | |
666 | |
667 TRACE(("setnonblocking: %d", fd)) | |
668 | |
669 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { | |
670 if (errno == ENODEV) { | |
671 /* Some devices (like /dev/null redirected in) | |
672 * can't be set to non-blocking */ | |
673 TRACE(("ignoring ENODEV for setnonblocking")) | |
674 } else { | |
675 dropbear_exit("Couldn't set nonblocking"); | |
676 } | |
677 } | |
678 TRACE(("leave setnonblocking")) | |
679 } |