Mercurial > dropbear
comparison svr-chansession.c @ 165:0cfba3034be5
Fixed DEBUG_TRACE macro so that we don't get semicolons left about the place
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Sun, 02 Jan 2005 20:25:56 +0000 |
parents | b4cfe976c8e1 |
children | 8e68dbe8687b |
comparison
equal
deleted
inserted
replaced
161:b9d3f725e00b | 165:0cfba3034be5 |
---|---|
85 pid_t pid; | 85 pid_t pid; |
86 unsigned int i; | 86 unsigned int i; |
87 struct sigaction sa_chld; | 87 struct sigaction sa_chld; |
88 struct exitinfo *exit = NULL; | 88 struct exitinfo *exit = NULL; |
89 | 89 |
90 TRACE(("enter sigchld handler")); | 90 TRACE(("enter sigchld handler")) |
91 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { | 91 while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { |
92 /* find the corresponding chansess */ | 92 /* find the corresponding chansess */ |
93 for (i = 0; i < svr_ses.childpidsize; i++) { | 93 for (i = 0; i < svr_ses.childpidsize; i++) { |
94 if (svr_ses.childpids[i].pid == pid) { | 94 if (svr_ses.childpids[i].pid == pid) { |
95 | 95 |
124 | 124 |
125 | 125 |
126 sa_chld.sa_handler = sesssigchild_handler; | 126 sa_chld.sa_handler = sesssigchild_handler; |
127 sa_chld.sa_flags = SA_NOCLDSTOP; | 127 sa_chld.sa_flags = SA_NOCLDSTOP; |
128 sigaction(SIGCHLD, &sa_chld, NULL); | 128 sigaction(SIGCHLD, &sa_chld, NULL); |
129 TRACE(("leave sigchld handler")); | 129 TRACE(("leave sigchld handler")) |
130 } | 130 } |
131 | 131 |
132 /* send the exit status or the signal causing termination for a session */ | 132 /* send the exit status or the signal causing termination for a session */ |
133 /* XXX server */ | 133 /* XXX server */ |
134 static void send_exitsignalstatus(struct Channel *channel) { | 134 static void send_exitsignalstatus(struct Channel *channel) { |
246 | 246 |
247 chansess = (struct ChanSess*)channel->typedata; | 247 chansess = (struct ChanSess*)channel->typedata; |
248 | 248 |
249 send_exitsignalstatus(channel); | 249 send_exitsignalstatus(channel); |
250 | 250 |
251 TRACE(("enter closechansess")); | 251 TRACE(("enter closechansess")) |
252 if (chansess == NULL) { | 252 if (chansess == NULL) { |
253 TRACE(("leave closechansess: chansess == NULL")); | 253 TRACE(("leave closechansess: chansess == NULL")) |
254 return; | 254 return; |
255 } | 255 } |
256 | 256 |
257 m_free(chansess->cmd); | 257 m_free(chansess->cmd); |
258 m_free(chansess->term); | 258 m_free(chansess->term); |
278 | 278 |
279 /* clear child pid entries */ | 279 /* clear child pid entries */ |
280 for (i = 0; i < svr_ses.childpidsize; i++) { | 280 for (i = 0; i < svr_ses.childpidsize; i++) { |
281 if (svr_ses.childpids[i].chansess == chansess) { | 281 if (svr_ses.childpids[i].chansess == chansess) { |
282 assert(svr_ses.childpids[i].pid > 0); | 282 assert(svr_ses.childpids[i].pid > 0); |
283 TRACE(("closing pid %d", svr_ses.childpids[i].pid)); | 283 TRACE(("closing pid %d", svr_ses.childpids[i].pid)) |
284 TRACE(("exitpid = %d", chansess->exit.exitpid)); | 284 TRACE(("exitpid = %d", chansess->exit.exitpid)) |
285 svr_ses.childpids[i].pid = -1; | 285 svr_ses.childpids[i].pid = -1; |
286 svr_ses.childpids[i].chansess = NULL; | 286 svr_ses.childpids[i].chansess = NULL; |
287 } | 287 } |
288 } | 288 } |
289 | 289 |
290 m_free(chansess); | 290 m_free(chansess); |
291 | 291 |
292 TRACE(("leave closechansess")); | 292 TRACE(("leave closechansess")) |
293 } | 293 } |
294 | 294 |
295 /* Handle requests for a channel. These can be execution requests, | 295 /* Handle requests for a channel. These can be execution requests, |
296 * or x11/authagent forwarding. These are passed to appropriate handlers */ | 296 * or x11/authagent forwarding. These are passed to appropriate handlers */ |
297 static void chansessionrequest(struct Channel *channel) { | 297 static void chansessionrequest(struct Channel *channel) { |
300 unsigned int typelen; | 300 unsigned int typelen; |
301 unsigned char wantreply; | 301 unsigned char wantreply; |
302 int ret = 1; | 302 int ret = 1; |
303 struct ChanSess *chansess; | 303 struct ChanSess *chansess; |
304 | 304 |
305 TRACE(("enter chansessionrequest")); | 305 TRACE(("enter chansessionrequest")) |
306 | 306 |
307 type = buf_getstring(ses.payload, &typelen); | 307 type = buf_getstring(ses.payload, &typelen); |
308 wantreply = buf_getbyte(ses.payload); | 308 wantreply = buf_getbyte(ses.payload); |
309 | 309 |
310 if (typelen > MAX_NAME_LEN) { | 310 if (typelen > MAX_NAME_LEN) { |
311 TRACE(("leave chansessionrequest: type too long")); /* XXX send error?*/ | 311 TRACE(("leave chansessionrequest: type too long")) /* XXX send error?*/ |
312 goto out; | 312 goto out; |
313 } | 313 } |
314 | 314 |
315 chansess = (struct ChanSess*)channel->typedata; | 315 chansess = (struct ChanSess*)channel->typedata; |
316 assert(chansess != NULL); | 316 assert(chansess != NULL); |
317 TRACE(("type is %s", type)); | 317 TRACE(("type is %s", type)) |
318 | 318 |
319 if (strcmp(type, "window-change") == 0) { | 319 if (strcmp(type, "window-change") == 0) { |
320 ret = sessionwinchange(chansess); | 320 ret = sessionwinchange(chansess); |
321 } else if (strcmp(type, "shell") == 0) { | 321 } else if (strcmp(type, "shell") == 0) { |
322 ret = sessioncommand(channel, chansess, 0, 0); | 322 ret = sessioncommand(channel, chansess, 0, 0); |
349 send_msg_channel_failure(channel); | 349 send_msg_channel_failure(channel); |
350 } | 350 } |
351 } | 351 } |
352 | 352 |
353 m_free(type); | 353 m_free(type); |
354 TRACE(("leave chansessionrequest")); | 354 TRACE(("leave chansessionrequest")) |
355 } | 355 } |
356 | 356 |
357 | 357 |
358 /* Send a signal to a session's process as requested by the client*/ | 358 /* Send a signal to a session's process as requested by the client*/ |
359 static int sessionsignal(struct ChanSess *chansess) { | 359 static int sessionsignal(struct ChanSess *chansess) { |
419 unsigned char opcode; | 419 unsigned char opcode; |
420 unsigned int value; | 420 unsigned int value; |
421 const struct TermCode * termcode; | 421 const struct TermCode * termcode; |
422 unsigned int len; | 422 unsigned int len; |
423 | 423 |
424 TRACE(("enter get_termmodes")); | 424 TRACE(("enter get_termmodes")) |
425 | 425 |
426 /* Term modes */ | 426 /* Term modes */ |
427 /* We'll ignore errors and continue if we can't set modes. | 427 /* We'll ignore errors and continue if we can't set modes. |
428 * We're ignoring baud rates since they seem evil */ | 428 * We're ignoring baud rates since they seem evil */ |
429 if (tcgetattr(chansess->master, &termio) == -1) { | 429 if (tcgetattr(chansess->master, &termio) == -1) { |
436 if (len != ses.payload->len - ses.payload->pos) { | 436 if (len != ses.payload->len - ses.payload->pos) { |
437 dropbear_exit("bad term mode string"); | 437 dropbear_exit("bad term mode string"); |
438 } | 438 } |
439 | 439 |
440 if (len == 0) { | 440 if (len == 0) { |
441 TRACE(("leave get_termmodes: empty terminal modes string")); | 441 TRACE(("leave get_termmodes: empty terminal modes string")) |
442 } | 442 } |
443 | 443 |
444 while (((opcode = buf_getbyte(ses.payload)) != 0x00) && opcode <= 159) { | 444 while (((opcode = buf_getbyte(ses.payload)) != 0x00) && opcode <= 159) { |
445 | 445 |
446 /* must be before checking type, so that value is consumed even if | 446 /* must be before checking type, so that value is consumed even if |
498 } | 498 } |
499 } | 499 } |
500 if (tcsetattr(chansess->master, TCSANOW, &termio) < 0) { | 500 if (tcsetattr(chansess->master, TCSANOW, &termio) < 0) { |
501 dropbear_log(LOG_INFO, "error setting terminal attributes"); | 501 dropbear_log(LOG_INFO, "error setting terminal attributes"); |
502 } | 502 } |
503 TRACE(("leave get_termmodes")); | 503 TRACE(("leave get_termmodes")) |
504 } | 504 } |
505 | 505 |
506 /* Set up a session pty which will be used to execute the shell or program. | 506 /* Set up a session pty which will be used to execute the shell or program. |
507 * The pty is allocated now, and kept for when the shell/program executes. | 507 * The pty is allocated now, and kept for when the shell/program executes. |
508 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ | 508 * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ |
509 static int sessionpty(struct ChanSess * chansess) { | 509 static int sessionpty(struct ChanSess * chansess) { |
510 | 510 |
511 unsigned int termlen; | 511 unsigned int termlen; |
512 unsigned char namebuf[65]; | 512 unsigned char namebuf[65]; |
513 | 513 |
514 TRACE(("enter sessionpty")); | 514 TRACE(("enter sessionpty")) |
515 chansess->term = buf_getstring(ses.payload, &termlen); | 515 chansess->term = buf_getstring(ses.payload, &termlen); |
516 if (termlen > MAX_TERM_LEN) { | 516 if (termlen > MAX_TERM_LEN) { |
517 /* TODO send disconnect ? */ | 517 /* TODO send disconnect ? */ |
518 TRACE(("leave sessionpty: term len too long")); | 518 TRACE(("leave sessionpty: term len too long")) |
519 return DROPBEAR_FAILURE; | 519 return DROPBEAR_FAILURE; |
520 } | 520 } |
521 | 521 |
522 /* allocate the pty */ | 522 /* allocate the pty */ |
523 if (chansess->master != -1) { | 523 if (chansess->master != -1) { |
524 dropbear_exit("multiple pty requests"); | 524 dropbear_exit("multiple pty requests"); |
525 } | 525 } |
526 if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) { | 526 if (pty_allocate(&chansess->master, &chansess->slave, namebuf, 64) == 0) { |
527 TRACE(("leave sessionpty: failed to allocate pty")); | 527 TRACE(("leave sessionpty: failed to allocate pty")) |
528 return DROPBEAR_FAILURE; | 528 return DROPBEAR_FAILURE; |
529 } | 529 } |
530 | 530 |
531 chansess->tty = (char*)m_strdup(namebuf); | 531 chansess->tty = (char*)m_strdup(namebuf); |
532 if (!chansess->tty) { | 532 if (!chansess->tty) { |
539 sessionwinchange(chansess); | 539 sessionwinchange(chansess); |
540 | 540 |
541 /* Read the terminal modes */ | 541 /* Read the terminal modes */ |
542 get_termmodes(chansess); | 542 get_termmodes(chansess); |
543 | 543 |
544 TRACE(("leave sessionpty")); | 544 TRACE(("leave sessionpty")) |
545 return DROPBEAR_SUCCESS; | 545 return DROPBEAR_SUCCESS; |
546 } | 546 } |
547 | 547 |
548 /* Handle a command request from the client. This is used for both shell | 548 /* Handle a command request from the client. This is used for both shell |
549 * and command-execution requests, and passes the command to | 549 * and command-execution requests, and passes the command to |
553 int iscmd, int issubsys) { | 553 int iscmd, int issubsys) { |
554 | 554 |
555 unsigned int cmdlen; | 555 unsigned int cmdlen; |
556 int ret; | 556 int ret; |
557 | 557 |
558 TRACE(("enter sessioncommand")); | 558 TRACE(("enter sessioncommand")) |
559 | 559 |
560 if (chansess->cmd != NULL) { | 560 if (chansess->cmd != NULL) { |
561 /* Note that only one command can _succeed_. The client might try | 561 /* Note that only one command can _succeed_. The client might try |
562 * one command (which fails), then try another. Ie fallback | 562 * one command (which fails), then try another. Ie fallback |
563 * from sftp to scp */ | 563 * from sftp to scp */ |
610 int outfds[2]; | 610 int outfds[2]; |
611 int errfds[2]; | 611 int errfds[2]; |
612 pid_t pid; | 612 pid_t pid; |
613 unsigned int i; | 613 unsigned int i; |
614 | 614 |
615 TRACE(("enter noptycommand")); | 615 TRACE(("enter noptycommand")) |
616 | 616 |
617 /* redirect stdin/stdout/stderr */ | 617 /* redirect stdin/stdout/stderr */ |
618 if (pipe(infds) != 0) | 618 if (pipe(infds) != 0) |
619 return DROPBEAR_FAILURE; | 619 return DROPBEAR_FAILURE; |
620 if (pipe(outfds) != 0) | 620 if (pipe(outfds) != 0) |
633 #define FDIN 0 | 633 #define FDIN 0 |
634 #define FDOUT 1 | 634 #define FDOUT 1 |
635 if ((dup2(infds[FDIN], STDIN_FILENO) < 0) || | 635 if ((dup2(infds[FDIN], STDIN_FILENO) < 0) || |
636 (dup2(outfds[FDOUT], STDOUT_FILENO) < 0) || | 636 (dup2(outfds[FDOUT], STDOUT_FILENO) < 0) || |
637 (dup2(errfds[FDOUT], STDERR_FILENO) < 0)) { | 637 (dup2(errfds[FDOUT], STDERR_FILENO) < 0)) { |
638 TRACE(("leave noptycommand: error redirecting FDs")); | 638 TRACE(("leave noptycommand: error redirecting FDs")) |
639 return DROPBEAR_FAILURE; | 639 return DROPBEAR_FAILURE; |
640 } | 640 } |
641 | 641 |
642 close(infds[FDOUT]); | 642 close(infds[FDOUT]); |
643 close(infds[FDIN]); | 643 close(infds[FDIN]); |
649 execchild(chansess); | 649 execchild(chansess); |
650 /* not reached */ | 650 /* not reached */ |
651 | 651 |
652 } else { | 652 } else { |
653 /* parent */ | 653 /* parent */ |
654 TRACE(("continue noptycommand: parent")); | 654 TRACE(("continue noptycommand: parent")) |
655 chansess->pid = pid; | 655 chansess->pid = pid; |
656 | 656 |
657 addchildpid(chansess, pid); | 657 addchildpid(chansess, pid); |
658 | 658 |
659 if (svr_ses.lastexit.exitpid != -1) { | 659 if (svr_ses.lastexit.exitpid != -1) { |
685 | 685 |
686 } | 686 } |
687 #undef FDIN | 687 #undef FDIN |
688 #undef FDOUT | 688 #undef FDOUT |
689 | 689 |
690 TRACE(("leave noptycommand")); | 690 TRACE(("leave noptycommand")) |
691 return DROPBEAR_SUCCESS; | 691 return DROPBEAR_SUCCESS; |
692 } | 692 } |
693 | 693 |
694 /* Execute a command or shell within a pty environment, and set up | 694 /* Execute a command or shell within a pty environment, and set up |
695 * redirection as appropriate. | 695 * redirection as appropriate. |
703 int len; | 703 int len; |
704 struct stat sb; | 704 struct stat sb; |
705 char *hushpath = NULL; | 705 char *hushpath = NULL; |
706 #endif | 706 #endif |
707 | 707 |
708 TRACE(("enter ptycommand")); | 708 TRACE(("enter ptycommand")) |
709 | 709 |
710 /* we need to have a pty allocated */ | 710 /* we need to have a pty allocated */ |
711 if (chansess->master == -1 || chansess->tty == NULL) { | 711 if (chansess->master == -1 || chansess->tty == NULL) { |
712 dropbear_log(LOG_WARNING, "no pty was allocated, couldn't execute"); | 712 dropbear_log(LOG_WARNING, "no pty was allocated, couldn't execute"); |
713 return DROPBEAR_FAILURE; | 713 return DROPBEAR_FAILURE; |
726 pty_make_controlling_tty(&chansess->slave, chansess->tty); | 726 pty_make_controlling_tty(&chansess->slave, chansess->tty); |
727 | 727 |
728 if ((dup2(chansess->slave, STDIN_FILENO) < 0) || | 728 if ((dup2(chansess->slave, STDIN_FILENO) < 0) || |
729 (dup2(chansess->slave, STDERR_FILENO) < 0) || | 729 (dup2(chansess->slave, STDERR_FILENO) < 0) || |
730 (dup2(chansess->slave, STDOUT_FILENO) < 0)) { | 730 (dup2(chansess->slave, STDOUT_FILENO) < 0)) { |
731 TRACE(("leave ptycommand: error redirecting filedesc")); | 731 TRACE(("leave ptycommand: error redirecting filedesc")) |
732 return DROPBEAR_FAILURE; | 732 return DROPBEAR_FAILURE; |
733 } | 733 } |
734 | 734 |
735 close(chansess->slave); | 735 close(chansess->slave); |
736 | 736 |
774 execchild(chansess); | 774 execchild(chansess); |
775 /* not reached */ | 775 /* not reached */ |
776 | 776 |
777 } else { | 777 } else { |
778 /* parent */ | 778 /* parent */ |
779 TRACE(("continue ptycommand: parent")); | 779 TRACE(("continue ptycommand: parent")) |
780 chansess->pid = pid; | 780 chansess->pid = pid; |
781 | 781 |
782 /* add a child pid */ | 782 /* add a child pid */ |
783 addchildpid(chansess, pid); | 783 addchildpid(chansess, pid); |
784 | 784 |
790 | 790 |
791 setnonblocking(chansess->master); | 791 setnonblocking(chansess->master); |
792 | 792 |
793 } | 793 } |
794 | 794 |
795 TRACE(("leave ptycommand")); | 795 TRACE(("leave ptycommand")) |
796 return DROPBEAR_SUCCESS; | 796 return DROPBEAR_SUCCESS; |
797 } | 797 } |
798 | 798 |
799 /* Add the pid of a child to the list for exit-handling */ | 799 /* Add the pid of a child to the list for exit-handling */ |
800 static void addchildpid(struct ChanSess *chansess, pid_t pid) { | 800 static void addchildpid(struct ChanSess *chansess, pid_t pid) { |