Mercurial > dropbear
comparison dbutil.c @ 641:2b1bb792cd4d dropbear-tfm
- Update tfm changes to current default tip
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Mon, 21 Nov 2011 19:52:28 +0800 |
parents | 452bcf810e44 |
children | df11cb6a3665 76e780c74a5e |
comparison
equal
deleted
inserted
replaced
640:76097ec1a29a | 641:2b1bb792cd4d |
---|---|
55 #include "atomicio.h" | 55 #include "atomicio.h" |
56 | 56 |
57 #define MAX_FMT 100 | 57 #define MAX_FMT 100 |
58 | 58 |
59 static void generic_dropbear_exit(int exitcode, const char* format, | 59 static void generic_dropbear_exit(int exitcode, const char* format, |
60 va_list param); | 60 va_list param) ATTRIB_NORETURN; |
61 static void generic_dropbear_log(int priority, const char* format, | 61 static void generic_dropbear_log(int priority, const char* format, |
62 va_list param); | 62 va_list param); |
63 | 63 |
64 void (*_dropbear_exit)(int exitcode, const char* format, va_list param) | 64 void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN |
65 = generic_dropbear_exit; | 65 = generic_dropbear_exit; |
66 void (*_dropbear_log)(int priority, const char* format, va_list param) | 66 void (*_dropbear_log)(int priority, const char* format, va_list param) |
67 = generic_dropbear_log; | 67 = generic_dropbear_log; |
68 | 68 |
69 #ifdef DEBUG_TRACE | 69 #ifdef DEBUG_TRACE |
109 | 109 |
110 exit(exitcode); | 110 exit(exitcode); |
111 } | 111 } |
112 | 112 |
113 void 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); | 114 dropbear_exit("Failed assertion (%s:%d): `%s'", file, line, expr); |
115 } | 115 } |
116 | 116 |
117 static void generic_dropbear_log(int UNUSED(priority), const char* format, | 117 static void generic_dropbear_log(int UNUSED(priority), const char* format, |
118 va_list param) { | 118 va_list param) { |
119 | 119 |
159 | 159 |
160 /* disable nagle */ | 160 /* disable nagle */ |
161 val = 1; | 161 val = 1; |
162 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val)); | 162 setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val)); |
163 | 163 |
164 /* set the TOS bit. note that this will fail for ipv6, I can't find any | 164 /* set the TOS bit for either ipv4 or ipv6 */ |
165 * equivalent. */ | |
166 #ifdef IPTOS_LOWDELAY | 165 #ifdef IPTOS_LOWDELAY |
167 val = IPTOS_LOWDELAY; | 166 val = IPTOS_LOWDELAY; |
167 #if defined(IPPROTO_IPV6) && defined(IPV6_TCLASS) | |
168 setsockopt(sock, IPPROTO_IPV6, IPV6_TCLASS, (void*)&val, sizeof(val)); | |
169 #endif | |
168 setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val)); | 170 setsockopt(sock, IPPROTO_IP, IP_TOS, (void*)&val, sizeof(val)); |
169 #endif | 171 #endif |
170 | 172 |
171 #ifdef SO_PRIORITY | 173 #ifdef SO_PRIORITY |
172 /* linux specific, sets QoS class. | 174 /* linux specific, sets QoS class. |
252 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val)); | 254 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val)); |
253 linger.l_onoff = 1; | 255 linger.l_onoff = 1; |
254 linger.l_linger = 5; | 256 linger.l_linger = 5; |
255 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger)); | 257 setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger)); |
256 | 258 |
259 #if defined(IPPROTO_IPV6) && defined(IPV6_V6ONLY) | |
260 if (res->ai_family == AF_INET6) { | |
261 int on = 1; | |
262 if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, | |
263 &on, sizeof(on)) == -1) { | |
264 dropbear_log(LOG_WARNING, "Couldn't set IPV6_V6ONLY"); | |
265 } | |
266 } | |
267 #endif | |
268 | |
257 set_sock_priority(sock); | 269 set_sock_priority(sock); |
258 | 270 |
259 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { | 271 if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { |
260 err = errno; | 272 err = errno; |
261 close(sock); | 273 close(sock); |
292 } | 304 } |
293 | 305 |
294 TRACE(("leave dropbear_listen: success, %d socks bound", nsock)) | 306 TRACE(("leave dropbear_listen: success, %d socks bound", nsock)) |
295 return nsock; | 307 return nsock; |
296 } | 308 } |
309 | |
310 /* Connect to a given unix socket. The socket is blocking */ | |
311 #ifdef ENABLE_CONNECT_UNIX | |
312 int connect_unix(const char* path) { | |
313 struct sockaddr_un addr; | |
314 int fd = -1; | |
315 | |
316 memset((void*)&addr, 0x0, sizeof(addr)); | |
317 addr.sun_family = AF_UNIX; | |
318 strlcpy(addr.sun_path, path, sizeof(addr.sun_path)); | |
319 fd = socket(PF_UNIX, SOCK_STREAM, 0); | |
320 if (fd < 0) { | |
321 TRACE(("Failed to open unix socket")) | |
322 return -1; | |
323 } | |
324 if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { | |
325 TRACE(("Failed to connect to '%s' socket", path)) | |
326 m_close(fd); | |
327 return -1; | |
328 } | |
329 return fd; | |
330 } | |
331 #endif | |
297 | 332 |
298 /* Connect via TCP to a host. Connection will try ipv4 or ipv6, will | 333 /* Connect via TCP to a host. Connection will try ipv4 or ipv6, will |
299 * return immediately if nonblocking is set. On failure, if errstring | 334 * return immediately if nonblocking is set. On failure, if errstring |
300 * wasn't null, it will be a newly malloced error message */ | 335 * wasn't null, it will be a newly malloced error message */ |
301 | 336 |
339 err = errno; | 374 err = errno; |
340 continue; | 375 continue; |
341 } | 376 } |
342 | 377 |
343 if (nonblocking) { | 378 if (nonblocking) { |
344 if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) { | 379 setnonblocking(sock); |
345 close(sock); | |
346 sock = -1; | |
347 if (errstring != NULL && *errstring == NULL) { | |
348 *errstring = m_strdup("Failed non-blocking"); | |
349 } | |
350 TRACE(("Failed non-blocking: %s", strerror(errno))) | |
351 continue; | |
352 } | |
353 } | 380 } |
354 | 381 |
355 if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) { | 382 if (connect(sock, res->ai_addr, res->ai_addrlen) < 0) { |
356 if (errno == EINPROGRESS && nonblocking) { | 383 if (errno == EINPROGRESS && nonblocking) { |
357 TRACE(("Connect in progress")) | 384 TRACE(("Connect in progress")) |
439 | 466 |
440 if ((dup2(infds[FDIN], STDIN_FILENO) < 0) || | 467 if ((dup2(infds[FDIN], STDIN_FILENO) < 0) || |
441 (dup2(outfds[FDOUT], STDOUT_FILENO) < 0) || | 468 (dup2(outfds[FDOUT], STDOUT_FILENO) < 0) || |
442 (ret_errfd && dup2(errfds[FDOUT], STDERR_FILENO) < 0)) { | 469 (ret_errfd && dup2(errfds[FDOUT], STDERR_FILENO) < 0)) { |
443 TRACE(("leave noptycommand: error redirecting FDs")) | 470 TRACE(("leave noptycommand: error redirecting FDs")) |
444 dropbear_exit("child dup2() failure"); | 471 dropbear_exit("Child dup2() failure"); |
445 } | 472 } |
446 | 473 |
447 close(infds[FDOUT]); | 474 close(infds[FDOUT]); |
448 close(infds[FDIN]); | 475 close(infds[FDIN]); |
449 close(outfds[FDIN]); | 476 close(outfds[FDIN]); |
523 } | 550 } |
524 | 551 |
525 execv(usershell, argv); | 552 execv(usershell, argv); |
526 } | 553 } |
527 | 554 |
555 void get_socket_address(int fd, char **local_host, char **local_port, | |
556 char **remote_host, char **remote_port, int host_lookup) | |
557 { | |
558 struct sockaddr_storage addr; | |
559 socklen_t addrlen; | |
560 | |
561 if (local_host || local_port) { | |
562 addrlen = sizeof(addr); | |
563 if (getsockname(fd, (struct sockaddr*)&addr, &addrlen) < 0) { | |
564 dropbear_exit("Failed socket address: %s", strerror(errno)); | |
565 } | |
566 getaddrstring(&addr, local_host, local_port, host_lookup); | |
567 } | |
568 if (remote_host || remote_port) { | |
569 addrlen = sizeof(addr); | |
570 if (getpeername(fd, (struct sockaddr*)&addr, &addrlen) < 0) { | |
571 dropbear_exit("Failed socket address: %s", strerror(errno)); | |
572 } | |
573 getaddrstring(&addr, remote_host, remote_port, host_lookup); | |
574 } | |
575 } | |
576 | |
528 /* Return a string representation of the socket address passed. The return | 577 /* Return a string representation of the socket address passed. The return |
529 * value is allocated with malloc() */ | 578 * value is allocated with malloc() */ |
530 unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) { | 579 void getaddrstring(struct sockaddr_storage* addr, |
531 | 580 char **ret_host, char **ret_port, |
532 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; | 581 int host_lookup) { |
533 char *retstring = NULL; | 582 |
583 char host[NI_MAXHOST+1], serv[NI_MAXSERV+1]; | |
584 unsigned int len; | |
534 int ret; | 585 int ret; |
535 unsigned int len; | 586 |
587 int flags = NI_NUMERICSERV | NI_NUMERICHOST; | |
588 | |
589 #ifndef DO_HOST_LOOKUP | |
590 host_lookup = 0; | |
591 #endif | |
592 | |
593 if (host_lookup) { | |
594 flags = NI_NUMERICSERV; | |
595 } | |
536 | 596 |
537 len = sizeof(struct sockaddr_storage); | 597 len = sizeof(struct sockaddr_storage); |
538 /* Some platforms such as Solaris 8 require that len is the length | 598 /* Some platforms such as Solaris 8 require that len is the length |
539 * of the specific structure. Some older linux systems (glibc 2.1.3 | 599 * of the specific structure. Some older linux systems (glibc 2.1.3 |
540 * such as debian potato) have sockaddr_storage.__ss_family instead | 600 * such as debian potato) have sockaddr_storage.__ss_family instead |
548 len = sizeof(struct sockaddr_in6); | 608 len = sizeof(struct sockaddr_in6); |
549 } | 609 } |
550 #endif | 610 #endif |
551 #endif | 611 #endif |
552 | 612 |
553 ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf), | 613 ret = getnameinfo((struct sockaddr*)addr, len, host, sizeof(host)-1, |
554 sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST); | 614 serv, sizeof(serv)-1, flags); |
555 | 615 |
556 if (ret != 0) { | 616 if (ret != 0) { |
557 /* This is a fairly bad failure - it'll fallback to IP if it | 617 if (host_lookup) { |
558 * just can't resolve */ | 618 /* On some systems (Darwin does it) we get EINTR from getnameinfo |
559 dropbear_exit("failed lookup (%d, %d)", ret, errno); | 619 * somehow. Eew. So we'll just return the IP, since that doesn't seem |
560 } | 620 * to exhibit that behaviour. */ |
561 | 621 getaddrstring(addr, ret_host, ret_port, 0); |
562 if (withport) { | 622 return; |
563 len = strlen(hbuf) + 2 + strlen(sbuf); | 623 } else { |
564 retstring = (char*)m_malloc(len); | 624 /* if we can't do a numeric lookup, something's gone terribly wrong */ |
565 snprintf(retstring, len, "%s:%s", hbuf, sbuf); | 625 dropbear_exit("Failed lookup: %s", gai_strerror(ret)); |
566 } else { | 626 } |
567 retstring = m_strdup(hbuf); | 627 } |
568 } | 628 |
569 | 629 if (ret_host) { |
570 return retstring; | 630 *ret_host = m_strdup(host); |
571 | 631 } |
572 } | 632 if (ret_port) { |
573 | 633 *ret_port = m_strdup(serv); |
574 /* Get the hostname corresponding to the address addr. On failure, the IP | 634 } |
575 * address is returned. The return value is allocated with strdup() */ | |
576 char* getaddrhostname(struct sockaddr_storage * addr) { | |
577 | |
578 char hbuf[NI_MAXHOST]; | |
579 char sbuf[NI_MAXSERV]; | |
580 int ret; | |
581 unsigned int len; | |
582 #ifdef DO_HOST_LOOKUP | |
583 const int flags = NI_NUMERICSERV; | |
584 #else | |
585 const int flags = NI_NUMERICHOST | NI_NUMERICSERV; | |
586 #endif | |
587 | |
588 len = sizeof(struct sockaddr_storage); | |
589 /* Some platforms such as Solaris 8 require that len is the length | |
590 * of the specific structure. */ | |
591 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY | |
592 if (addr->ss_family == AF_INET) { | |
593 len = sizeof(struct sockaddr_in); | |
594 } | |
595 #ifdef AF_INET6 | |
596 if (addr->ss_family == AF_INET6) { | |
597 len = sizeof(struct sockaddr_in6); | |
598 } | |
599 #endif | |
600 #endif | |
601 | |
602 | |
603 ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf), | |
604 sbuf, sizeof(sbuf), flags); | |
605 | |
606 if (ret != 0) { | |
607 /* On some systems (Darwin does it) we get EINTR from getnameinfo | |
608 * somehow. Eew. So we'll just return the IP, since that doesn't seem | |
609 * to exhibit that behaviour. */ | |
610 return getaddrstring(addr, 0); | |
611 } | |
612 | |
613 return m_strdup(hbuf); | |
614 } | 635 } |
615 | 636 |
616 #ifdef DEBUG_TRACE | 637 #ifdef DEBUG_TRACE |
617 void printhex(const char * label, const unsigned char * buf, int len) { | 638 void printhex(const char * label, const unsigned char * buf, int len) { |
618 | 639 |