Mercurial > dropbear
comparison svr-chansession.c @ 1510:eb4c7052f51d coverity
merge coverity up to date
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sat, 17 Feb 2018 11:29:17 +0800 |
parents | 47f36d8565cf |
children | 79eef94ccea9 |
comparison
equal
deleted
inserted
replaced
1509:3520d7c25363 | 1510:eb4c7052f51d |
---|---|
78 struct ChanSess *chansess = (struct ChanSess*)channel->typedata; | 78 struct ChanSess *chansess = (struct ChanSess*)channel->typedata; |
79 TRACE(("sesscheckclose, pid is %d", chansess->exit.exitpid)) | 79 TRACE(("sesscheckclose, pid is %d", chansess->exit.exitpid)) |
80 return chansess->exit.exitpid != -1; | 80 return chansess->exit.exitpid != -1; |
81 } | 81 } |
82 | 82 |
83 void svr_chansess_checksignal(void) { | |
84 int status; | |
85 pid_t pid; | |
86 | |
87 if (!ses.channel_signal_pending) { | |
88 return; | |
89 } | |
90 | |
91 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { | |
92 unsigned int i; | |
93 struct exitinfo *ex = NULL; | |
94 TRACE(("sigchld handler: pid %d", pid)) | |
95 | |
96 ex = NULL; | |
97 /* find the corresponding chansess */ | |
98 for (i = 0; i < svr_ses.childpidsize; i++) { | |
99 if (svr_ses.childpids[i].pid == pid) { | |
100 TRACE(("found match session")); | |
101 ex = &svr_ses.childpids[i].chansess->exit; | |
102 break; | |
103 } | |
104 } | |
105 | |
106 /* If the pid wasn't matched, then we might have hit the race mentioned | |
107 * above. So we just store the info for the parent to deal with */ | |
108 if (ex == NULL) { | |
109 TRACE(("using lastexit")); | |
110 ex = &svr_ses.lastexit; | |
111 } | |
112 | |
113 ex->exitpid = pid; | |
114 if (WIFEXITED(status)) { | |
115 ex->exitstatus = WEXITSTATUS(status); | |
116 } | |
117 if (WIFSIGNALED(status)) { | |
118 ex->exitsignal = WTERMSIG(status); | |
119 #if !defined(AIX) && defined(WCOREDUMP) | |
120 ex->exitcore = WCOREDUMP(status); | |
121 #else | |
122 ex->exitcore = 0; | |
123 #endif | |
124 } else { | |
125 /* we use this to determine how pid exited */ | |
126 ex->exitsignal = -1; | |
127 } | |
128 | |
129 } | |
130 } | |
131 | |
83 /* Handler for childs exiting, store the state for return to the client */ | 132 /* Handler for childs exiting, store the state for return to the client */ |
84 | 133 |
85 /* There's a particular race we have to watch out for: if the forked child | 134 /* There's a particular race we have to watch out for: if the forked child |
86 * executes, exits, and this signal-handler is called, all before the parent | 135 * executes, exits, and this signal-handler is called, all before the parent |
87 * gets to run, then the childpids[] array won't have the pid in it. Hence we | 136 * gets to run, then the childpids[] array won't have the pid in it. Hence we |
88 * use the svr_ses.lastexit struct to hold the exit, which is then compared by | 137 * use the svr_ses.lastexit struct to hold the exit, which is then compared by |
89 * the parent when it runs. This work correctly at least in the case of a | 138 * the parent when it runs. This work correctly at least in the case of a |
90 * single shell spawned (ie the usual case) */ | 139 * single shell spawned (ie the usual case) */ |
91 static void sesssigchild_handler(int UNUSED(dummy)) { | 140 static void sesssigchild_handler(int UNUSED(dummy)) { |
92 | |
93 int status; | |
94 pid_t pid; | |
95 unsigned int i; | |
96 struct sigaction sa_chld; | 141 struct sigaction sa_chld; |
97 struct exitinfo *exit = NULL; | |
98 | 142 |
99 const int saved_errno = errno; | 143 const int saved_errno = errno; |
100 | 144 |
101 /* Make channel handling code look for closed channels */ | |
102 ses.channel_signal_pending = 1; | |
103 | |
104 TRACE(("enter sigchld handler")) | 145 TRACE(("enter sigchld handler")) |
105 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { | 146 |
106 TRACE(("sigchld handler: pid %d", pid)) | 147 /* Make sure that the main select() loop wakes up */ |
107 | 148 while (1) { |
108 exit = NULL; | 149 /* isserver is just a random byte to write. We can't do anything |
109 /* find the corresponding chansess */ | 150 about an error so should just ignore it */ |
110 for (i = 0; i < svr_ses.childpidsize; i++) { | 151 if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1 |
111 if (svr_ses.childpids[i].pid == pid) { | 152 || errno != EINTR) { |
112 TRACE(("found match session")); | 153 break; |
113 exit = &svr_ses.childpids[i].chansess->exit; | |
114 break; | |
115 } | |
116 } | |
117 | |
118 /* If the pid wasn't matched, then we might have hit the race mentioned | |
119 * above. So we just store the info for the parent to deal with */ | |
120 if (exit == NULL) { | |
121 TRACE(("using lastexit")); | |
122 exit = &svr_ses.lastexit; | |
123 } | |
124 | |
125 exit->exitpid = pid; | |
126 if (WIFEXITED(status)) { | |
127 exit->exitstatus = WEXITSTATUS(status); | |
128 } | |
129 if (WIFSIGNALED(status)) { | |
130 exit->exitsignal = WTERMSIG(status); | |
131 #if !defined(AIX) && defined(WCOREDUMP) | |
132 exit->exitcore = WCOREDUMP(status); | |
133 #else | |
134 exit->exitcore = 0; | |
135 #endif | |
136 } else { | |
137 /* we use this to determine how pid exited */ | |
138 exit->exitsignal = -1; | |
139 } | |
140 | |
141 /* Make sure that the main select() loop wakes up */ | |
142 while (1) { | |
143 /* isserver is just a random byte to write. We can't do anything | |
144 about an error so should just ignore it */ | |
145 if (write(ses.signal_pipe[1], &ses.isserver, 1) == 1 | |
146 || errno != EINTR) { | |
147 break; | |
148 } | |
149 } | 154 } |
150 } | 155 } |
151 | 156 |
152 sa_chld.sa_handler = sesssigchild_handler; | 157 sa_chld.sa_handler = sesssigchild_handler; |
153 sa_chld.sa_flags = SA_NOCLDSTOP; | 158 sa_chld.sa_flags = SA_NOCLDSTOP; |
656 /* TODO - send error - too long ? */ | 661 /* TODO - send error - too long ? */ |
657 return DROPBEAR_FAILURE; | 662 return DROPBEAR_FAILURE; |
658 } | 663 } |
659 } | 664 } |
660 if (issubsys) { | 665 if (issubsys) { |
661 #ifdef SFTPSERVER_PATH | 666 #if DROPBEAR_SFTPSERVER |
662 if ((cmdlen == 4) && strncmp(chansess->cmd, "sftp", 4) == 0) { | 667 if ((cmdlen == 4) && strncmp(chansess->cmd, "sftp", 4) == 0) { |
663 m_free(chansess->cmd); | 668 m_free(chansess->cmd); |
664 chansess->cmd = m_strdup(SFTPSERVER_PATH); | 669 chansess->cmd = m_strdup(SFTPSERVER_PATH); |
665 } else | 670 } else |
666 #endif | 671 #endif |
680 /* take public key option 'command' into account */ | 685 /* take public key option 'command' into account */ |
681 svr_pubkey_set_forced_command(chansess); | 686 svr_pubkey_set_forced_command(chansess); |
682 } | 687 } |
683 | 688 |
684 | 689 |
685 #ifdef LOG_COMMANDS | 690 #if LOG_COMMANDS |
686 if (chansess->cmd) { | 691 if (chansess->cmd) { |
687 dropbear_log(LOG_INFO, "User %s executing '%s'", | 692 dropbear_log(LOG_INFO, "User %s executing '%s'", |
688 ses.authstate.pw_name, chansess->cmd); | 693 ses.authstate.pw_name, chansess->cmd); |
689 } else { | 694 } else { |
690 dropbear_log(LOG_INFO, "User %s executing login shell", | 695 dropbear_log(LOG_INFO, "User %s executing login shell", |
767 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ | 772 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ |
768 static int ptycommand(struct Channel *channel, struct ChanSess *chansess) { | 773 static int ptycommand(struct Channel *channel, struct ChanSess *chansess) { |
769 | 774 |
770 pid_t pid; | 775 pid_t pid; |
771 struct logininfo *li = NULL; | 776 struct logininfo *li = NULL; |
772 #ifdef DO_MOTD | 777 #if DO_MOTD |
773 buffer * motdbuf = NULL; | 778 buffer * motdbuf = NULL; |
774 int len; | 779 int len; |
775 struct stat sb; | 780 struct stat sb; |
776 char *hushpath = NULL; | 781 char *hushpath = NULL; |
777 #endif | 782 #endif |
819 * terminal used for stdout with the dup2 above */ | 824 * terminal used for stdout with the dup2 above */ |
820 li = chansess_login_alloc(chansess); | 825 li = chansess_login_alloc(chansess); |
821 login_login(li); | 826 login_login(li); |
822 login_free_entry(li); | 827 login_free_entry(li); |
823 | 828 |
824 #ifdef DO_MOTD | 829 #if DO_MOTD |
825 if (svr_opts.domotd && !chansess->cmd) { | 830 if (svr_opts.domotd && !chansess->cmd) { |
826 /* don't show the motd if ~/.hushlogin exists */ | 831 /* don't show the motd if ~/.hushlogin exists */ |
827 | 832 |
828 /* 12 == strlen("/.hushlogin\0") */ | 833 /* 12 == strlen("/.hushlogin\0") */ |
829 len = strlen(ses.authstate.pw_dir) + 12; | 834 len = strlen(ses.authstate.pw_dir) + 12; |
897 } | 902 } |
898 | 903 |
899 /* Clean up, drop to user privileges, set up the environment and execute | 904 /* Clean up, drop to user privileges, set up the environment and execute |
900 * the command/shell. This function does not return. */ | 905 * the command/shell. This function does not return. */ |
901 static void execchild(const void *user_data) { | 906 static void execchild(const void *user_data) { |
902 struct ChanSess *chansess = user_data; | 907 const struct ChanSess *chansess = user_data; |
903 char *usershell = NULL; | 908 char *usershell = NULL; |
904 | 909 |
905 /* with uClinux we'll have vfork()ed, so don't want to overwrite the | 910 /* with uClinux we'll have vfork()ed, so don't want to overwrite the |
906 * hostkey. can't think of a workaround to clear it */ | 911 * hostkey. can't think of a workaround to clear it */ |
907 #if !DROPBEAR_VFORK | 912 #if !DROPBEAR_VFORK |