]> andersk Git - openssh.git/blame - session.c
- Remove references to SSLeay.
[openssh.git] / session.c
CommitLineData
7368a6c8 1/*
2 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
3 * All rights reserved
4 */
e78a59f5 5/*
6 * SSH2 support by Markus Friedl.
7 * Copyright (c) 2000 Markus Friedl. All rights reserved.
8 */
7368a6c8 9
10#include "includes.h"
1d1ffb87 11RCSID("$OpenBSD: session.c,v 1.12 2000/05/03 18:03:07 markus Exp $");
7368a6c8 12
13#include "xmalloc.h"
14#include "ssh.h"
15#include "pty.h"
16#include "packet.h"
17#include "buffer.h"
18#include "cipher.h"
19#include "mpaux.h"
20#include "servconf.h"
21#include "uidswap.h"
22#include "compat.h"
23#include "channels.h"
24#include "nchan.h"
25
e78a59f5 26#include "bufaux.h"
27#include "ssh2.h"
28#include "auth.h"
29
7368a6c8 30/* types */
31
32#define TTYSZ 64
33typedef struct Session Session;
34struct Session {
35 int used;
36 int self;
0b242b12 37 int extended;
7368a6c8 38 struct passwd *pw;
39 pid_t pid;
40 /* tty */
41 char *term;
42 int ptyfd, ttyfd, ptymaster;
43 int row, col, xpixel, ypixel;
44 char tty[TTYSZ];
45 /* X11 */
46 char *display;
47 int screen;
48 char *auth_proto;
49 char *auth_data;
0b242b12 50 int single_connection;
7368a6c8 51 /* proto 2 */
52 int chanid;
53};
54
55/* func */
56
57Session *session_new(void);
58void session_set_fds(Session *s, int fdin, int fdout, int fderr);
59void session_pty_cleanup(Session *s);
1d1ffb87 60void session_proctitle(Session *s);
7368a6c8 61void do_exec_pty(Session *s, const char *command, struct passwd * pw);
62void do_exec_no_pty(Session *s, const char *command, struct passwd * pw);
63
64void
65do_child(const char *command, struct passwd * pw, const char *term,
66 const char *display, const char *auth_proto,
67 const char *auth_data, const char *ttyname);
68
69/* import */
70extern ServerOptions options;
3a6cb538 71#ifdef HAVE___PROGNAME
7368a6c8 72extern char *__progname;
3a6cb538 73#else /* HAVE___PROGNAME */
3fd95d9a 74static const char *__progname = "sshd";
3a6cb538 75#endif /* HAVE___PROGNAME */
76
7368a6c8 77extern int log_stderr;
78extern int debug_flag;
79
80/* Local Xauthority file. */
81static char *xauthfile;
82
83/* data */
84#define MAX_SESSIONS 10
85Session sessions[MAX_SESSIONS];
86
87/* Flags set in auth-rsa from authorized_keys flags. These are set in auth-rsa.c. */
88int no_port_forwarding_flag = 0;
89int no_agent_forwarding_flag = 0;
90int no_x11_forwarding_flag = 0;
91int no_pty_flag = 0;
92
93/* RSA authentication "command=" option. */
94char *forced_command = NULL;
95
96/* RSA authentication "environment=" options. */
97struct envstring *custom_environment = NULL;
98
99/*
100 * Remove local Xauthority file.
101 */
102void
103xauthfile_cleanup_proc(void *ignore)
104{
105 debug("xauthfile_cleanup_proc called");
106
107 if (xauthfile != NULL) {
108 char *p;
109 unlink(xauthfile);
110 p = strrchr(xauthfile, '/');
111 if (p != NULL) {
112 *p = '\0';
113 rmdir(xauthfile);
114 }
115 xfree(xauthfile);
116 xauthfile = NULL;
117 }
118}
119
120/*
121 * Function to perform cleanup if we get aborted abnormally (e.g., due to a
122 * dropped connection).
123 */
6ae2364d 124void
7368a6c8 125pty_cleanup_proc(void *session)
126{
127 Session *s=session;
128 if (s == NULL)
129 fatal("pty_cleanup_proc: no session");
130 debug("pty_cleanup_proc: %s", s->tty);
131
132 if (s->pid != 0) {
133 /* Record that the user has logged out. */
134 record_logout(s->pid, s->tty);
135 }
136
137 /* Release the pseudo-tty. */
138 pty_release(s->tty);
139}
140
141/*
142 * Prepares for an interactive session. This is called after the user has
143 * been successfully authenticated. During this message exchange, pseudo
144 * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
145 * are requested, etc.
146 */
6ae2364d 147void
7368a6c8 148do_authenticated(struct passwd * pw)
149{
150 Session *s;
151 int type;
152 int compression_level = 0, enable_compression_after_reply = 0;
153 int have_pty = 0;
154 char *command;
155 int n_bytes;
156 int plen;
157 unsigned int proto_len, data_len, dlen;
158
159 /*
160 * Cancel the alarm we set to limit the time taken for
161 * authentication.
162 */
163 alarm(0);
164
165 /*
166 * Inform the channel mechanism that we are the server side and that
167 * the client may request to connect to any port at all. (The user
168 * could do it anyway, and we wouldn\'t know what is permitted except
169 * by the client telling us, so we can equally well trust the client
170 * not to request anything bogus.)
171 */
172 if (!no_port_forwarding_flag)
173 channel_permit_all_opens();
174
175 s = session_new();
0b242b12 176 s->pw = pw;
7368a6c8 177
178 /*
179 * We stay in this loop until the client requests to execute a shell
180 * or a command.
181 */
182 for (;;) {
183 int success = 0;
184
185 /* Get a packet from the client. */
186 type = packet_read(&plen);
187
188 /* Process the packet. */
189 switch (type) {
190 case SSH_CMSG_REQUEST_COMPRESSION:
191 packet_integrity_check(plen, 4, type);
192 compression_level = packet_get_int();
193 if (compression_level < 1 || compression_level > 9) {
194 packet_send_debug("Received illegal compression level %d.",
195 compression_level);
196 break;
197 }
198 /* Enable compression after we have responded with SUCCESS. */
199 enable_compression_after_reply = 1;
200 success = 1;
201 break;
202
203 case SSH_CMSG_REQUEST_PTY:
204 if (no_pty_flag) {
205 debug("Allocating a pty not permitted for this authentication.");
206 break;
207 }
208 if (have_pty)
209 packet_disconnect("Protocol error: you already have a pty.");
210
211 debug("Allocating pty.");
212
213 /* Allocate a pty and open it. */
214 if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
215 sizeof(s->tty))) {
216 error("Failed to allocate pty.");
217 break;
218 }
219 fatal_add_cleanup(pty_cleanup_proc, (void *)s);
220 pty_setowner(pw, s->tty);
221
222 /* Get TERM from the packet. Note that the value may be of arbitrary length. */
223 s->term = packet_get_string(&dlen);
224 packet_integrity_check(dlen, strlen(s->term), type);
225 /* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */
226 /* Remaining bytes */
227 n_bytes = plen - (4 + dlen + 4 * 4);
228
229 if (strcmp(s->term, "") == 0) {
230 xfree(s->term);
231 s->term = NULL;
232 }
233 /* Get window size from the packet. */
234 s->row = packet_get_int();
235 s->col = packet_get_int();
236 s->xpixel = packet_get_int();
237 s->ypixel = packet_get_int();
238 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
239
240 /* Get tty modes from the packet. */
241 tty_parse_modes(s->ttyfd, &n_bytes);
242 packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type);
243
1d1ffb87 244 session_proctitle(s);
245
7368a6c8 246 /* Indicate that we now have a pty. */
247 success = 1;
248 have_pty = 1;
249 break;
250
251 case SSH_CMSG_X11_REQUEST_FORWARDING:
252 if (!options.x11_forwarding) {
253 packet_send_debug("X11 forwarding disabled in server configuration file.");
254 break;
255 }
256#ifdef XAUTH_PATH
257 if (no_x11_forwarding_flag) {
258 packet_send_debug("X11 forwarding not permitted for this authentication.");
259 break;
260 }
261 debug("Received request for X11 forwarding with auth spoofing.");
262 if (s->display != NULL)
263 packet_disconnect("Protocol error: X11 display already set.");
264
265 s->auth_proto = packet_get_string(&proto_len);
266 s->auth_data = packet_get_string(&data_len);
267 packet_integrity_check(plen, 4 + proto_len + 4 + data_len + 4, type);
268
269 if (packet_get_protocol_flags() & SSH_PROTOFLAG_SCREEN_NUMBER)
270 s->screen = packet_get_int();
271 else
272 s->screen = 0;
273 s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
274
275 if (s->display == NULL)
276 break;
277
278 /* Setup to always have a local .Xauthority. */
279 xauthfile = xmalloc(MAXPATHLEN);
280 strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
281 temporarily_use_uid(pw->pw_uid);
282 if (mkdtemp(xauthfile) == NULL) {
283 restore_uid();
284 error("private X11 dir: mkdtemp %s failed: %s",
285 xauthfile, strerror(errno));
286 xfree(xauthfile);
287 xauthfile = NULL;
0b242b12 288 /* XXXX remove listening channels */
7368a6c8 289 break;
290 }
291 strlcat(xauthfile, "/cookies", MAXPATHLEN);
292 open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
293 restore_uid();
294 fatal_add_cleanup(xauthfile_cleanup_proc, NULL);
295 success = 1;
296 break;
297#else /* XAUTH_PATH */
298 packet_send_debug("No xauth program; cannot forward with spoofing.");
299 break;
300#endif /* XAUTH_PATH */
301
302 case SSH_CMSG_AGENT_REQUEST_FORWARDING:
303 if (no_agent_forwarding_flag || compat13) {
304 debug("Authentication agent forwarding not permitted for this authentication.");
305 break;
306 }
307 debug("Received authentication agent forwarding request.");
308 auth_input_request_forwarding(pw);
309 success = 1;
310 break;
311
312 case SSH_CMSG_PORT_FORWARD_REQUEST:
313 if (no_port_forwarding_flag) {
314 debug("Port forwarding not permitted for this authentication.");
315 break;
316 }
317 debug("Received TCP/IP port forwarding request.");
1d1ffb87 318 channel_input_port_forward_request(pw->pw_uid == 0, options.gateway_ports);
7368a6c8 319 success = 1;
320 break;
321
322 case SSH_CMSG_MAX_PACKET_SIZE:
323 if (packet_set_maxsize(packet_get_int()) > 0)
324 success = 1;
325 break;
326
327 case SSH_CMSG_EXEC_SHELL:
328 case SSH_CMSG_EXEC_CMD:
329 /* Set interactive/non-interactive mode. */
330 packet_set_interactive(have_pty || s->display != NULL,
331 options.keepalives);
332
333 if (type == SSH_CMSG_EXEC_CMD) {
334 command = packet_get_string(&dlen);
335 debug("Exec command '%.500s'", command);
336 packet_integrity_check(plen, 4 + dlen, type);
337 } else {
338 command = NULL;
339 packet_integrity_check(plen, 0, type);
340 }
341 if (forced_command != NULL) {
342 command = forced_command;
343 debug("Forced command '%.500s'", forced_command);
344 }
345 if (have_pty)
346 do_exec_pty(s, command, pw);
347 else
348 do_exec_no_pty(s, command, pw);
349
350 if (command != NULL)
351 xfree(command);
352 /* Cleanup user's local Xauthority file. */
353 if (xauthfile)
354 xauthfile_cleanup_proc(NULL);
355 return;
356
357 default:
358 /*
359 * Any unknown messages in this phase are ignored,
360 * and a failure message is returned.
361 */
362 log("Unknown packet type received after authentication: %d", type);
363 }
364 packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE);
365 packet_send();
366 packet_write_wait();
367
368 /* Enable compression now that we have replied if appropriate. */
369 if (enable_compression_after_reply) {
370 enable_compression_after_reply = 0;
371 packet_start_compression(compression_level);
372 }
373 }
374}
375
376/*
377 * This is called to fork and execute a command when we have no tty. This
378 * will call do_child from the child, and server_loop from the parent after
379 * setting up file descriptors and such.
380 */
6ae2364d 381void
7368a6c8 382do_exec_no_pty(Session *s, const char *command, struct passwd * pw)
383{
384 int pid;
385
386#ifdef USE_PIPES
387 int pin[2], pout[2], perr[2];
388 /* Allocate pipes for communicating with the program. */
389 if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0)
390 packet_disconnect("Could not create pipes: %.100s",
391 strerror(errno));
392#else /* USE_PIPES */
393 int inout[2], err[2];
394 /* Uses socket pairs to communicate with the program. */
395 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||
396 socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)
397 packet_disconnect("Could not create socket pairs: %.100s",
398 strerror(errno));
399#endif /* USE_PIPES */
400 if (s == NULL)
401 fatal("do_exec_no_pty: no session");
402
1d1ffb87 403 session_proctitle(s);
7368a6c8 404
405#ifdef USE_PAM
406 do_pam_setcred();
407#endif /* USE_PAM */
408
409 /* Fork the child. */
410 if ((pid = fork()) == 0) {
411 /* Child. Reinitialize the log since the pid has changed. */
412 log_init(__progname, options.log_level, options.log_facility, log_stderr);
413
414 /*
415 * Create a new session and process group since the 4.4BSD
416 * setlogin() affects the entire process group.
417 */
418 if (setsid() < 0)
419 error("setsid failed: %.100s", strerror(errno));
420
421#ifdef USE_PIPES
422 /*
423 * Redirect stdin. We close the parent side of the socket
424 * pair, and make the child side the standard input.
425 */
426 close(pin[1]);
427 if (dup2(pin[0], 0) < 0)
428 perror("dup2 stdin");
429 close(pin[0]);
430
431 /* Redirect stdout. */
432 close(pout[0]);
433 if (dup2(pout[1], 1) < 0)
434 perror("dup2 stdout");
435 close(pout[1]);
436
437 /* Redirect stderr. */
438 close(perr[0]);
439 if (dup2(perr[1], 2) < 0)
440 perror("dup2 stderr");
441 close(perr[1]);
442#else /* USE_PIPES */
443 /*
444 * Redirect stdin, stdout, and stderr. Stdin and stdout will
445 * use the same socket, as some programs (particularly rdist)
446 * seem to depend on it.
447 */
448 close(inout[1]);
449 close(err[1]);
450 if (dup2(inout[0], 0) < 0) /* stdin */
451 perror("dup2 stdin");
452 if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */
453 perror("dup2 stdout");
454 if (dup2(err[0], 2) < 0) /* stderr */
455 perror("dup2 stderr");
456#endif /* USE_PIPES */
457
458 /* Do processing for the child (exec command etc). */
459 do_child(command, pw, NULL, s->display, s->auth_proto, s->auth_data, NULL);
460 /* NOTREACHED */
461 }
462 if (pid < 0)
463 packet_disconnect("fork failed: %.100s", strerror(errno));
464 s->pid = pid;
465#ifdef USE_PIPES
466 /* We are the parent. Close the child sides of the pipes. */
467 close(pin[0]);
468 close(pout[1]);
469 close(perr[1]);
470
e78a59f5 471 if (compat20) {
0b242b12 472 session_set_fds(s, pin[1], pout[0], s->extended ? perr[0] : -1);
e78a59f5 473 } else {
474 /* Enter the interactive session. */
475 server_loop(pid, pin[1], pout[0], perr[0]);
476 /* server_loop has closed pin[1], pout[1], and perr[1]. */
477 }
7368a6c8 478#else /* USE_PIPES */
479 /* We are the parent. Close the child sides of the socket pairs. */
480 close(inout[0]);
481 close(err[0]);
482
483 /*
484 * Enter the interactive session. Note: server_loop must be able to
485 * handle the case that fdin and fdout are the same.
486 */
e78a59f5 487 if (compat20) {
0b242b12 488 session_set_fds(s, inout[1], inout[1], s->extended ? err[1] : -1);
e78a59f5 489 } else {
490 server_loop(pid, inout[1], inout[1], err[1]);
491 /* server_loop has closed inout[1] and err[1]. */
492 }
7368a6c8 493#endif /* USE_PIPES */
494}
495
496/*
497 * This is called to fork and execute a command when we have a tty. This
498 * will call do_child from the child, and server_loop from the parent after
499 * setting up file descriptors, controlling tty, updating wtmp, utmp,
500 * lastlog, and other such operations.
501 */
6ae2364d 502void
7368a6c8 503do_exec_pty(Session *s, const char *command, struct passwd * pw)
504{
505 FILE *f;
506 char buf[100], *time_string;
507 char line[256];
508 const char *hostname;
509 int fdout, ptyfd, ttyfd, ptymaster;
510 int quiet_login;
511 pid_t pid;
512 socklen_t fromlen;
513 struct sockaddr_storage from;
514 struct stat st;
515 time_t last_login_time;
516
517 if (s == NULL)
518 fatal("do_exec_pty: no session");
519 ptyfd = s->ptyfd;
520 ttyfd = s->ttyfd;
521
522 /* Get remote host name. */
523 hostname = get_canonical_hostname();
524
525 /*
526 * Get the time when the user last logged in. Buf will be set to
527 * contain the hostname the last login was from.
528 */
529 if (!options.use_login) {
530 last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name,
531 buf, sizeof(buf));
532 }
7368a6c8 533
534#ifdef USE_PAM
535 do_pam_session(pw->pw_name, s->tty);
536 do_pam_setcred();
537#endif /* USE_PAM */
538
539 /* Fork the child. */
540 if ((pid = fork()) == 0) {
541 pid = getpid();
542
543 /* Child. Reinitialize the log because the pid has
544 changed. */
545 log_init(__progname, options.log_level, options.log_facility, log_stderr);
546
547 /* Close the master side of the pseudo tty. */
548 close(ptyfd);
549
550 /* Make the pseudo tty our controlling tty. */
551 pty_make_controlling_tty(&ttyfd, s->tty);
552
553 /* Redirect stdin from the pseudo tty. */
554 if (dup2(ttyfd, fileno(stdin)) < 0)
555 error("dup2 stdin failed: %.100s", strerror(errno));
556
557 /* Redirect stdout to the pseudo tty. */
558 if (dup2(ttyfd, fileno(stdout)) < 0)
559 error("dup2 stdin failed: %.100s", strerror(errno));
560
561 /* Redirect stderr to the pseudo tty. */
562 if (dup2(ttyfd, fileno(stderr)) < 0)
563 error("dup2 stdin failed: %.100s", strerror(errno));
564
565 /* Close the extra descriptor for the pseudo tty. */
566 close(ttyfd);
567
1d1ffb87 568/* XXXX ? move to do_child() ??*/
7368a6c8 569 /*
570 * Get IP address of client. This is needed because we want
571 * to record where the user logged in from. If the
572 * connection is not a socket, let the ip address be 0.0.0.0.
573 */
574 memset(&from, 0, sizeof(from));
575 if (packet_connection_is_on_socket()) {
576 fromlen = sizeof(from);
577 if (getpeername(packet_get_connection_in(),
578 (struct sockaddr *) & from, &fromlen) < 0) {
579 debug("getpeername: %.100s", strerror(errno));
580 fatal_cleanup();
581 }
582 }
583 /* Record that there was a login on that terminal. */
584 record_login(pid, s->tty, pw->pw_name, pw->pw_uid, hostname,
585 (struct sockaddr *)&from);
586
587 /* Check if .hushlogin exists. */
588 snprintf(line, sizeof line, "%.200s/.hushlogin", pw->pw_dir);
589 quiet_login = stat(line, &st) >= 0;
590
591#ifdef USE_PAM
592 if (!quiet_login)
593 print_pam_messages();
594#endif /* USE_PAM */
595
596 /*
597 * If the user has logged in before, display the time of last
598 * login. However, don't display anything extra if a command
599 * has been specified (so that ssh can be used to execute
600 * commands on a remote machine without users knowing they
601 * are going to another machine). Login(1) will do this for
602 * us as well, so check if login(1) is used
603 */
604 if (command == NULL && last_login_time != 0 && !quiet_login &&
605 !options.use_login) {
606 /* Convert the date to a string. */
607 time_string = ctime(&last_login_time);
608 /* Remove the trailing newline. */
609 if (strchr(time_string, '\n'))
610 *strchr(time_string, '\n') = 0;
611 /* Display the last login time. Host if displayed
612 if known. */
613 if (strcmp(buf, "") == 0)
614 printf("Last login: %s\r\n", time_string);
615 else
616 printf("Last login: %s from %s\r\n", time_string, buf);
617 }
618 /*
619 * Print /etc/motd unless a command was specified or printing
620 * it was disabled in server options or login(1) will be
621 * used. Note that some machines appear to print it in
622 * /etc/profile or similar.
623 */
624 if (command == NULL && options.print_motd && !quiet_login &&
625 !options.use_login) {
626 /* Print /etc/motd if it exists. */
627 f = fopen("/etc/motd", "r");
628 if (f) {
629 while (fgets(line, sizeof(line), f))
630 fputs(line, stdout);
631 fclose(f);
632 }
633 }
634 /* Do common processing for the child, such as execing the command. */
635 do_child(command, pw, s->term, s->display, s->auth_proto, s->auth_data, s->tty);
636 /* NOTREACHED */
637 }
638 if (pid < 0)
639 packet_disconnect("fork failed: %.100s", strerror(errno));
640 s->pid = pid;
641
642 /* Parent. Close the slave side of the pseudo tty. */
643 close(ttyfd);
644
645 /*
646 * Create another descriptor of the pty master side for use as the
647 * standard input. We could use the original descriptor, but this
648 * simplifies code in server_loop. The descriptor is bidirectional.
649 */
650 fdout = dup(ptyfd);
651 if (fdout < 0)
652 packet_disconnect("dup #1 failed: %.100s", strerror(errno));
653
654 /* we keep a reference to the pty master */
655 ptymaster = dup(ptyfd);
656 if (ptymaster < 0)
657 packet_disconnect("dup #2 failed: %.100s", strerror(errno));
658 s->ptymaster = ptymaster;
659
660 /* Enter interactive session. */
e78a59f5 661 if (compat20) {
662 session_set_fds(s, ptyfd, fdout, -1);
663 } else {
664 server_loop(pid, ptyfd, fdout, -1);
665 /* server_loop _has_ closed ptyfd and fdout. */
666 session_pty_cleanup(s);
667 }
7368a6c8 668}
669
670/*
671 * Sets the value of the given variable in the environment. If the variable
672 * already exists, its value is overriden.
673 */
6ae2364d 674void
7368a6c8 675child_set_env(char ***envp, unsigned int *envsizep, const char *name,
676 const char *value)
677{
678 unsigned int i, namelen;
679 char **env;
680
681 /*
682 * Find the slot where the value should be stored. If the variable
683 * already exists, we reuse the slot; otherwise we append a new slot
684 * at the end of the array, expanding if necessary.
685 */
686 env = *envp;
687 namelen = strlen(name);
688 for (i = 0; env[i]; i++)
689 if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
690 break;
691 if (env[i]) {
692 /* Reuse the slot. */
693 xfree(env[i]);
694 } else {
695 /* New variable. Expand if necessary. */
696 if (i >= (*envsizep) - 1) {
697 (*envsizep) += 50;
698 env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *));
699 }
700 /* Need to set the NULL pointer at end of array beyond the new slot. */
701 env[i + 1] = NULL;
702 }
703
704 /* Allocate space and format the variable in the appropriate slot. */
705 env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
706 snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
707}
708
709/*
710 * Reads environment variables from the given file and adds/overrides them
711 * into the environment. If the file does not exist, this does nothing.
712 * Otherwise, it must consist of empty lines, comments (line starts with '#')
713 * and assignments of the form name=value. No other forms are allowed.
714 */
6ae2364d 715void
7368a6c8 716read_environment_file(char ***env, unsigned int *envsize,
717 const char *filename)
718{
719 FILE *f;
720 char buf[4096];
721 char *cp, *value;
722
723 f = fopen(filename, "r");
724 if (!f)
725 return;
726
727 while (fgets(buf, sizeof(buf), f)) {
728 for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
729 ;
730 if (!*cp || *cp == '#' || *cp == '\n')
731 continue;
732 if (strchr(cp, '\n'))
733 *strchr(cp, '\n') = '\0';
734 value = strchr(cp, '=');
735 if (value == NULL) {
736 fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf);
737 continue;
738 }
739 /* Replace the equals sign by nul, and advance value to the value string. */
740 *value = '\0';
741 value++;
742 child_set_env(env, envsize, cp, value);
743 }
744 fclose(f);
745}
746
747#ifdef USE_PAM
748/*
749 * Sets any environment variables which have been specified by PAM
750 */
751void do_pam_environment(char ***env, int *envsize)
752{
753 char *equals, var_name[512], var_val[512];
754 char **pam_env;
755 int i;
756
757 if ((pam_env = fetch_pam_environment()) == NULL)
758 return;
759
760 for(i = 0; pam_env[i] != NULL; i++) {
761 if ((equals = strstr(pam_env[i], "=")) == NULL)
762 continue;
763
764 if (strlen(pam_env[i]) < (sizeof(var_name) - 1)) {
765 memset(var_name, '\0', sizeof(var_name));
766 memset(var_val, '\0', sizeof(var_val));
767
768 strncpy(var_name, pam_env[i], equals - pam_env[i]);
769 strcpy(var_val, equals + 1);
770
771 debug("PAM environment: %s=%s", var_name, var_val);
772
773 child_set_env(env, envsize, var_name, var_val);
774 }
775 }
776}
777#endif /* USE_PAM */
778
779/*
780 * Performs common processing for the child, such as setting up the
781 * environment, closing extra file descriptors, setting the user and group
782 * ids, and executing the command or shell.
783 */
6ae2364d 784void
7368a6c8 785do_child(const char *command, struct passwd * pw, const char *term,
786 const char *display, const char *auth_proto,
787 const char *auth_data, const char *ttyname)
788{
789 const char *shell, *cp = NULL;
790 char buf[256];
791 FILE *f;
792 unsigned int envsize, i;
793 char **env;
794 extern char **environ;
795 struct stat st;
796 char *argv[10];
797
798#ifndef USE_PAM /* pam_nologin handles this */
799 f = fopen("/etc/nologin", "r");
800 if (f) {
801 /* /etc/nologin exists. Print its contents and exit. */
802 while (fgets(buf, sizeof(buf), f))
803 fputs(buf, stderr);
804 fclose(f);
805 if (pw->pw_uid != 0)
806 exit(254);
807 }
808#endif /* USE_PAM */
809
810 /* Set login name in the kernel. */
811 if (setlogin(pw->pw_name) < 0)
812 error("setlogin failed: %s", strerror(errno));
813
814 /* Set uid, gid, and groups. */
815 /* Login(1) does this as well, and it needs uid 0 for the "-h"
816 switch, so we let login(1) to this for us. */
817 if (!options.use_login) {
818 if (getuid() == 0 || geteuid() == 0) {
819 if (setgid(pw->pw_gid) < 0) {
820 perror("setgid");
821 exit(1);
822 }
823 /* Initialize the group list. */
824 if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
825 perror("initgroups");
826 exit(1);
827 }
828 endgrent();
829
830 /* Permanently switch to the desired uid. */
831 permanently_set_uid(pw->pw_uid);
832 }
833 if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
834 fatal("Failed to set uids to %d.", (int) pw->pw_uid);
835 }
836 /*
837 * Get the shell from the password data. An empty shell field is
838 * legal, and means /bin/sh.
839 */
840 shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell;
841
842#ifdef AFS
843 /* Try to get AFS tokens for the local cell. */
844 if (k_hasafs()) {
845 char cell[64];
846
847 if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0)
848 krb_afslog(cell, 0);
849
850 krb_afslog(0, 0);
851 }
852#endif /* AFS */
853
854 /* Initialize the environment. */
855 envsize = 100;
856 env = xmalloc(envsize * sizeof(char *));
857 env[0] = NULL;
858
859 if (!options.use_login) {
860 /* Set basic environment. */
861 child_set_env(&env, &envsize, "USER", pw->pw_name);
862 child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
863 child_set_env(&env, &envsize, "HOME", pw->pw_dir);
864 child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
865
866 snprintf(buf, sizeof buf, "%.200s/%.50s",
867 _PATH_MAILDIR, pw->pw_name);
868 child_set_env(&env, &envsize, "MAIL", buf);
869
870 /* Normal systems set SHELL by default. */
871 child_set_env(&env, &envsize, "SHELL", shell);
872 }
873 if (getenv("TZ"))
874 child_set_env(&env, &envsize, "TZ", getenv("TZ"));
875
876 /* Set custom environment options from RSA authentication. */
877 while (custom_environment) {
878 struct envstring *ce = custom_environment;
879 char *s = ce->s;
880 int i;
881 for (i = 0; s[i] != '=' && s[i]; i++);
882 if (s[i] == '=') {
883 s[i] = 0;
884 child_set_env(&env, &envsize, s, s + i + 1);
885 }
886 custom_environment = ce->next;
887 xfree(ce->s);
888 xfree(ce);
889 }
890
891 snprintf(buf, sizeof buf, "%.50s %d %d",
892 get_remote_ipaddr(), get_remote_port(), get_local_port());
893 child_set_env(&env, &envsize, "SSH_CLIENT", buf);
894
895 if (ttyname)
896 child_set_env(&env, &envsize, "SSH_TTY", ttyname);
897 if (term)
898 child_set_env(&env, &envsize, "TERM", term);
899 if (display)
900 child_set_env(&env, &envsize, "DISPLAY", display);
901
902#ifdef _AIX
903 {
904 char *authstate,*krb5cc;
905
906 if ((authstate = getenv("AUTHSTATE")) != NULL)
907 child_set_env(&env,&envsize,"AUTHSTATE",authstate);
908
909 if ((krb5cc = getenv("KRB5CCNAME")) != NULL)
910 child_set_env(&env,&envsize,"KRB5CCNAME",krb5cc);
911 }
912#endif
913
914#ifdef KRB4
915 {
916 extern char *ticket;
917
918 if (ticket)
919 child_set_env(&env, &envsize, "KRBTKFILE", ticket);
920 }
921#endif /* KRB4 */
922
923#ifdef USE_PAM
924 /* Pull in any environment variables that may have been set by PAM. */
925 do_pam_environment(&env, &envsize);
926#endif /* USE_PAM */
927
928 read_environment_file(&env,&envsize,"/etc/environment");
929
930 if (xauthfile)
931 child_set_env(&env, &envsize, "XAUTHORITY", xauthfile);
932 if (auth_get_socket_name() != NULL)
933 child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
934 auth_get_socket_name());
935
936 /* read $HOME/.ssh/environment. */
937 if (!options.use_login) {
938 snprintf(buf, sizeof buf, "%.200s/.ssh/environment", pw->pw_dir);
939 read_environment_file(&env, &envsize, buf);
940 }
941 if (debug_flag) {
942 /* dump the environment */
943 fprintf(stderr, "Environment:\n");
944 for (i = 0; env[i]; i++)
945 fprintf(stderr, " %.200s\n", env[i]);
946 }
947 /*
948 * Close the connection descriptors; note that this is the child, and
949 * the server will still have the socket open, and it is important
950 * that we do not shutdown it. Note that the descriptors cannot be
951 * closed before building the environment, as we call
952 * get_remote_ipaddr there.
953 */
954 if (packet_get_connection_in() == packet_get_connection_out())
955 close(packet_get_connection_in());
956 else {
957 close(packet_get_connection_in());
958 close(packet_get_connection_out());
959 }
960 /*
961 * Close all descriptors related to channels. They will still remain
962 * open in the parent.
963 */
964 /* XXX better use close-on-exec? -markus */
965 channel_close_all();
966
967 /*
968 * Close any extra file descriptors. Note that there may still be
969 * descriptors left by system functions. They will be closed later.
970 */
971 endpwent();
972
973 /*
974 * Close any extra open file descriptors so that we don\'t have them
975 * hanging around in clients. Note that we want to do this after
976 * initgroups, because at least on Solaris 2.3 it leaves file
977 * descriptors open.
978 */
979 for (i = 3; i < 64; i++)
980 close(i);
981
982 /* Change current directory to the user\'s home directory. */
983 if (chdir(pw->pw_dir) < 0)
984 fprintf(stderr, "Could not chdir to home directory %s: %s\n",
985 pw->pw_dir, strerror(errno));
986
987 /*
988 * Must take new environment into use so that .ssh/rc, /etc/sshrc and
989 * xauth are run in the proper environment.
990 */
991 environ = env;
992
993 /*
994 * Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first
995 * in this order).
996 */
997 if (!options.use_login) {
998 if (stat(SSH_USER_RC, &st) >= 0) {
999 if (debug_flag)
1000 fprintf(stderr, "Running /bin/sh %s\n", SSH_USER_RC);
1001
1002 f = popen("/bin/sh " SSH_USER_RC, "w");
1003 if (f) {
1004 if (auth_proto != NULL && auth_data != NULL)
1005 fprintf(f, "%s %s\n", auth_proto, auth_data);
1006 pclose(f);
1007 } else
1008 fprintf(stderr, "Could not run %s\n", SSH_USER_RC);
1009 } else if (stat(SSH_SYSTEM_RC, &st) >= 0) {
1010 if (debug_flag)
1011 fprintf(stderr, "Running /bin/sh %s\n", SSH_SYSTEM_RC);
1012
1013 f = popen("/bin/sh " SSH_SYSTEM_RC, "w");
1014 if (f) {
1015 if (auth_proto != NULL && auth_data != NULL)
1016 fprintf(f, "%s %s\n", auth_proto, auth_data);
1017 pclose(f);
1018 } else
1019 fprintf(stderr, "Could not run %s\n", SSH_SYSTEM_RC);
1020 }
1021#ifdef XAUTH_PATH
1022 else {
1023 /* Add authority data to .Xauthority if appropriate. */
1024 if (auth_proto != NULL && auth_data != NULL) {
1025 if (debug_flag)
1026 fprintf(stderr, "Running %.100s add %.100s %.100s %.100s\n",
1027 XAUTH_PATH, display, auth_proto, auth_data);
1028
1029 f = popen(XAUTH_PATH " -q -", "w");
1030 if (f) {
1031 fprintf(f, "add %s %s %s\n", display, auth_proto, auth_data);
1032 pclose(f);
1033 } else
1034 fprintf(stderr, "Could not run %s -q -\n", XAUTH_PATH);
1035 }
1036 }
1037#endif /* XAUTH_PATH */
1038
1039 /* Get the last component of the shell name. */
1040 cp = strrchr(shell, '/');
1041 if (cp)
1042 cp++;
1043 else
1044 cp = shell;
1045 }
1046 /*
1047 * If we have no command, execute the shell. In this case, the shell
1048 * name to be passed in argv[0] is preceded by '-' to indicate that
1049 * this is a login shell.
1050 */
1051 if (!command) {
1052 if (!options.use_login) {
1053 char buf[256];
1054
1055 /*
1056 * Check for mail if we have a tty and it was enabled
1057 * in server options.
1058 */
1059 if (ttyname && options.check_mail) {
1060 char *mailbox;
1061 struct stat mailstat;
1062 mailbox = getenv("MAIL");
1063 if (mailbox != NULL) {
1064 if (stat(mailbox, &mailstat) != 0 || mailstat.st_size == 0)
1065 printf("No mail.\n");
1066 else if (mailstat.st_mtime < mailstat.st_atime)
1067 printf("You have mail.\n");
1068 else
1069 printf("You have new mail.\n");
1070 }
1071 }
1072 /* Start the shell. Set initial character to '-'. */
1073 buf[0] = '-';
1074 strncpy(buf + 1, cp, sizeof(buf) - 1);
1075 buf[sizeof(buf) - 1] = 0;
1076
1077 /* Execute the shell. */
1078 argv[0] = buf;
1079 argv[1] = NULL;
1080 execve(shell, argv, env);
1081
1082 /* Executing the shell failed. */
1083 perror(shell);
1084 exit(1);
1085
1086 } else {
1087 /* Launch login(1). */
1088
1089 execl("/usr/bin/login", "login", "-h", get_remote_ipaddr(),
1090 "-p", "-f", "--", pw->pw_name, NULL);
1091
1092 /* Login couldn't be executed, die. */
1093
1094 perror("login");
1095 exit(1);
1096 }
1097 }
1098 /*
1099 * Execute the command using the user's shell. This uses the -c
1100 * option to execute the command.
1101 */
1102 argv[0] = (char *) cp;
1103 argv[1] = "-c";
1104 argv[2] = (char *) command;
1105 argv[3] = NULL;
1106 execve(shell, argv, env);
1107 perror(shell);
1108 exit(1);
1109}
1110
1111Session *
1112session_new(void)
1113{
1114 int i;
1115 static int did_init = 0;
1116 if (!did_init) {
1117 debug("session_new: init");
1118 for(i = 0; i < MAX_SESSIONS; i++) {
1119 sessions[i].used = 0;
1120 sessions[i].self = i;
1121 }
1122 did_init = 1;
1123 }
1124 for(i = 0; i < MAX_SESSIONS; i++) {
1125 Session *s = &sessions[i];
1126 if (! s->used) {
1127 s->pid = 0;
0b242b12 1128 s->extended = 0;
7368a6c8 1129 s->chanid = -1;
1130 s->ptyfd = -1;
1131 s->ttyfd = -1;
1132 s->term = NULL;
1133 s->pw = NULL;
1134 s->display = NULL;
1135 s->screen = 0;
1136 s->auth_data = NULL;
1137 s->auth_proto = NULL;
1138 s->used = 1;
0b242b12 1139 s->pw = NULL;
7368a6c8 1140 debug("session_new: session %d", i);
1141 return s;
1142 }
1143 }
1144 return NULL;
1145}
1146
1147void
1148session_dump(void)
1149{
1150 int i;
1151 for(i = 0; i < MAX_SESSIONS; i++) {
1152 Session *s = &sessions[i];
1153 debug("dump: used %d session %d %p channel %d pid %d",
1154 s->used,
1155 s->self,
1156 s,
1157 s->chanid,
1158 s->pid);
1159 }
1160}
1161
e78a59f5 1162int
1163session_open(int chanid)
1164{
1165 Session *s = session_new();
1166 debug("session_open: channel %d", chanid);
1167 if (s == NULL) {
1168 error("no more sessions");
1169 return 0;
1170 }
e78a59f5 1171 s->pw = auth_get_user();
1172 if (s->pw == NULL)
0b242b12 1173 fatal("no user for session %i", s->self);
1174 debug("session_open: session %d: link with channel %d", s->self, chanid);
1175 s->chanid = chanid;
e78a59f5 1176 return 1;
1177}
1178
1179Session *
1180session_by_channel(int id)
1181{
1182 int i;
1183 for(i = 0; i < MAX_SESSIONS; i++) {
1184 Session *s = &sessions[i];
1185 if (s->used && s->chanid == id) {
1186 debug("session_by_channel: session %d channel %d", i, id);
1187 return s;
1188 }
1189 }
1190 debug("session_by_channel: unknown channel %d", id);
1191 session_dump();
1192 return NULL;
1193}
1194
1195Session *
1196session_by_pid(pid_t pid)
1197{
1198 int i;
1199 debug("session_by_pid: pid %d", pid);
1200 for(i = 0; i < MAX_SESSIONS; i++) {
1201 Session *s = &sessions[i];
1202 if (s->used && s->pid == pid)
1203 return s;
1204 }
1205 error("session_by_pid: unknown pid %d", pid);
1206 session_dump();
1207 return NULL;
1208}
1209
1210int
1211session_window_change_req(Session *s)
1212{
1213 s->col = packet_get_int();
1214 s->row = packet_get_int();
1215 s->xpixel = packet_get_int();
1216 s->ypixel = packet_get_int();
6ae2364d 1217 packet_done();
e78a59f5 1218 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1219 return 1;
1220}
1221
1222int
1223session_pty_req(Session *s)
1224{
1225 unsigned int len;
6ae2364d 1226 char *term_modes; /* encoded terminal modes */
e78a59f5 1227
1228 if (s->ttyfd != -1)
6ae2364d 1229 return 0;
e78a59f5 1230 s->term = packet_get_string(&len);
1231 s->col = packet_get_int();
1232 s->row = packet_get_int();
1233 s->xpixel = packet_get_int();
1234 s->ypixel = packet_get_int();
6ae2364d 1235 term_modes = packet_get_string(&len);
1236 packet_done();
e78a59f5 1237
1238 if (strcmp(s->term, "") == 0) {
1239 xfree(s->term);
1240 s->term = NULL;
1241 }
1242 /* Allocate a pty and open it. */
1243 if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
1244 xfree(s->term);
1245 s->term = NULL;
1246 s->ptyfd = -1;
1247 s->ttyfd = -1;
1248 error("session_pty_req: session %d alloc failed", s->self);
6ae2364d 1249 xfree(term_modes);
1250 return 0;
e78a59f5 1251 }
1252 debug("session_pty_req: session %d alloc %s", s->self, s->tty);
1253 /*
1254 * Add a cleanup function to clear the utmp entry and record logout
1255 * time in case we call fatal() (e.g., the connection gets closed).
1256 */
1257 fatal_add_cleanup(pty_cleanup_proc, (void *)s);
1258 pty_setowner(s->pw, s->tty);
1259 /* Get window size from the packet. */
1260 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
1261
1d1ffb87 1262 session_proctitle(s);
1263
35484284 1264 /* XXX parse and set terminal modes */
1265 xfree(term_modes);
e78a59f5 1266 return 1;
1267}
1268
0b242b12 1269int
1270session_subsystem_req(Session *s)
1271{
1272 unsigned int len;
1273 int success = 0;
1274 char *subsys = packet_get_string(&len);
1275
1276 packet_done();
1277 log("subsystem request for %s", subsys);
1278
1279 xfree(subsys);
1280 return success;
1281}
1282
1283int
1284session_x11_req(Session *s)
1285{
1286 if (!options.x11_forwarding) {
1287 debug("X11 forwarding disabled in server configuration file.");
1288 return 0;
1289 }
1290 if (xauthfile != NULL) {
1291 debug("X11 fwd already started.");
1292 return 0;
1293 }
1294
1295 debug("Received request for X11 forwarding with auth spoofing.");
1296 if (s->display != NULL)
1297 packet_disconnect("Protocol error: X11 display already set.");
1298
1299 s->single_connection = packet_get_char();
1300 s->auth_proto = packet_get_string(NULL);
1301 s->auth_data = packet_get_string(NULL);
1302 s->screen = packet_get_int();
1303 packet_done();
1304
1305 s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
1306 if (s->display == NULL) {
1307 xfree(s->auth_proto);
1308 xfree(s->auth_data);
1309 return 0;
1310 }
1311 xauthfile = xmalloc(MAXPATHLEN);
1312 strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
1313 temporarily_use_uid(s->pw->pw_uid);
1314 if (mkdtemp(xauthfile) == NULL) {
1315 restore_uid();
1316 error("private X11 dir: mkdtemp %s failed: %s",
1317 xauthfile, strerror(errno));
1318 xfree(xauthfile);
1319 xauthfile = NULL;
1320 xfree(s->auth_proto);
1321 xfree(s->auth_data);
1322 /* XXXX remove listening channels */
1323 return 0;
1324 }
1325 strlcat(xauthfile, "/cookies", MAXPATHLEN);
1326 open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
1327 restore_uid();
1328 fatal_add_cleanup(xauthfile_cleanup_proc, s);
1329 return 1;
1330}
1331
e78a59f5 1332void
1333session_input_channel_req(int id, void *arg)
1334{
1335 unsigned int len;
1336 int reply;
1337 int success = 0;
1338 char *rtype;
1339 Session *s;
1340 Channel *c;
1341
1342 rtype = packet_get_string(&len);
1343 reply = packet_get_char();
1344
1345 s = session_by_channel(id);
1346 if (s == NULL)
1347 fatal("session_input_channel_req: channel %d: no session", id);
1348 c = channel_lookup(id);
1349 if (c == NULL)
1350 fatal("session_input_channel_req: channel %d: bad channel", id);
1351
1352 debug("session_input_channel_req: session %d channel %d request %s reply %d",
1353 s->self, id, rtype, reply);
1354
1355 /*
1356 * a session is in LARVAL state until a shell
1357 * or programm is executed
1358 */
1359 if (c->type == SSH_CHANNEL_LARVAL) {
1360 if (strcmp(rtype, "shell") == 0) {
34bce9a5 1361 packet_done();
1362 s->extended = 1;
e78a59f5 1363 if (s->ttyfd == -1)
1364 do_exec_no_pty(s, NULL, s->pw);
1365 else
1366 do_exec_pty(s, NULL, s->pw);
1367 success = 1;
1368 } else if (strcmp(rtype, "exec") == 0) {
1369 char *command = packet_get_string(&len);
35484284 1370 packet_done();
0b242b12 1371 s->extended = 1;
e78a59f5 1372 if (s->ttyfd == -1)
1373 do_exec_no_pty(s, command, s->pw);
1374 else
1375 do_exec_pty(s, command, s->pw);
1376 xfree(command);
1377 success = 1;
1378 } else if (strcmp(rtype, "pty-req") == 0) {
35484284 1379 success = session_pty_req(s);
0b242b12 1380 } else if (strcmp(rtype, "x11-req") == 0) {
1381 success = session_x11_req(s);
1382 } else if (strcmp(rtype, "subsystem") == 0) {
1383 success = session_subsystem_req(s);
e78a59f5 1384 }
1385 }
1386 if (strcmp(rtype, "window-change") == 0) {
1387 success = session_window_change_req(s);
1388 }
1389
1390 if (reply) {
1391 packet_start(success ?
1392 SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
1393 packet_put_int(c->remote_id);
1394 packet_send();
1395 }
1396 xfree(rtype);
1397}
1398
1399void
1400session_set_fds(Session *s, int fdin, int fdout, int fderr)
1401{
1402 if (!compat20)
1403 fatal("session_set_fds: called for proto != 2.0");
1404 /*
1405 * now that have a child and a pipe to the child,
1406 * we can activate our channel and register the fd's
1407 */
1408 if (s->chanid == -1)
1409 fatal("no channel for session %d", s->self);
1410 channel_set_fds(s->chanid,
1411 fdout, fdin, fderr,
1412 fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ);
1413}
1414
7368a6c8 1415void
1416session_pty_cleanup(Session *s)
1417{
1418 if (s == NULL || s->ttyfd == -1)
1419 return;
1420
1421 debug("session_pty_cleanup: session %i release %s", s->self, s->tty);
1422
1423 /* Cancel the cleanup function. */
1424 fatal_remove_cleanup(pty_cleanup_proc, (void *)s);
1425
1426 /* Record that the user has logged out. */
1427 record_logout(s->pid, s->tty);
1428
1429 /* Release the pseudo-tty. */
1430 pty_release(s->tty);
1431
1432 /*
1433 * Close the server side of the socket pairs. We must do this after
1434 * the pty cleanup, so that another process doesn't get this pty
1435 * while we're still cleaning up.
1436 */
1437 if (close(s->ptymaster) < 0)
1438 error("close(s->ptymaster): %s", strerror(errno));
1439}
e78a59f5 1440
1441void
1442session_exit_message(Session *s, int status)
1443{
1444 Channel *c;
1445 if (s == NULL)
1446 fatal("session_close: no session");
1447 c = channel_lookup(s->chanid);
1448 if (c == NULL)
1449 fatal("session_close: session %d: no channel %d",
1450 s->self, s->chanid);
1451 debug("session_exit_message: session %d channel %d pid %d",
1452 s->self, s->chanid, s->pid);
1453
1454 if (WIFEXITED(status)) {
1455 channel_request_start(s->chanid,
1456 "exit-status", 0);
1457 packet_put_int(WEXITSTATUS(status));
1458 packet_send();
1459 } else if (WIFSIGNALED(status)) {
1460 channel_request_start(s->chanid,
1461 "exit-signal", 0);
1462 packet_put_int(WTERMSIG(status));
1463 packet_put_char(WCOREDUMP(status));
1464 packet_put_cstring("");
1465 packet_put_cstring("");
1466 packet_send();
1467 } else {
1468 /* Some weird exit cause. Just exit. */
1469 packet_disconnect("wait returned status %04x.", status);
1470 }
1471
1472 /* disconnect channel */
1473 debug("session_exit_message: release channel %d", s->chanid);
1474 channel_cancel_cleanup(s->chanid);
9da5c3c9 1475 /*
1476 * emulate a write failure with 'chan_write_failed', nobody will be
1477 * interested in data we write.
1478 * Note that we must not call 'chan_read_failed', since there could
1479 * be some more data waiting in the pipe.
1480 */
0b242b12 1481 if (c->ostate != CHAN_OUTPUT_CLOSED)
1482 chan_write_failed(c);
e78a59f5 1483 s->chanid = -1;
1484}
1485
1486void
1487session_free(Session *s)
1488{
1489 debug("session_free: session %d pid %d", s->self, s->pid);
1490 if (s->term)
1491 xfree(s->term);
1492 if (s->display)
1493 xfree(s->display);
1494 if (s->auth_data)
1495 xfree(s->auth_data);
1496 if (s->auth_proto)
1497 xfree(s->auth_proto);
1498 s->used = 0;
1499}
1500
1501void
1502session_close(Session *s)
1503{
1504 session_pty_cleanup(s);
1505 session_free(s);
1d1ffb87 1506 session_proctitle(s);
e78a59f5 1507}
1508
1509void
1510session_close_by_pid(pid_t pid, int status)
1511{
1512 Session *s = session_by_pid(pid);
1513 if (s == NULL) {
1514 debug("session_close_by_pid: no session for pid %d", s->pid);
1515 return;
1516 }
1517 if (s->chanid != -1)
1518 session_exit_message(s, status);
1519 session_close(s);
1520}
1521
1522/*
1523 * this is called when a channel dies before
1524 * the session 'child' itself dies
1525 */
1526void
1527session_close_by_channel(int id, void *arg)
1528{
1529 Session *s = session_by_channel(id);
1530 if (s == NULL) {
1531 debug("session_close_by_channel: no session for channel %d", id);
1532 return;
1533 }
1534 /* disconnect channel */
1535 channel_cancel_cleanup(s->chanid);
1536 s->chanid = -1;
1537
1538 debug("session_close_by_channel: channel %d kill %d", id, s->pid);
1539 if (s->pid == 0) {
1540 /* close session immediately */
1541 session_close(s);
1542 } else {
1543 /* notify child, delay session cleanup */
1544 if (kill(s->pid, (s->ttyfd == -1) ? SIGTERM : SIGHUP) < 0)
1545 error("session_close_by_channel: kill %d: %s",
1546 s->pid, strerror(errno));
1547 }
1548}
1549
1d1ffb87 1550char *
1551session_tty_list(void)
1552{
1553 static char buf[1024];
1554 int i;
1555 buf[0] = '\0';
1556 for(i = 0; i < MAX_SESSIONS; i++) {
1557 Session *s = &sessions[i];
1558 if (s->used && s->ttyfd != -1) {
1559 if (buf[0] != '\0')
1560 strlcat(buf, ",", sizeof buf);
1561 strlcat(buf, strrchr(s->tty, '/') + 1, sizeof buf);
1562 }
1563 }
1564 if (buf[0] == '\0')
1565 strlcpy(buf, "notty", sizeof buf);
1566 return buf;
1567}
1568
1569void
1570session_proctitle(Session *s)
1571{
1572 if (s->pw == NULL)
1573 error("no user for session %d", s->self);
1574 else
1575 setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
1576}
1577
e78a59f5 1578void
1579do_authenticated2(void)
1580{
1581 /*
1582 * Cancel the alarm we set to limit the time taken for
1583 * authentication.
1584 */
1585 alarm(0);
e78a59f5 1586 server_loop2();
34bce9a5 1587 if (xauthfile)
1588 xauthfile_cleanup_proc(NULL);
e78a59f5 1589}
This page took 0.32849 seconds and 5 git commands to generate.