Mercurial > dropbear
comparison svr-chansession.c @ 481:357a2e2e9bcc
- Generalise spawn_command function
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Mon, 15 Sep 2008 13:41:18 +0000 |
parents | c302c7383282 |
children | 7ad49f34a122 |
comparison
equal
deleted
inserted
replaced
480:c302c7383282 | 481:357a2e2e9bcc |
---|---|
45 static int sessionpty(struct ChanSess * chansess); | 45 static int sessionpty(struct ChanSess * chansess); |
46 static int sessionsignal(struct ChanSess *chansess); | 46 static int sessionsignal(struct ChanSess *chansess); |
47 static int noptycommand(struct Channel *channel, struct ChanSess *chansess); | 47 static int noptycommand(struct Channel *channel, struct ChanSess *chansess); |
48 static int ptycommand(struct Channel *channel, struct ChanSess *chansess); | 48 static int ptycommand(struct Channel *channel, struct ChanSess *chansess); |
49 static int sessionwinchange(struct ChanSess *chansess); | 49 static int sessionwinchange(struct ChanSess *chansess); |
50 static void execchild(struct ChanSess *chansess); | 50 static void execchild(void *user_data_chansess); |
51 static void addchildpid(struct ChanSess *chansess, pid_t pid); | 51 static void addchildpid(struct ChanSess *chansess, pid_t pid); |
52 static void sesssigchild_handler(int val); | 52 static void sesssigchild_handler(int val); |
53 static void closechansess(struct Channel *channel); | 53 static void closechansess(struct Channel *channel); |
54 static int newchansess(struct Channel *channel); | 54 static int newchansess(struct Channel *channel); |
55 static void chansessionrequest(struct Channel *channel); | 55 static void chansessionrequest(struct Channel *channel); |
631 | 631 |
632 /* Execute a command and set up redirection of stdin/stdout/stderr without a | 632 /* Execute a command and set up redirection of stdin/stdout/stderr without a |
633 * pty. | 633 * pty. |
634 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ | 634 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ |
635 static int noptycommand(struct Channel *channel, struct ChanSess *chansess) { | 635 static int noptycommand(struct Channel *channel, struct ChanSess *chansess) { |
636 | 636 int ret; |
637 int infds[2]; | |
638 int outfds[2]; | |
639 int errfds[2]; | |
640 pid_t pid; | |
641 unsigned int i; | |
642 | |
643 const int FDIN = 0; | |
644 const int FDOUT = 1; | |
645 | 637 |
646 TRACE(("enter noptycommand")) | 638 TRACE(("enter noptycommand")) |
647 | 639 ret = spawn_command(execchild, chansess, |
648 /* redirect stdin/stdout/stderr */ | 640 &channel->writefd, &channel->readfd, &channel->errfd, |
649 if (pipe(infds) != 0) | 641 &chansess->pid); |
650 return DROPBEAR_FAILURE; | 642 |
651 if (pipe(outfds) != 0) | 643 if (ret == DROPBEAR_FAILURE) { |
652 return DROPBEAR_FAILURE; | 644 return ret; |
653 if (pipe(errfds) != 0) | 645 } |
654 return DROPBEAR_FAILURE; | 646 |
655 | 647 ses.maxfd = MAX(ses.maxfd, channel->writefd); |
656 #ifdef __uClinux__ | 648 ses.maxfd = MAX(ses.maxfd, channel->readfd); |
657 pid = vfork(); | 649 ses.maxfd = MAX(ses.maxfd, channel->errfd); |
658 #else | 650 |
659 pid = fork(); | 651 addchildpid(chansess, chansess->pid); |
660 #endif | 652 |
661 | 653 if (svr_ses.lastexit.exitpid != -1) { |
662 if (pid < 0) | 654 TRACE(("parent side: lastexitpid is %d", svr_ses.lastexit.exitpid)) |
663 return DROPBEAR_FAILURE; | 655 /* The child probably exited and the signal handler triggered |
664 | 656 * possibly before we got around to adding the childpid. So we fill |
665 if (!pid) { | 657 * out its data manually */ |
666 /* child */ | 658 int i; |
667 | 659 for (i = 0; i < svr_ses.childpidsize; i++) { |
668 TRACE(("back to normal sigchld")) | 660 if (svr_ses.childpids[i].pid == svr_ses.lastexit.exitpid) { |
669 /* Revert to normal sigchld handling */ | 661 TRACE(("found match for lastexitpid")) |
670 if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) { | 662 svr_ses.childpids[i].chansess->exit = svr_ses.lastexit; |
671 dropbear_exit("signal() error"); | 663 svr_ses.lastexit.exitpid = -1; |
672 } | |
673 | |
674 /* redirect stdin/stdout */ | |
675 | |
676 if ((dup2(infds[FDIN], STDIN_FILENO) < 0) || | |
677 (dup2(outfds[FDOUT], STDOUT_FILENO) < 0) || | |
678 (dup2(errfds[FDOUT], STDERR_FILENO) < 0)) { | |
679 TRACE(("leave noptycommand: error redirecting FDs")) | |
680 return DROPBEAR_FAILURE; | |
681 } | |
682 | |
683 close(infds[FDOUT]); | |
684 close(infds[FDIN]); | |
685 close(outfds[FDIN]); | |
686 close(outfds[FDOUT]); | |
687 close(errfds[FDIN]); | |
688 close(errfds[FDOUT]); | |
689 | |
690 execchild(chansess); | |
691 /* not reached */ | |
692 | |
693 } else { | |
694 /* parent */ | |
695 TRACE(("continue noptycommand: parent")) | |
696 chansess->pid = pid; | |
697 TRACE(("child pid is %d", pid)) | |
698 | |
699 addchildpid(chansess, pid); | |
700 | |
701 if (svr_ses.lastexit.exitpid != -1) { | |
702 TRACE(("parent side: lastexitpid is %d", svr_ses.lastexit.exitpid)) | |
703 /* The child probably exited and the signal handler triggered | |
704 * possibly before we got around to adding the childpid. So we fill | |
705 * out its data manually */ | |
706 for (i = 0; i < svr_ses.childpidsize; i++) { | |
707 if (svr_ses.childpids[i].pid == svr_ses.lastexit.exitpid) { | |
708 TRACE(("found match for lastexitpid")) | |
709 svr_ses.childpids[i].chansess->exit = svr_ses.lastexit; | |
710 svr_ses.lastexit.exitpid = -1; | |
711 } | |
712 } | 664 } |
713 } | 665 } |
714 | 666 } |
715 close(infds[FDIN]); | |
716 close(outfds[FDOUT]); | |
717 close(errfds[FDOUT]); | |
718 channel->writefd = infds[FDOUT]; | |
719 channel->readfd = outfds[FDIN]; | |
720 channel->errfd = errfds[FDIN]; | |
721 ses.maxfd = MAX(ses.maxfd, channel->writefd); | |
722 ses.maxfd = MAX(ses.maxfd, channel->readfd); | |
723 ses.maxfd = MAX(ses.maxfd, channel->errfd); | |
724 | |
725 setnonblocking(channel->readfd); | |
726 setnonblocking(channel->writefd); | |
727 setnonblocking(channel->errfd); | |
728 | |
729 } | |
730 #undef FDIN | |
731 #undef FDOUT | |
732 | 667 |
733 TRACE(("leave noptycommand")) | 668 TRACE(("leave noptycommand")) |
734 return DROPBEAR_SUCCESS; | 669 return DROPBEAR_SUCCESS; |
735 } | 670 } |
736 | 671 |
871 | 806 |
872 } | 807 } |
873 | 808 |
874 /* Clean up, drop to user privileges, set up the environment and execute | 809 /* Clean up, drop to user privileges, set up the environment and execute |
875 * the command/shell. This function does not return. */ | 810 * the command/shell. This function does not return. */ |
876 static void execchild(struct ChanSess *chansess) { | 811 static void execchild(void *user_data) { |
877 | 812 |
878 char *argv[4]; | 813 char *argv[4]; |
879 char * usershell = NULL; | 814 char * usershell = NULL; |
880 char * baseshell = NULL; | 815 char * baseshell = NULL; |
881 unsigned int i; | 816 unsigned int i; |
817 struct ChanSess *chansess = user_data; | |
882 | 818 |
883 /* with uClinux we'll have vfork()ed, so don't want to overwrite the | 819 /* with uClinux we'll have vfork()ed, so don't want to overwrite the |
884 * hostkey. can't think of a workaround to clear it */ | 820 * hostkey. can't think of a workaround to clear it */ |
885 #ifndef __uClinux__ | 821 #ifndef __uClinux__ |
886 /* wipe the hostkey */ | 822 /* wipe the hostkey */ |