comparison svr-chansession.c @ 1511:5916af64acd4 fuzz

merge from main
author Matt Johnston <matt@ucc.asn.au>
date Sat, 17 Feb 2018 19:29:51 +0800
parents 47f36d8565cf
children 79eef94ccea9
comparison
equal deleted inserted replaced
1457:32f990cc96b1 1511:5916af64acd4
41 /* Handles sessions (either shells or programs) requested by the client */ 41 /* Handles sessions (either shells or programs) requested by the client */
42 42
43 static int sessioncommand(struct Channel *channel, struct ChanSess *chansess, 43 static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
44 int iscmd, int issubsys); 44 int iscmd, int issubsys);
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(const 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(const struct ChanSess *chansess);
50 static void execchild(void *user_data_chansess); 50 static void execchild(const 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(const 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);
56 static int sesscheckclose(struct Channel *channel); 56 static int sesscheckclose(const struct Channel *channel);
57 57
58 static void send_exitsignalstatus(struct Channel *channel); 58 static void send_exitsignalstatus(const struct Channel *channel);
59 static void send_msg_chansess_exitstatus(struct Channel * channel, 59 static void send_msg_chansess_exitstatus(const struct Channel * channel,
60 struct ChanSess * chansess); 60 const struct ChanSess * chansess);
61 static void send_msg_chansess_exitsignal(struct Channel * channel, 61 static void send_msg_chansess_exitsignal(const struct Channel * channel,
62 struct ChanSess * chansess); 62 const struct ChanSess * chansess);
63 static void get_termmodes(struct ChanSess *chansess); 63 static void get_termmodes(const struct ChanSess *chansess);
64 64
65 const struct ChanType svrchansess = { 65 const struct ChanType svrchansess = {
66 0, /* sepfds */ 66 0, /* sepfds */
67 "session", /* name */ 67 "session", /* name */
68 newchansess, /* inithandler */ 68 newchansess, /* inithandler */
72 }; 72 };
73 73
74 /* required to clear environment */ 74 /* required to clear environment */
75 extern char** environ; 75 extern char** environ;
76 76
77 static int sesscheckclose(struct Channel *channel) { 77 static int sesscheckclose(const struct Channel *channel) {
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 }
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 }
81 } 130 }
82 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
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;
157 162
158 errno = saved_errno; 163 errno = saved_errno;
159 } 164 }
160 165
161 /* send the exit status or the signal causing termination for a session */ 166 /* send the exit status or the signal causing termination for a session */
162 static void send_exitsignalstatus(struct Channel *channel) { 167 static void send_exitsignalstatus(const struct Channel *channel) {
163 168
164 struct ChanSess *chansess = (struct ChanSess*)channel->typedata; 169 struct ChanSess *chansess = (struct ChanSess*)channel->typedata;
165 170
166 if (chansess->exit.exitpid >= 0) { 171 if (chansess->exit.exitpid >= 0) {
167 if (chansess->exit.exitsignal > 0) { 172 if (chansess->exit.exitsignal > 0) {
171 } 176 }
172 } 177 }
173 } 178 }
174 179
175 /* send the exitstatus to the client */ 180 /* send the exitstatus to the client */
176 static void send_msg_chansess_exitstatus(struct Channel * channel, 181 static void send_msg_chansess_exitstatus(const struct Channel * channel,
177 struct ChanSess * chansess) { 182 const struct ChanSess * chansess) {
178 183
179 dropbear_assert(chansess->exit.exitpid != -1); 184 dropbear_assert(chansess->exit.exitpid != -1);
180 dropbear_assert(chansess->exit.exitsignal == -1); 185 dropbear_assert(chansess->exit.exitsignal == -1);
181 186
182 CHECKCLEARTOWRITE(); 187 CHECKCLEARTOWRITE();
190 encrypt_packet(); 195 encrypt_packet();
191 196
192 } 197 }
193 198
194 /* send the signal causing the exit to the client */ 199 /* send the signal causing the exit to the client */
195 static void send_msg_chansess_exitsignal(struct Channel * channel, 200 static void send_msg_chansess_exitsignal(const struct Channel * channel,
196 struct ChanSess * chansess) { 201 const struct ChanSess * chansess) {
197 202
198 int i; 203 int i;
199 char* signame = NULL; 204 char* signame = NULL;
200 dropbear_assert(chansess->exit.exitpid != -1); 205 dropbear_assert(chansess->exit.exitpid != -1);
201 dropbear_assert(chansess->exit.exitsignal > 0); 206 dropbear_assert(chansess->exit.exitsignal > 0);
271 return 0; 276 return 0;
272 277
273 } 278 }
274 279
275 static struct logininfo* 280 static struct logininfo*
276 chansess_login_alloc(struct ChanSess *chansess) { 281 chansess_login_alloc(const struct ChanSess *chansess) {
277 struct logininfo * li; 282 struct logininfo * li;
278 li = login_alloc_entry(chansess->pid, ses.authstate.username, 283 li = login_alloc_entry(chansess->pid, ses.authstate.username,
279 svr_ses.remotehost, chansess->tty); 284 svr_ses.remotehost, chansess->tty);
280 return li; 285 return li;
281 } 286 }
282 287
283 /* clean a session channel */ 288 /* clean a session channel */
284 static void closechansess(struct Channel *channel) { 289 static void closechansess(const struct Channel *channel) {
285 290
286 struct ChanSess *chansess; 291 struct ChanSess *chansess;
287 unsigned int i; 292 unsigned int i;
288 struct logininfo *li; 293 struct logininfo *li;
289 294
401 TRACE(("leave chansessionrequest")) 406 TRACE(("leave chansessionrequest"))
402 } 407 }
403 408
404 409
405 /* Send a signal to a session's process as requested by the client*/ 410 /* Send a signal to a session's process as requested by the client*/
406 static int sessionsignal(struct ChanSess *chansess) { 411 static int sessionsignal(const struct ChanSess *chansess) {
407 412
408 int sig = 0; 413 int sig = 0;
409 char* signame = NULL; 414 char* signame = NULL;
410 int i; 415 int i;
411 416
439 return DROPBEAR_SUCCESS; 444 return DROPBEAR_SUCCESS;
440 } 445 }
441 446
442 /* Let the process know that the window size has changed, as notified from the 447 /* Let the process know that the window size has changed, as notified from the
443 * client. Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ 448 * client. Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
444 static int sessionwinchange(struct ChanSess *chansess) { 449 static int sessionwinchange(const struct ChanSess *chansess) {
445 450
446 int termc, termr, termw, termh; 451 int termc, termr, termw, termh;
447 452
448 if (chansess->master < 0) { 453 if (chansess->master < 0) {
449 /* haven't got a pty yet */ 454 /* haven't got a pty yet */
458 pty_change_window_size(chansess->master, termr, termc, termw, termh); 463 pty_change_window_size(chansess->master, termr, termc, termw, termh);
459 464
460 return DROPBEAR_SUCCESS; 465 return DROPBEAR_SUCCESS;
461 } 466 }
462 467
463 static void get_termmodes(struct ChanSess *chansess) { 468 static void get_termmodes(const struct ChanSess *chansess) {
464 469
465 struct termios termio; 470 struct termios termio;
466 unsigned char opcode; 471 unsigned char opcode;
467 unsigned int value; 472 unsigned int value;
468 const struct TermCode * termcode; 473 const struct TermCode * termcode;
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;
896 901
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(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