Mercurial > dropbear
comparison dbutil.c @ 511:582cb38e4eb5 insecure-nocrypto
propagate from branch 'au.asn.ucc.matt.dropbear' (head cdcc3c729e29544e8b98a408e2dc60e4483dfd2a)
to branch 'au.asn.ucc.matt.dropbear.insecure-nocrypto' (head 0ca38a1cf349f7426ac9de34ebe4c3e3735effab)
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Thu, 06 Nov 2008 13:16:55 +0000 |
parents | b956d6151600 |
children | d588e3ea557a |
comparison
equal
deleted
inserted
replaced
361:461c4b1fb35f | 511:582cb38e4eb5 |
---|---|
144 if (!debug_trace) { | 144 if (!debug_trace) { |
145 return; | 145 return; |
146 } | 146 } |
147 | 147 |
148 va_start(param, format); | 148 va_start(param, format); |
149 fprintf(stderr, "TRACE: "); | 149 fprintf(stderr, "TRACE (%d): ", getpid()); |
150 vfprintf(stderr, format, param); | 150 vfprintf(stderr, format, param); |
151 fprintf(stderr, "\n"); | 151 fprintf(stderr, "\n"); |
152 va_end(param); | 152 va_end(param); |
153 } | 153 } |
154 #endif /* DEBUG_TRACE */ | 154 #endif /* DEBUG_TRACE */ |
197 | 197 |
198 memset(&hints, 0, sizeof(hints)); | 198 memset(&hints, 0, sizeof(hints)); |
199 hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */ | 199 hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */ |
200 hints.ai_socktype = SOCK_STREAM; | 200 hints.ai_socktype = SOCK_STREAM; |
201 | 201 |
202 // for calling getaddrinfo: | 202 /* for calling getaddrinfo: |
203 // address == NULL and !AI_PASSIVE: local loopback | 203 address == NULL and !AI_PASSIVE: local loopback |
204 // address == NULL and AI_PASSIVE: all interfaces | 204 address == NULL and AI_PASSIVE: all interfaces |
205 // address != NULL: whatever the address says | 205 address != NULL: whatever the address says */ |
206 if (!address) { | 206 if (!address) { |
207 TRACE(("dropbear_listen: local loopback")) | 207 TRACE(("dropbear_listen: local loopback")) |
208 } else { | 208 } else { |
209 if (address[0] == '\0') { | 209 if (address[0] == '\0') { |
210 TRACE(("dropbear_listen: all interfaces")) | 210 TRACE(("dropbear_listen: all interfaces")) |
284 if (errstring != NULL && *errstring == NULL) { | 284 if (errstring != NULL && *errstring == NULL) { |
285 int len; | 285 int len; |
286 len = 20 + strlen(strerror(err)); | 286 len = 20 + strlen(strerror(err)); |
287 *errstring = (char*)m_malloc(len); | 287 *errstring = (char*)m_malloc(len); |
288 snprintf(*errstring, len, "Error listening: %s", strerror(err)); | 288 snprintf(*errstring, len, "Error listening: %s", strerror(err)); |
289 TRACE(("leave dropbear_listen: failure, %s", strerror(err))) | 289 } |
290 return -1; | 290 TRACE(("leave dropbear_listen: failure, %s", strerror(err))) |
291 } | 291 return -1; |
292 } | 292 } |
293 | 293 |
294 TRACE(("leave dropbear_listen: success, %d socks bound", nsock)) | 294 TRACE(("leave dropbear_listen: success, %d socks bound", nsock)) |
295 return nsock; | 295 return nsock; |
296 } | 296 } |
319 | 319 |
320 err = getaddrinfo(remotehost, remoteport, &hints, &res0); | 320 err = getaddrinfo(remotehost, remoteport, &hints, &res0); |
321 if (err) { | 321 if (err) { |
322 if (errstring != NULL && *errstring == NULL) { | 322 if (errstring != NULL && *errstring == NULL) { |
323 int len; | 323 int len; |
324 len = 20 + strlen(gai_strerror(err)); | 324 len = 100 + strlen(gai_strerror(err)); |
325 *errstring = (char*)m_malloc(len); | 325 *errstring = (char*)m_malloc(len); |
326 snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err)); | 326 snprintf(*errstring, len, "Error resolving '%s' port '%s'. %s", |
327 remotehost, remoteport, gai_strerror(err)); | |
327 } | 328 } |
328 TRACE(("Error resolving: %s", gai_strerror(err))) | 329 TRACE(("Error resolving: %s", gai_strerror(err))) |
329 return -1; | 330 return -1; |
330 } | 331 } |
331 | 332 |
387 | 388 |
388 TRACE(("leave connect_remote: sock %d\n", sock)) | 389 TRACE(("leave connect_remote: sock %d\n", sock)) |
389 return sock; | 390 return sock; |
390 } | 391 } |
391 | 392 |
393 /* Sets up a pipe for a, returning three non-blocking file descriptors | |
394 * and the pid. exec_fn is the function that will actually execute the child process, | |
395 * it will be run after the child has fork()ed, and is passed exec_data. | |
396 * If ret_errfd == NULL then stderr will not be captured. | |
397 * ret_pid can be passed as NULL to discard the pid. */ | |
398 int spawn_command(void(*exec_fn)(void *user_data), void *exec_data, | |
399 int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) { | |
400 int infds[2]; | |
401 int outfds[2]; | |
402 int errfds[2]; | |
403 pid_t pid; | |
404 | |
405 const int FDIN = 0; | |
406 const int FDOUT = 1; | |
407 | |
408 /* redirect stdin/stdout/stderr */ | |
409 if (pipe(infds) != 0) { | |
410 return DROPBEAR_FAILURE; | |
411 } | |
412 if (pipe(outfds) != 0) { | |
413 return DROPBEAR_FAILURE; | |
414 } | |
415 if (ret_errfd && pipe(errfds) != 0) { | |
416 return DROPBEAR_FAILURE; | |
417 } | |
418 | |
419 #ifdef __uClinux__ | |
420 pid = vfork(); | |
421 #else | |
422 pid = fork(); | |
423 #endif | |
424 | |
425 if (pid < 0) { | |
426 return DROPBEAR_FAILURE; | |
427 } | |
428 | |
429 if (!pid) { | |
430 /* child */ | |
431 | |
432 TRACE(("back to normal sigchld")) | |
433 /* Revert to normal sigchld handling */ | |
434 if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) { | |
435 dropbear_exit("signal() error"); | |
436 } | |
437 | |
438 /* redirect stdin/stdout */ | |
439 | |
440 if ((dup2(infds[FDIN], STDIN_FILENO) < 0) || | |
441 (dup2(outfds[FDOUT], STDOUT_FILENO) < 0) || | |
442 (ret_errfd && dup2(errfds[FDOUT], STDERR_FILENO) < 0)) { | |
443 TRACE(("leave noptycommand: error redirecting FDs")) | |
444 dropbear_exit("child dup2() failure"); | |
445 } | |
446 | |
447 close(infds[FDOUT]); | |
448 close(infds[FDIN]); | |
449 close(outfds[FDIN]); | |
450 close(outfds[FDOUT]); | |
451 if (ret_errfd) | |
452 { | |
453 close(errfds[FDIN]); | |
454 close(errfds[FDOUT]); | |
455 } | |
456 | |
457 exec_fn(exec_data); | |
458 /* not reached */ | |
459 return DROPBEAR_FAILURE; | |
460 } else { | |
461 /* parent */ | |
462 close(infds[FDIN]); | |
463 close(outfds[FDOUT]); | |
464 | |
465 setnonblocking(outfds[FDIN]); | |
466 setnonblocking(infds[FDOUT]); | |
467 | |
468 if (ret_errfd) { | |
469 close(errfds[FDOUT]); | |
470 setnonblocking(errfds[FDIN]); | |
471 } | |
472 | |
473 if (ret_pid) { | |
474 *ret_pid = pid; | |
475 } | |
476 | |
477 *ret_writefd = infds[FDOUT]; | |
478 *ret_readfd = outfds[FDIN]; | |
479 if (ret_errfd) { | |
480 *ret_errfd = errfds[FDIN]; | |
481 } | |
482 return DROPBEAR_SUCCESS; | |
483 } | |
484 } | |
485 | |
486 /* Runs a command with "sh -c". Will close FDs (except stdin/stdout/stderr) and | |
487 * re-enabled SIGPIPE. If cmd is NULL, will run a login shell. | |
488 */ | |
489 void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) { | |
490 char * argv[4]; | |
491 char * baseshell = NULL; | |
492 unsigned int i; | |
493 | |
494 baseshell = basename(usershell); | |
495 | |
496 if (cmd != NULL) { | |
497 argv[0] = baseshell; | |
498 } else { | |
499 /* a login shell should be "-bash" for "/bin/bash" etc */ | |
500 int len = strlen(baseshell) + 2; /* 2 for "-" */ | |
501 argv[0] = (char*)m_malloc(len); | |
502 snprintf(argv[0], len, "-%s", baseshell); | |
503 } | |
504 | |
505 if (cmd != NULL) { | |
506 argv[1] = "-c"; | |
507 argv[2] = (char*)cmd; | |
508 argv[3] = NULL; | |
509 } else { | |
510 /* construct a shell of the form "-bash" etc */ | |
511 argv[1] = NULL; | |
512 } | |
513 | |
514 /* Re-enable SIGPIPE for the executed process */ | |
515 if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) { | |
516 dropbear_exit("signal() error"); | |
517 } | |
518 | |
519 /* close file descriptors except stdin/stdout/stderr | |
520 * Need to be sure FDs are closed here to avoid reading files as root */ | |
521 for (i = 3; i <= maxfd; i++) { | |
522 m_close(i); | |
523 } | |
524 | |
525 execv(usershell, argv); | |
526 } | |
527 | |
392 /* Return a string representation of the socket address passed. The return | 528 /* Return a string representation of the socket address passed. The return |
393 * value is allocated with malloc() */ | 529 * value is allocated with malloc() */ |
394 unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) { | 530 unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) { |
395 | 531 |
396 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; | 532 char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV]; |
398 int ret; | 534 int ret; |
399 unsigned int len; | 535 unsigned int len; |
400 | 536 |
401 len = sizeof(struct sockaddr_storage); | 537 len = sizeof(struct sockaddr_storage); |
402 /* Some platforms such as Solaris 8 require that len is the length | 538 /* Some platforms such as Solaris 8 require that len is the length |
403 * of the specific structure. */ | 539 * of the specific structure. Some older linux systems (glibc 2.1.3 |
540 * such as debian potato) have sockaddr_storage.__ss_family instead | |
541 * but we'll ignore them */ | |
542 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY | |
404 if (addr->ss_family == AF_INET) { | 543 if (addr->ss_family == AF_INET) { |
405 len = sizeof(struct sockaddr_in); | 544 len = sizeof(struct sockaddr_in); |
406 } | 545 } |
407 #ifdef AF_INET6 | 546 #ifdef AF_INET6 |
408 if (addr->ss_family == AF_INET6) { | 547 if (addr->ss_family == AF_INET6) { |
409 len = sizeof(struct sockaddr_in6); | 548 len = sizeof(struct sockaddr_in6); |
410 } | 549 } |
550 #endif | |
411 #endif | 551 #endif |
412 | 552 |
413 ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf), | 553 ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf), |
414 sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST); | 554 sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST); |
415 | 555 |
446 #endif | 586 #endif |
447 | 587 |
448 len = sizeof(struct sockaddr_storage); | 588 len = sizeof(struct sockaddr_storage); |
449 /* Some platforms such as Solaris 8 require that len is the length | 589 /* Some platforms such as Solaris 8 require that len is the length |
450 * of the specific structure. */ | 590 * of the specific structure. */ |
591 #ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY | |
451 if (addr->ss_family == AF_INET) { | 592 if (addr->ss_family == AF_INET) { |
452 len = sizeof(struct sockaddr_in); | 593 len = sizeof(struct sockaddr_in); |
453 } | 594 } |
454 #ifdef AF_INET6 | 595 #ifdef AF_INET6 |
455 if (addr->ss_family == AF_INET6) { | 596 if (addr->ss_family == AF_INET6) { |
456 len = sizeof(struct sockaddr_in6); | 597 len = sizeof(struct sockaddr_in6); |
457 } | 598 } |
599 #endif | |
458 #endif | 600 #endif |
459 | 601 |
460 | 602 |
461 ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf), | 603 ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf), |
462 sbuf, sizeof(sbuf), flags); | 604 sbuf, sizeof(sbuf), flags); |
519 /* reads the contents of filename into the buffer buf, from the current | 661 /* 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. | 662 * position, either to the end of the file, or the buffer being full. |
521 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ | 663 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ |
522 int buf_readfile(buffer* buf, const char* filename) { | 664 int buf_readfile(buffer* buf, const char* filename) { |
523 | 665 |
524 int fd; | 666 int fd = -1; |
525 int len; | 667 int len; |
526 int maxlen; | 668 int maxlen; |
669 int ret = DROPBEAR_FAILURE; | |
527 | 670 |
528 fd = open(filename, O_RDONLY); | 671 fd = open(filename, O_RDONLY); |
529 | 672 |
530 if (fd < 0) { | 673 if (fd < 0) { |
531 close(fd); | 674 goto out; |
532 return DROPBEAR_FAILURE; | |
533 } | 675 } |
534 | 676 |
535 do { | 677 do { |
536 maxlen = buf->size - buf->pos; | 678 maxlen = buf->size - buf->pos; |
537 len = read(fd, buf_getwriteptr(buf, maxlen), | 679 len = read(fd, buf_getwriteptr(buf, maxlen), maxlen); |
538 maxlen); | 680 if (len < 0) { |
681 if (errno == EINTR || errno == EAGAIN) { | |
682 continue; | |
683 } | |
684 goto out; | |
685 } | |
539 buf_incrwritepos(buf, len); | 686 buf_incrwritepos(buf, len); |
540 } while (len < maxlen && len > 0); | 687 } while (len < maxlen && len > 0); |
541 | 688 |
542 close(fd); | 689 ret = DROPBEAR_SUCCESS; |
543 return DROPBEAR_SUCCESS; | 690 |
691 out: | |
692 if (fd >= 0) { | |
693 m_close(fd); | |
694 } | |
695 return ret; | |
544 } | 696 } |
545 | 697 |
546 /* get a line from the file into buffer in the style expected for an | 698 /* get a line from the file into buffer in the style expected for an |
547 * authkeys file. | 699 * authkeys file. |
548 * Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/ | 700 * Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/ |
675 dropbear_exit("Couldn't set nonblocking"); | 827 dropbear_exit("Couldn't set nonblocking"); |
676 } | 828 } |
677 } | 829 } |
678 TRACE(("leave setnonblocking")) | 830 TRACE(("leave setnonblocking")) |
679 } | 831 } |
832 | |
833 void disallow_core() { | |
834 struct rlimit lim; | |
835 lim.rlim_cur = lim.rlim_max = 0; | |
836 setrlimit(RLIMIT_CORE, &lim); | |
837 } | |
838 | |
839 /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE, with the result in *val */ | |
840 int m_str_to_uint(const char* str, unsigned int *val) { | |
841 errno = 0; | |
842 *val = strtoul(str, NULL, 10); | |
843 /* The c99 spec doesn't actually seem to define EINVAL, but most platforms | |
844 * I've looked at mention it in their manpage */ | |
845 if ((*val == 0 && errno == EINVAL) | |
846 || (*val == ULONG_MAX && errno == ERANGE)) { | |
847 return DROPBEAR_FAILURE; | |
848 } else { | |
849 return DROPBEAR_SUCCESS; | |
850 } | |
851 } |