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 59static void generic_dropbear_exit(int exitcode, const char* format, 60 va_list param); 61static void generic_dropbear_log(int priority, const char* format, 62 va_list param); 63 64void (*_dropbear_exit)(int exitcode, const char* format, va_list param) 65 = generic_dropbear_exit; 66void (*_dropbear_log)(int priority, const char* format, va_list param) 67 = generic_dropbear_log; 68 69#ifdef DEBUG_TRACE 70int debug_trace = 0; 71#endif 72 73#ifndef DISABLE_SYSLOG 74void startsyslog() { 75 76 openlog(PROGNAME, LOG_PID, LOG_AUTHPRIV); 77 78} 79#endif /* DISABLE_SYSLOG */ 80 81/* the "format" string must be <= 100 characters */ 82void 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 92void 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 101static 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 113void fail_assert(const char* expr, const char* file, int line) { 114 dropbear_exit("failed assertion (%s:%d): `%s'", file, line, expr); 115} 116 117static 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 */ 129void 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 140void 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 156static 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.*/ 186int 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 */ 303int 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() */ 394unsigned 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() */ 440char* 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 481void 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 */ 503char * 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 */ 528int 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 555out: 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) 567int 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 591out: 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 */ 608void 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 621void * 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 636void * 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 646void __m_free(void* ptr) { 647 if (ptr != NULL) { 648 free(ptr); 649 } 650} 651 652void * 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 */ 670void 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 681void 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 697void disallow_core() { 698 struct rlimit lim; 699 lim.rlim_cur = lim.rlim_max = 0; 700 setrlimit(RLIMIT_CORE, &lim); 701} 702