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 */