version 1.74.2.5, 2002/03/09 00:20:45 |
version 1.74.2.6, 2002/06/02 22:56:11 |
|
|
#include "serverloop.h" |
#include "serverloop.h" |
#include "canohost.h" |
#include "canohost.h" |
#include "session.h" |
#include "session.h" |
|
#include "monitor_wrap.h" |
|
|
/* types */ |
|
|
|
#define TTYSZ 64 |
|
typedef struct Session Session; |
|
struct Session { |
|
int used; |
|
int self; |
|
struct passwd *pw; |
|
Authctxt *authctxt; |
|
pid_t pid; |
|
/* tty */ |
|
char *term; |
|
int ptyfd, ttyfd, ptymaster; |
|
int row, col, xpixel, ypixel; |
|
char tty[TTYSZ]; |
|
/* X11 */ |
|
int display_number; |
|
char *display; |
|
int screen; |
|
char *auth_display; |
|
char *auth_proto; |
|
char *auth_data; |
|
int single_connection; |
|
/* proto 2 */ |
|
int chanid; |
|
int is_subsystem; |
|
}; |
|
|
|
/* func */ |
/* func */ |
|
|
Session *session_new(void); |
Session *session_new(void); |
void session_set_fds(Session *, int, int, int); |
void session_set_fds(Session *, int, int, int); |
static void session_pty_cleanup(void *); |
void session_pty_cleanup(void *); |
void session_proctitle(Session *); |
void session_proctitle(Session *); |
int session_setup_x11fwd(Session *); |
int session_setup_x11fwd(Session *); |
void do_exec_pty(Session *, const char *); |
void do_exec_pty(Session *, const char *); |
|
|
static void do_authenticated1(Authctxt *); |
static void do_authenticated1(Authctxt *); |
static void do_authenticated2(Authctxt *); |
static void do_authenticated2(Authctxt *); |
|
|
static void session_close(Session *); |
|
static int session_pty_req(Session *); |
static int session_pty_req(Session *); |
|
|
/* import */ |
/* import */ |
|
|
Session sessions[MAX_SESSIONS]; |
Session sessions[MAX_SESSIONS]; |
|
|
#ifdef HAVE_LOGIN_CAP |
#ifdef HAVE_LOGIN_CAP |
static login_cap_t *lc; |
login_cap_t *lc; |
#endif |
#endif |
|
|
void |
void |
|
|
close(startup_pipe); |
close(startup_pipe); |
startup_pipe = -1; |
startup_pipe = -1; |
} |
} |
#ifdef HAVE_LOGIN_CAP |
|
if ((lc = login_getclass(authctxt->pw->pw_class)) == NULL) { |
|
error("unable to get login class"); |
|
return; |
|
} |
|
#ifdef BSD_AUTH |
|
if (auth_approval(NULL, lc, authctxt->pw->pw_name, "ssh") <= 0) { |
|
packet_disconnect("Approval failure for %s", |
|
authctxt->pw->pw_name); |
|
} |
|
#endif |
|
#endif |
|
/* setup the channel layer */ |
/* setup the channel layer */ |
if (!no_port_forwarding_flag && options.allow_tcp_forwarding) |
if (!no_port_forwarding_flag && options.allow_tcp_forwarding) |
channel_permit_all_opens(); |
channel_permit_all_opens(); |
|
|
do_login(Session *s, const char *command) |
do_login(Session *s, const char *command) |
{ |
{ |
char *time_string; |
char *time_string; |
char hostname[MAXHOSTNAMELEN]; |
|
socklen_t fromlen; |
socklen_t fromlen; |
struct sockaddr_storage from; |
struct sockaddr_storage from; |
time_t last_login_time; |
|
struct passwd * pw = s->pw; |
struct passwd * pw = s->pw; |
pid_t pid = getpid(); |
pid_t pid = getpid(); |
|
|
|
|
} |
} |
} |
} |
|
|
/* Get the time and hostname when the user last logged in. */ |
|
if (options.print_lastlog) { |
|
hostname[0] = '\0'; |
|
last_login_time = get_last_login_time(pw->pw_uid, pw->pw_name, |
|
hostname, sizeof(hostname)); |
|
} |
|
|
|
/* Record that there was a login on that tty from the remote host. */ |
/* Record that there was a login on that tty from the remote host. */ |
record_login(pid, s->tty, pw->pw_name, pw->pw_uid, |
if (!use_privsep) |
get_remote_name_or_ip(utmp_len, options.verify_reverse_mapping), |
record_login(pid, s->tty, pw->pw_name, pw->pw_uid, |
(struct sockaddr *)&from); |
get_remote_name_or_ip(utmp_len, |
|
options.verify_reverse_mapping), |
|
(struct sockaddr *)&from); |
|
|
if (check_quietlogin(s, command)) |
if (check_quietlogin(s, command)) |
return; |
return; |
|
|
if (options.print_lastlog && last_login_time != 0) { |
if (options.print_lastlog && s->last_login_time != 0) { |
time_string = ctime(&last_login_time); |
time_string = ctime(&s->last_login_time); |
if (strchr(time_string, '\n')) |
if (strchr(time_string, '\n')) |
*strchr(time_string, '\n') = 0; |
*strchr(time_string, '\n') = 0; |
if (strcmp(hostname, "") == 0) |
if (strcmp(s->hostname, "") == 0) |
printf("Last login: %s\r\n", time_string); |
printf("Last login: %s\r\n", time_string); |
else |
else |
printf("Last login: %s from %s\r\n", time_string, hostname); |
printf("Last login: %s from %s\r\n", time_string, |
|
s->hostname); |
} |
} |
|
|
do_motd(); |
do_motd(); |
|
|
} |
} |
|
|
/* Set login name, uid, gid, and groups. */ |
/* Set login name, uid, gid, and groups. */ |
static void |
void |
do_setusercontext(struct passwd *pw) |
do_setusercontext(struct passwd *pw) |
{ |
{ |
if (getuid() == 0 || geteuid() == 0) { |
if (getuid() == 0 || geteuid() == 0) { |
|
|
fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); |
fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); |
} |
} |
|
|
|
static void |
|
launch_login(struct passwd *pw, const char *hostname) |
|
{ |
|
/* Launch login(1). */ |
|
|
|
execl("/usr/bin/login", "login", "-h", hostname, |
|
"-p", "-f", "--", pw->pw_name, (char *)NULL); |
|
|
|
/* Login couldn't be executed, die. */ |
|
|
|
perror("login"); |
|
exit(1); |
|
} |
|
|
/* |
/* |
* Performs common processing for the child, such as setting up the |
* Performs common processing for the child, such as setting up the |
* environment, closing extra file descriptors, setting the user and group |
* environment, closing extra file descriptors, setting the user and group |
|
|
signal(SIGPIPE, SIG_DFL); |
signal(SIGPIPE, SIG_DFL); |
|
|
if (options.use_login) { |
if (options.use_login) { |
/* Launch login(1). */ |
launch_login(pw, hostname); |
|
/* NEVERREACHED */ |
execl("/usr/bin/login", "login", "-h", hostname, |
|
"-p", "-f", "--", pw->pw_name, (char *)NULL); |
|
|
|
/* Login couldn't be executed, die. */ |
|
|
|
perror("login"); |
|
exit(1); |
|
} |
} |
|
|
/* Get the last component of the shell name. */ |
/* Get the last component of the shell name. */ |
|
|
return 1; |
return 1; |
} |
} |
|
|
|
Session * |
|
session_by_tty(char *tty) |
|
{ |
|
int i; |
|
for (i = 0; i < MAX_SESSIONS; i++) { |
|
Session *s = &sessions[i]; |
|
if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { |
|
debug("session_by_tty: session %d tty %s", i, tty); |
|
return s; |
|
} |
|
} |
|
debug("session_by_tty: unknown tty %.100s", tty); |
|
session_dump(); |
|
return NULL; |
|
} |
|
|
static Session * |
static Session * |
session_by_channel(int id) |
session_by_channel(int id) |
{ |
{ |
|
|
packet_disconnect("Protocol error: you already have a pty."); |
packet_disconnect("Protocol error: you already have a pty."); |
return 0; |
return 0; |
} |
} |
|
/* Get the time and hostname when the user last logged in. */ |
|
if (options.print_lastlog) { |
|
s->hostname[0] = '\0'; |
|
s->last_login_time = get_last_login_time(s->pw->pw_uid, |
|
s->pw->pw_name, s->hostname, sizeof(s->hostname)); |
|
} |
|
|
s->term = packet_get_string(&len); |
s->term = packet_get_string(&len); |
|
|
|
|
|
|
/* Allocate a pty and open it. */ |
/* Allocate a pty and open it. */ |
debug("Allocating pty."); |
debug("Allocating pty."); |
if (!pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty))) { |
if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { |
if (s->term) |
if (s->term) |
xfree(s->term); |
xfree(s->term); |
s->term = NULL; |
s->term = NULL; |
|
|
* time in case we call fatal() (e.g., the connection gets closed). |
* time in case we call fatal() (e.g., the connection gets closed). |
*/ |
*/ |
fatal_add_cleanup(session_pty_cleanup, (void *)s); |
fatal_add_cleanup(session_pty_cleanup, (void *)s); |
pty_setowner(s->pw, s->tty); |
if (!use_privsep) |
|
pty_setowner(s->pw, s->tty); |
|
|
/* Set window size from the packet. */ |
/* Set window size from the packet. */ |
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); |
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel); |
|
|
* Function to perform pty cleanup. Also called if we get aborted abnormally |
* Function to perform pty cleanup. Also called if we get aborted abnormally |
* (e.g., due to a dropped connection). |
* (e.g., due to a dropped connection). |
*/ |
*/ |
static void |
void |
session_pty_cleanup(void *session) |
session_pty_cleanup2(void *session) |
{ |
{ |
Session *s = session; |
Session *s = session; |
|
|
|
|
record_logout(s->pid, s->tty); |
record_logout(s->pid, s->tty); |
|
|
/* Release the pseudo-tty. */ |
/* Release the pseudo-tty. */ |
pty_release(s->tty); |
if (getuid() == 0) |
|
pty_release(s->tty); |
|
|
/* |
/* |
* Close the server side of the socket pairs. We must do this after |
* Close the server side of the socket pairs. We must do this after |
|
|
* while we're still cleaning up. |
* while we're still cleaning up. |
*/ |
*/ |
if (close(s->ptymaster) < 0) |
if (close(s->ptymaster) < 0) |
error("close(s->ptymaster): %s", strerror(errno)); |
error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno)); |
|
|
/* unlink pty from session */ |
/* unlink pty from session */ |
s->ttyfd = -1; |
s->ttyfd = -1; |
} |
} |
|
|
|
void |
|
session_pty_cleanup(void *session) |
|
{ |
|
PRIVSEP(session_pty_cleanup2(session)); |
|
} |
|
|
static void |
static void |
session_exit_message(Session *s, int status) |
session_exit_message(Session *s, int status) |
{ |
{ |
|
|
s->chanid = -1; |
s->chanid = -1; |
} |
} |
|
|
static void |
void |
session_close(Session *s) |
session_close(Session *s) |
{ |
{ |
debug("session_close: session %d pid %d", s->self, s->pid); |
debug("session_close: session %d pid %d", s->self, s->pid); |
|
|
} |
} |
|
|
void |
void |
session_destroy_all(void) |
session_destroy_all(void (*closefunc)(Session *)) |
{ |
{ |
int i; |
int i; |
for (i = 0; i < MAX_SESSIONS; i++) { |
for (i = 0; i < MAX_SESSIONS; i++) { |
Session *s = &sessions[i]; |
Session *s = &sessions[i]; |
if (s->used) |
if (s->used) { |
session_close(s); |
if (closefunc != NULL) |
|
closefunc(s); |
|
else |
|
session_close(s); |
|
} |
} |
} |
} |
} |
|
|