summaryrefslogtreecommitdiff
path: root/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'session.c')
-rw-r--r--session.c382
1 files changed, 262 insertions, 120 deletions
diff --git a/session.c b/session.c
index ca04a4532..c8ed25234 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: session.c,v 1.236 2008/05/08 12:02:23 djm Exp $ */ 1/* $OpenBSD: session.c,v 1.237 2008/05/08 12:21:16 djm Exp $ */
2/* 2/*
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved 4 * All rights reserved
@@ -102,9 +102,9 @@ void session_set_fds(Session *, int, int, int);
102void session_pty_cleanup(Session *); 102void session_pty_cleanup(Session *);
103void session_proctitle(Session *); 103void session_proctitle(Session *);
104int session_setup_x11fwd(Session *); 104int session_setup_x11fwd(Session *);
105void do_exec_pty(Session *, const char *); 105int do_exec_pty(Session *, const char *);
106void do_exec_no_pty(Session *, const char *); 106int do_exec_no_pty(Session *, const char *);
107void do_exec(Session *, const char *); 107int do_exec(Session *, const char *);
108void do_login(Session *, const char *); 108void do_login(Session *, const char *);
109#ifdef LOGIN_NEEDS_UTMPX 109#ifdef LOGIN_NEEDS_UTMPX
110static void do_pre_login(Session *s); 110static void do_pre_login(Session *s);
@@ -132,8 +132,9 @@ extern Buffer loginmsg;
132const char *original_command = NULL; 132const char *original_command = NULL;
133 133
134/* data */ 134/* data */
135#define MAX_SESSIONS 20 135static int sessions_first_unused = -1;
136Session sessions[MAX_SESSIONS]; 136static int sessions_nalloc = 0;
137static Session *sessions = NULL;
137 138
138#define SUBSYSTEM_NONE 0 139#define SUBSYSTEM_NONE 0
139#define SUBSYSTEM_EXT 1 140#define SUBSYSTEM_EXT 1
@@ -167,7 +168,7 @@ static int
167auth_input_request_forwarding(struct passwd * pw) 168auth_input_request_forwarding(struct passwd * pw)
168{ 169{
169 Channel *nc; 170 Channel *nc;
170 int sock; 171 int sock = -1;
171 struct sockaddr_un sunaddr; 172 struct sockaddr_un sunaddr;
172 173
173 if (auth_sock_name != NULL) { 174 if (auth_sock_name != NULL) {
@@ -179,43 +180,48 @@ auth_input_request_forwarding(struct passwd * pw)
179 temporarily_use_uid(pw); 180 temporarily_use_uid(pw);
180 181
181 /* Allocate a buffer for the socket name, and format the name. */ 182 /* Allocate a buffer for the socket name, and format the name. */
182 auth_sock_name = xmalloc(MAXPATHLEN); 183 auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
183 auth_sock_dir = xmalloc(MAXPATHLEN);
184 strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN);
185 184
186 /* Create private directory for socket */ 185 /* Create private directory for socket */
187 if (mkdtemp(auth_sock_dir) == NULL) { 186 if (mkdtemp(auth_sock_dir) == NULL) {
188 packet_send_debug("Agent forwarding disabled: " 187 packet_send_debug("Agent forwarding disabled: "
189 "mkdtemp() failed: %.100s", strerror(errno)); 188 "mkdtemp() failed: %.100s", strerror(errno));
190 restore_uid(); 189 restore_uid();
191 xfree(auth_sock_name);
192 xfree(auth_sock_dir); 190 xfree(auth_sock_dir);
193 auth_sock_name = NULL;
194 auth_sock_dir = NULL; 191 auth_sock_dir = NULL;
195 return 0; 192 goto authsock_err;
196 } 193 }
197 snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", 194
198 auth_sock_dir, (long) getpid()); 195 xasprintf(&auth_sock_name, "%s/agent.%ld",
196 auth_sock_dir, (long) getpid());
199 197
200 /* Create the socket. */ 198 /* Create the socket. */
201 sock = socket(AF_UNIX, SOCK_STREAM, 0); 199 sock = socket(AF_UNIX, SOCK_STREAM, 0);
202 if (sock < 0) 200 if (sock < 0) {
203 packet_disconnect("socket: %.100s", strerror(errno)); 201 error("socket: %.100s", strerror(errno));
202 restore_uid();
203 goto authsock_err;
204 }
204 205
205 /* Bind it to the name. */ 206 /* Bind it to the name. */
206 memset(&sunaddr, 0, sizeof(sunaddr)); 207 memset(&sunaddr, 0, sizeof(sunaddr));
207 sunaddr.sun_family = AF_UNIX; 208 sunaddr.sun_family = AF_UNIX;
208 strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); 209 strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
209 210
210 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) 211 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
211 packet_disconnect("bind: %.100s", strerror(errno)); 212 error("bind: %.100s", strerror(errno));
213 restore_uid();
214 goto authsock_err;
215 }
212 216
213 /* Restore the privileged uid. */ 217 /* Restore the privileged uid. */
214 restore_uid(); 218 restore_uid();
215 219
216 /* Start listening on the socket. */ 220 /* Start listening on the socket. */
217 if (listen(sock, SSH_LISTEN_BACKLOG) < 0) 221 if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
218 packet_disconnect("listen: %.100s", strerror(errno)); 222 error("listen: %.100s", strerror(errno));
223 goto authsock_err;
224 }
219 225
220 /* Allocate a channel for the authentication agent socket. */ 226 /* Allocate a channel for the authentication agent socket. */
221 nc = channel_new("auth socket", 227 nc = channel_new("auth socket",
@@ -224,6 +230,19 @@ auth_input_request_forwarding(struct passwd * pw)
224 0, "auth socket", 1); 230 0, "auth socket", 1);
225 strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); 231 strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
226 return 1; 232 return 1;
233
234 authsock_err:
235 if (auth_sock_name != NULL)
236 xfree(auth_sock_name);
237 if (auth_sock_dir != NULL) {
238 rmdir(auth_sock_dir);
239 xfree(auth_sock_dir);
240 }
241 if (sock != -1)
242 close(sock);
243 auth_sock_name = NULL;
244 auth_sock_dir = NULL;
245 return 0;
227} 246}
228 247
229static void 248static void
@@ -373,10 +392,14 @@ do_authenticated1(Authctxt *authctxt)
373 if (type == SSH_CMSG_EXEC_CMD) { 392 if (type == SSH_CMSG_EXEC_CMD) {
374 command = packet_get_string(&dlen); 393 command = packet_get_string(&dlen);
375 debug("Exec command '%.500s'", command); 394 debug("Exec command '%.500s'", command);
376 do_exec(s, command); 395 if (do_exec(s, command) != 0)
396 packet_disconnect(
397 "command execution failed");
377 xfree(command); 398 xfree(command);
378 } else { 399 } else {
379 do_exec(s, NULL); 400 if (do_exec(s, NULL) != 0)
401 packet_disconnect(
402 "shell execution failed");
380 } 403 }
381 packet_check_eom(); 404 packet_check_eom();
382 session_close(s); 405 session_close(s);
@@ -401,41 +424,84 @@ do_authenticated1(Authctxt *authctxt)
401 } 424 }
402} 425}
403 426
427#define USE_PIPES
404/* 428/*
405 * This is called to fork and execute a command when we have no tty. This 429 * This is called to fork and execute a command when we have no tty. This
406 * will call do_child from the child, and server_loop from the parent after 430 * will call do_child from the child, and server_loop from the parent after
407 * setting up file descriptors and such. 431 * setting up file descriptors and such.
408 */ 432 */
409void 433int
410do_exec_no_pty(Session *s, const char *command) 434do_exec_no_pty(Session *s, const char *command)
411{ 435{
412 pid_t pid; 436 pid_t pid;
413 437
414#ifdef USE_PIPES 438#ifdef USE_PIPES
415 int pin[2], pout[2], perr[2]; 439 int pin[2], pout[2], perr[2];
440
416 /* Allocate pipes for communicating with the program. */ 441 /* Allocate pipes for communicating with the program. */
417 if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0) 442 if (pipe(pin) < 0) {
418 packet_disconnect("Could not create pipes: %.100s", 443 error("%s: pipe in: %.100s", __func__, strerror(errno));
419 strerror(errno)); 444 return -1;
420#else /* USE_PIPES */ 445 }
446 if (pipe(pout) < 0) {
447 error("%s: pipe out: %.100s", __func__, strerror(errno));
448 close(pin[0]);
449 close(pin[1]);
450 return -1;
451 }
452 if (pipe(perr) < 0) {
453 error("%s: pipe err: %.100s", __func__, strerror(errno));
454 close(pin[0]);
455 close(pin[1]);
456 close(pout[0]);
457 close(pout[1]);
458 return -1;
459 }
460#else
421 int inout[2], err[2]; 461 int inout[2], err[2];
462
422 /* Uses socket pairs to communicate with the program. */ 463 /* Uses socket pairs to communicate with the program. */
423 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 || 464 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) {
424 socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) 465 error("%s: socketpair #1: %.100s", __func__, strerror(errno));
425 packet_disconnect("Could not create socket pairs: %.100s", 466 return -1;
426 strerror(errno)); 467 }
427#endif /* USE_PIPES */ 468 if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
469 error("%s: socketpair #2: %.100s", __func__, strerror(errno));
470 close(inout[0]);
471 close(inout[1]);
472 return -1;
473 }
474#endif
475
428 if (s == NULL) 476 if (s == NULL)
429 fatal("do_exec_no_pty: no session"); 477 fatal("do_exec_no_pty: no session");
430 478
431 session_proctitle(s); 479 session_proctitle(s);
432 480
433 /* Fork the child. */ 481 /* Fork the child. */
434 if ((pid = fork()) == 0) { 482 switch ((pid = fork())) {
483 case -1:
484 error("%s: fork: %.100s", __func__, strerror(errno));
485#ifdef USE_PIPES
486 close(pin[0]);
487 close(pin[1]);
488 close(pout[0]);
489 close(pout[1]);
490 close(perr[0]);
491 close(perr[1]);
492#else
493 close(inout[0]);
494 close(inout[1]);
495 close(err[0]);
496 close(err[1]);
497#endif
498 return -1;
499 case 0:
435 is_child = 1; 500 is_child = 1;
436 501
437 /* Child. Reinitialize the log since the pid has changed. */ 502 /* Child. Reinitialize the log since the pid has changed. */
438 log_init(__progname, options.log_level, options.log_facility, log_stderr); 503 log_init(__progname, options.log_level,
504 options.log_facility, log_stderr);
439 505
440 /* 506 /*
441 * Create a new session and process group since the 4.4BSD 507 * Create a new session and process group since the 4.4BSD
@@ -465,7 +531,7 @@ do_exec_no_pty(Session *s, const char *command)
465 if (dup2(perr[1], 2) < 0) 531 if (dup2(perr[1], 2) < 0)
466 perror("dup2 stderr"); 532 perror("dup2 stderr");
467 close(perr[1]); 533 close(perr[1]);
468#else /* USE_PIPES */ 534#else
469 /* 535 /*
470 * Redirect stdin, stdout, and stderr. Stdin and stdout will 536 * Redirect stdin, stdout, and stderr. Stdin and stdout will
471 * use the same socket, as some programs (particularly rdist) 537 * use the same socket, as some programs (particularly rdist)
@@ -475,11 +541,14 @@ do_exec_no_pty(Session *s, const char *command)
475 close(err[1]); 541 close(err[1]);
476 if (dup2(inout[0], 0) < 0) /* stdin */ 542 if (dup2(inout[0], 0) < 0) /* stdin */
477 perror("dup2 stdin"); 543 perror("dup2 stdin");
478 if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */ 544 if (dup2(inout[0], 1) < 0) /* stdout (same as stdin) */
479 perror("dup2 stdout"); 545 perror("dup2 stdout");
546 close(inout[0]);
480 if (dup2(err[0], 2) < 0) /* stderr */ 547 if (dup2(err[0], 2) < 0) /* stderr */
481 perror("dup2 stderr"); 548 perror("dup2 stderr");
482#endif /* USE_PIPES */ 549 close(err[0]);
550#endif
551
483 552
484#ifdef _UNICOS 553#ifdef _UNICOS
485 cray_init_job(s->pw); /* set up cray jid and tmpdir */ 554 cray_init_job(s->pw); /* set up cray jid and tmpdir */
@@ -488,7 +557,10 @@ do_exec_no_pty(Session *s, const char *command)
488 /* Do processing for the child (exec command etc). */ 557 /* Do processing for the child (exec command etc). */
489 do_child(s, command); 558 do_child(s, command);
490 /* NOTREACHED */ 559 /* NOTREACHED */
560 default:
561 break;
491 } 562 }
563
492#ifdef _UNICOS 564#ifdef _UNICOS
493 signal(WJSIGNAL, cray_job_termination_handler); 565 signal(WJSIGNAL, cray_job_termination_handler);
494#endif /* _UNICOS */ 566#endif /* _UNICOS */
@@ -496,11 +568,18 @@ do_exec_no_pty(Session *s, const char *command)
496 if (is_winnt) 568 if (is_winnt)
497 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 569 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
498#endif 570#endif
499 if (pid < 0) 571
500 packet_disconnect("fork failed: %.100s", strerror(errno));
501 s->pid = pid; 572 s->pid = pid;
502 /* Set interactive/non-interactive mode. */ 573 /* Set interactive/non-interactive mode. */
503 packet_set_interactive(s->display != NULL); 574 packet_set_interactive(s->display != NULL);
575
576 /*
577 * Clear loginmsg, since it's the child's responsibility to display
578 * it to the user, otherwise multiple sessions may accumulate
579 * multiple copies of the login messages.
580 */
581 buffer_clear(&loginmsg);
582
504#ifdef USE_PIPES 583#ifdef USE_PIPES
505 /* We are the parent. Close the child sides of the pipes. */ 584 /* We are the parent. Close the child sides of the pipes. */
506 close(pin[0]); 585 close(pin[0]);
@@ -518,29 +597,26 @@ do_exec_no_pty(Session *s, const char *command)
518 server_loop(pid, pin[1], pout[0], perr[0]); 597 server_loop(pid, pin[1], pout[0], perr[0]);
519 /* server_loop has closed pin[1], pout[0], and perr[0]. */ 598 /* server_loop has closed pin[1], pout[0], and perr[0]. */
520 } 599 }
521#else /* USE_PIPES */ 600#else
522 /* We are the parent. Close the child sides of the socket pairs. */ 601 /* We are the parent. Close the child sides of the socket pairs. */
523 close(inout[0]); 602 close(inout[0]);
524 close(err[0]); 603 close(err[0]);
525 604
526 /* 605 /*
527 * Clear loginmsg, since it's the child's responsibility to display
528 * it to the user, otherwise multiple sessions may accumulate
529 * multiple copies of the login messages.
530 */
531 buffer_clear(&loginmsg);
532
533 /*
534 * Enter the interactive session. Note: server_loop must be able to 606 * Enter the interactive session. Note: server_loop must be able to
535 * handle the case that fdin and fdout are the same. 607 * handle the case that fdin and fdout are the same.
536 */ 608 */
537 if (compat20) { 609 if (compat20) {
538 session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]); 610 session_set_fds(s, inout[1], inout[1],
611 s->is_subsystem ? -1 : err[1]);
612 if (s->is_subsystem)
613 close(err[1]);
539 } else { 614 } else {
540 server_loop(pid, inout[1], inout[1], err[1]); 615 server_loop(pid, inout[1], inout[1], err[1]);
541 /* server_loop has closed inout[1] and err[1]. */ 616 /* server_loop has closed inout[1] and err[1]. */
542 } 617 }
543#endif /* USE_PIPES */ 618#endif
619 return 0;
544} 620}
545 621
546/* 622/*
@@ -549,7 +625,7 @@ do_exec_no_pty(Session *s, const char *command)
549 * setting up file descriptors, controlling tty, updating wtmp, utmp, 625 * setting up file descriptors, controlling tty, updating wtmp, utmp,
550 * lastlog, and other such operations. 626 * lastlog, and other such operations.
551 */ 627 */
552void 628int
553do_exec_pty(Session *s, const char *command) 629do_exec_pty(Session *s, const char *command)
554{ 630{
555 int fdout, ptyfd, ttyfd, ptymaster; 631 int fdout, ptyfd, ttyfd, ptymaster;
@@ -560,12 +636,46 @@ do_exec_pty(Session *s, const char *command)
560 ptyfd = s->ptyfd; 636 ptyfd = s->ptyfd;
561 ttyfd = s->ttyfd; 637 ttyfd = s->ttyfd;
562 638
639 /*
640 * Create another descriptor of the pty master side for use as the
641 * standard input. We could use the original descriptor, but this
642 * simplifies code in server_loop. The descriptor is bidirectional.
643 * Do this before forking (and cleanup in the child) so as to
644 * detect and gracefully fail out-of-fd conditions.
645 */
646 if ((fdout = dup(ptyfd)) < 0) {
647 error("%s: dup #1: %s", __func__, strerror(errno));
648 close(ttyfd);
649 close(ptyfd);
650 return -1;
651 }
652 /* we keep a reference to the pty master */
653 if ((ptymaster = dup(ptyfd)) < 0) {
654 error("%s: dup #2: %s", __func__, strerror(errno));
655 close(ttyfd);
656 close(ptyfd);
657 close(fdout);
658 return -1;
659 }
660
563 /* Fork the child. */ 661 /* Fork the child. */
564 if ((pid = fork()) == 0) { 662 switch ((pid = fork())) {
663 case -1:
664 error("%s: fork: %.100s", __func__, strerror(errno));
665 close(fdout);
666 close(ptymaster);
667 close(ttyfd);
668 close(ptyfd);
669 return -1;
670 case 0:
565 is_child = 1; 671 is_child = 1;
566 672
673 close(fdout);
674 close(ptymaster);
675
567 /* Child. Reinitialize the log because the pid has changed. */ 676 /* Child. Reinitialize the log because the pid has changed. */
568 log_init(__progname, options.log_level, options.log_facility, log_stderr); 677 log_init(__progname, options.log_level,
678 options.log_facility, log_stderr);
569 /* Close the master side of the pseudo tty. */ 679 /* Close the master side of the pseudo tty. */
570 close(ptyfd); 680 close(ptyfd);
571 681
@@ -596,11 +706,16 @@ do_exec_pty(Session *s, const char *command)
596 do_pre_login(s); 706 do_pre_login(s);
597# endif 707# endif
598#endif 708#endif
599 709 /*
600 /* Do common processing for the child, such as execing the command. */ 710 * Do common processing for the child, such as execing
601 do_child(s, command); 711 * the command.
602 /* NOTREACHED */ 712 */
713 do_child(s, command);
714 /* NOTREACHED */
715 default:
716 break;
603 } 717 }
718
604#ifdef _UNICOS 719#ifdef _UNICOS
605 signal(WJSIGNAL, cray_job_termination_handler); 720 signal(WJSIGNAL, cray_job_termination_handler);
606#endif /* _UNICOS */ 721#endif /* _UNICOS */
@@ -608,29 +723,14 @@ do_exec_pty(Session *s, const char *command)
608 if (is_winnt) 723 if (is_winnt)
609 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 724 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
610#endif 725#endif
611 if (pid < 0) 726
612 packet_disconnect("fork failed: %.100s", strerror(errno));
613 s->pid = pid; 727 s->pid = pid;
614 728
615 /* Parent. Close the slave side of the pseudo tty. */ 729 /* Parent. Close the slave side of the pseudo tty. */
616 close(ttyfd); 730 close(ttyfd);
617 731
618 /*
619 * Create another descriptor of the pty master side for use as the
620 * standard input. We could use the original descriptor, but this
621 * simplifies code in server_loop. The descriptor is bidirectional.
622 */
623 fdout = dup(ptyfd);
624 if (fdout < 0)
625 packet_disconnect("dup #1 failed: %.100s", strerror(errno));
626
627 /* we keep a reference to the pty master */
628 ptymaster = dup(ptyfd);
629 if (ptymaster < 0)
630 packet_disconnect("dup #2 failed: %.100s", strerror(errno));
631 s->ptymaster = ptymaster;
632
633 /* Enter interactive session. */ 732 /* Enter interactive session. */
733 s->ptymaster = ptymaster;
634 packet_set_interactive(1); 734 packet_set_interactive(1);
635 if (compat20) { 735 if (compat20) {
636 session_set_fds(s, ptyfd, fdout, -1); 736 session_set_fds(s, ptyfd, fdout, -1);
@@ -638,6 +738,7 @@ do_exec_pty(Session *s, const char *command)
638 server_loop(pid, ptyfd, fdout, -1); 738 server_loop(pid, ptyfd, fdout, -1);
639 /* server_loop _has_ closed ptyfd and fdout. */ 739 /* server_loop _has_ closed ptyfd and fdout. */
640 } 740 }
741 return 0;
641} 742}
642 743
643#ifdef LOGIN_NEEDS_UTMPX 744#ifdef LOGIN_NEEDS_UTMPX
@@ -672,9 +773,11 @@ do_pre_login(Session *s)
672 * This is called to fork and execute a command. If another command is 773 * This is called to fork and execute a command. If another command is
673 * to be forced, execute that instead. 774 * to be forced, execute that instead.
674 */ 775 */
675void 776int
676do_exec(Session *s, const char *command) 777do_exec(Session *s, const char *command)
677{ 778{
779 int ret;
780
678 if (options.adm_forced_command) { 781 if (options.adm_forced_command) {
679 original_command = command; 782 original_command = command;
680 command = options.adm_forced_command; 783 command = options.adm_forced_command;
@@ -705,9 +808,9 @@ do_exec(Session *s, const char *command)
705 } 808 }
706#endif 809#endif
707 if (s->ttyfd != -1) 810 if (s->ttyfd != -1)
708 do_exec_pty(s, command); 811 ret = do_exec_pty(s, command);
709 else 812 else
710 do_exec_no_pty(s, command); 813 ret = do_exec_no_pty(s, command);
711 814
712 original_command = NULL; 815 original_command = NULL;
713 816
@@ -717,6 +820,8 @@ do_exec(Session *s, const char *command)
717 * multiple copies of the login messages. 820 * multiple copies of the login messages.
718 */ 821 */
719 buffer_clear(&loginmsg); 822 buffer_clear(&loginmsg);
823
824 return ret;
720} 825}
721 826
722/* administrative, login(1)-like work */ 827/* administrative, login(1)-like work */
@@ -1740,43 +1845,79 @@ do_child(Session *s, const char *command)
1740 exit(1); 1845 exit(1);
1741} 1846}
1742 1847
1848void
1849session_unused(int id)
1850{
1851 debug3("%s: session id %d unused", __func__, id);
1852 if (id >= options.max_sessions ||
1853 id >= sessions_nalloc) {
1854 fatal("%s: insane session id %d (max %d nalloc %d)",
1855 __func__, id, options.max_sessions, sessions_nalloc);
1856 }
1857 bzero(&sessions[id], sizeof(*sessions));
1858 sessions[id].self = id;
1859 sessions[id].used = 0;
1860 sessions[id].chanid = -1;
1861 sessions[id].ptyfd = -1;
1862 sessions[id].ttyfd = -1;
1863 sessions[id].ptymaster = -1;
1864 sessions[id].x11_chanids = NULL;
1865 sessions[id].next_unused = sessions_first_unused;
1866 sessions_first_unused = id;
1867}
1868
1743Session * 1869Session *
1744session_new(void) 1870session_new(void)
1745{ 1871{
1746 int i; 1872 Session *s, *tmp;
1747 static int did_init = 0; 1873
1748 if (!did_init) { 1874 if (sessions_first_unused == -1) {
1749 debug("session_new: init"); 1875 if (sessions_nalloc >= options.max_sessions)
1750 for (i = 0; i < MAX_SESSIONS; i++) { 1876 return NULL;
1751 sessions[i].used = 0; 1877 debug2("%s: allocate (allocated %d max %d)",
1878 __func__, sessions_nalloc, options.max_sessions);
1879 tmp = xrealloc(sessions, sessions_nalloc + 1,
1880 sizeof(*sessions));
1881 if (tmp == NULL) {
1882 error("%s: cannot allocate %d sessions",
1883 __func__, sessions_nalloc + 1);
1884 return NULL;
1752 } 1885 }
1753 did_init = 1; 1886 sessions = tmp;
1887 session_unused(sessions_nalloc++);
1754 } 1888 }
1755 for (i = 0; i < MAX_SESSIONS; i++) { 1889
1756 Session *s = &sessions[i]; 1890 if (sessions_first_unused >= sessions_nalloc ||
1757 if (! s->used) { 1891 sessions_first_unused < 0) {
1758 memset(s, 0, sizeof(*s)); 1892 fatal("%s: insane first_unused %d max %d nalloc %d",
1759 s->chanid = -1; 1893 __func__, sessions_first_unused, options.max_sessions,
1760 s->ptyfd = -1; 1894 sessions_nalloc);
1761 s->ttyfd = -1;
1762 s->used = 1;
1763 s->self = i;
1764 s->x11_chanids = NULL;
1765 debug("session_new: session %d", i);
1766 return s;
1767 }
1768 } 1895 }
1769 return NULL; 1896
1897 s = &sessions[sessions_first_unused];
1898 if (s->used) {
1899 fatal("%s: session %d already used",
1900 __func__, sessions_first_unused);
1901 }
1902 sessions_first_unused = s->next_unused;
1903 s->used = 1;
1904 s->next_unused = -1;
1905 debug("session_new: session %d", s->self);
1906
1907 return s;
1770} 1908}
1771 1909
1772static void 1910static void
1773session_dump(void) 1911session_dump(void)
1774{ 1912{
1775 int i; 1913 int i;
1776 for (i = 0; i < MAX_SESSIONS; i++) { 1914 for (i = 0; i < sessions_nalloc; i++) {
1777 Session *s = &sessions[i]; 1915 Session *s = &sessions[i];
1778 debug("dump: used %d session %d %p channel %d pid %ld", 1916
1917 debug("dump: used %d next_unused %d session %d %p "
1918 "channel %d pid %ld",
1779 s->used, 1919 s->used,
1920 s->next_unused,
1780 s->self, 1921 s->self,
1781 s, 1922 s,
1782 s->chanid, 1923 s->chanid,
@@ -1806,7 +1947,7 @@ Session *
1806session_by_tty(char *tty) 1947session_by_tty(char *tty)
1807{ 1948{
1808 int i; 1949 int i;
1809 for (i = 0; i < MAX_SESSIONS; i++) { 1950 for (i = 0; i < sessions_nalloc; i++) {
1810 Session *s = &sessions[i]; 1951 Session *s = &sessions[i];
1811 if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { 1952 if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
1812 debug("session_by_tty: session %d tty %s", i, tty); 1953 debug("session_by_tty: session %d tty %s", i, tty);
@@ -1822,10 +1963,11 @@ static Session *
1822session_by_channel(int id) 1963session_by_channel(int id)
1823{ 1964{
1824 int i; 1965 int i;
1825 for (i = 0; i < MAX_SESSIONS; i++) { 1966 for (i = 0; i < sessions_nalloc; i++) {
1826 Session *s = &sessions[i]; 1967 Session *s = &sessions[i];
1827 if (s->used && s->chanid == id) { 1968 if (s->used && s->chanid == id) {
1828 debug("session_by_channel: session %d channel %d", i, id); 1969 debug("session_by_channel: session %d channel %d",
1970 i, id);
1829 return s; 1971 return s;
1830 } 1972 }
1831 } 1973 }
@@ -1839,7 +1981,7 @@ session_by_x11_channel(int id)
1839{ 1981{
1840 int i, j; 1982 int i, j;
1841 1983
1842 for (i = 0; i < MAX_SESSIONS; i++) { 1984 for (i = 0; i < sessions_nalloc; i++) {
1843 Session *s = &sessions[i]; 1985 Session *s = &sessions[i];
1844 1986
1845 if (s->x11_chanids == NULL || !s->used) 1987 if (s->x11_chanids == NULL || !s->used)
@@ -1862,7 +2004,7 @@ session_by_pid(pid_t pid)
1862{ 2004{
1863 int i; 2005 int i;
1864 debug("session_by_pid: pid %ld", (long)pid); 2006 debug("session_by_pid: pid %ld", (long)pid);
1865 for (i = 0; i < MAX_SESSIONS; i++) { 2007 for (i = 0; i < sessions_nalloc; i++) {
1866 Session *s = &sessions[i]; 2008 Session *s = &sessions[i];
1867 if (s->used && s->pid == pid) 2009 if (s->used && s->pid == pid)
1868 return s; 2010 return s;
@@ -1918,7 +2060,8 @@ session_pty_req(Session *s)
1918 2060
1919 /* Allocate a pty and open it. */ 2061 /* Allocate a pty and open it. */
1920 debug("Allocating pty."); 2062 debug("Allocating pty.");
1921 if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { 2063 if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
2064 sizeof(s->tty)))) {
1922 if (s->term) 2065 if (s->term)
1923 xfree(s->term); 2066 xfree(s->term);
1924 s->term = NULL; 2067 s->term = NULL;
@@ -1971,8 +2114,7 @@ session_subsystem_req(Session *s)
1971 s->is_subsystem = SUBSYSTEM_EXT; 2114 s->is_subsystem = SUBSYSTEM_EXT;
1972 } 2115 }
1973 debug("subsystem: exec() %s", cmd); 2116 debug("subsystem: exec() %s", cmd);
1974 do_exec(s, cmd); 2117 success = do_exec(s, cmd) == 0;
1975 success = 1;
1976 break; 2118 break;
1977 } 2119 }
1978 } 2120 }
@@ -2015,19 +2157,19 @@ static int
2015session_shell_req(Session *s) 2157session_shell_req(Session *s)
2016{ 2158{
2017 packet_check_eom(); 2159 packet_check_eom();
2018 do_exec(s, NULL); 2160 return do_exec(s, NULL) == 0;
2019 return 1;
2020} 2161}
2021 2162
2022static int 2163static int
2023session_exec_req(Session *s) 2164session_exec_req(Session *s)
2024{ 2165{
2025 u_int len; 2166 u_int len, success;
2167
2026 char *command = packet_get_string(&len); 2168 char *command = packet_get_string(&len);
2027 packet_check_eom(); 2169 packet_check_eom();
2028 do_exec(s, command); 2170 success = do_exec(s, command) == 0;
2029 xfree(command); 2171 xfree(command);
2030 return 1; 2172 return success;
2031} 2173}
2032 2174
2033static int 2175static int
@@ -2037,8 +2179,7 @@ session_break_req(Session *s)
2037 packet_get_int(); /* ignored */ 2179 packet_get_int(); /* ignored */
2038 packet_check_eom(); 2180 packet_check_eom();
2039 2181
2040 if (s->ttyfd == -1 || 2182 if (s->ttyfd == -1 || tcsendbreak(s->ttyfd, 0) < 0)
2041 tcsendbreak(s->ttyfd, 0) < 0)
2042 return 0; 2183 return 0;
2043 return 1; 2184 return 1;
2044} 2185}
@@ -2185,8 +2326,9 @@ session_pty_cleanup2(Session *s)
2185 * the pty cleanup, so that another process doesn't get this pty 2326 * the pty cleanup, so that another process doesn't get this pty
2186 * while we're still cleaning up. 2327 * while we're still cleaning up.
2187 */ 2328 */
2188 if (close(s->ptymaster) < 0) 2329 if (s->ptymaster != -1 && close(s->ptymaster) < 0)
2189 error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno)); 2330 error("close(s->ptymaster/%d): %s",
2331 s->ptymaster, strerror(errno));
2190 2332
2191 /* unlink pty from session */ 2333 /* unlink pty from session */
2192 s->ttyfd = -1; 2334 s->ttyfd = -1;
@@ -2346,7 +2488,6 @@ session_close(Session *s)
2346 xfree(s->auth_data); 2488 xfree(s->auth_data);
2347 if (s->auth_proto) 2489 if (s->auth_proto)
2348 xfree(s->auth_proto); 2490 xfree(s->auth_proto);
2349 s->used = 0;
2350 if (s->env != NULL) { 2491 if (s->env != NULL) {
2351 for (i = 0; i < s->num_env; i++) { 2492 for (i = 0; i < s->num_env; i++) {
2352 xfree(s->env[i].name); 2493 xfree(s->env[i].name);
@@ -2355,6 +2496,7 @@ session_close(Session *s)
2355 xfree(s->env); 2496 xfree(s->env);
2356 } 2497 }
2357 session_proctitle(s); 2498 session_proctitle(s);
2499 session_unused(s->self);
2358} 2500}
2359 2501
2360void 2502void
@@ -2418,7 +2560,7 @@ void
2418session_destroy_all(void (*closefunc)(Session *)) 2560session_destroy_all(void (*closefunc)(Session *))
2419{ 2561{
2420 int i; 2562 int i;
2421 for (i = 0; i < MAX_SESSIONS; i++) { 2563 for (i = 0; i < sessions_nalloc; i++) {
2422 Session *s = &sessions[i]; 2564 Session *s = &sessions[i];
2423 if (s->used) { 2565 if (s->used) {
2424 if (closefunc != NULL) 2566 if (closefunc != NULL)
@@ -2437,7 +2579,7 @@ session_tty_list(void)
2437 char *cp; 2579 char *cp;
2438 2580
2439 buf[0] = '\0'; 2581 buf[0] = '\0';
2440 for (i = 0; i < MAX_SESSIONS; i++) { 2582 for (i = 0; i < sessions_nalloc; i++) {
2441 Session *s = &sessions[i]; 2583 Session *s = &sessions[i];
2442 if (s->used && s->ttyfd != -1) { 2584 if (s->used && s->ttyfd != -1) {
2443 2585