Mercurial > dropbear
comparison dbutil.c @ 389:5ff8218bcee9
propagate from branch 'au.asn.ucc.matt.ltm.dropbear' (head 2af95f00ebd5bb7a28b3817db1218442c935388e)
to branch 'au.asn.ucc.matt.dropbear' (head ecd779509ef23a8cdf64888904fc9b31d78aa933)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 11 Jan 2007 03:14:55 +0000 |
parents | e81d3bc1dc78 |
children | b895f91c2ee6 |
comparison
equal
deleted
inserted
replaced
388:fb54020f78e1 | 389:5ff8218bcee9 |
---|---|
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. 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 } |