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 }