version 1.108, 2001/10/11 13:45:21 |
version 1.108.2.5, 2002/06/22 07:23:17 |
|
|
#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 */ |
|
char *display; |
|
int screen; |
|
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 |
|
|
|
/* Name and directory of socket for authentication agent forwarding. */ |
|
static char *auth_sock_name = NULL; |
|
static char *auth_sock_dir = NULL; |
|
|
|
/* removes the agent forwarding socket */ |
|
|
|
static void |
|
auth_sock_cleanup_proc(void *_pw) |
|
{ |
|
struct passwd *pw = _pw; |
|
|
|
if (auth_sock_name != NULL) { |
|
temporarily_use_uid(pw); |
|
unlink(auth_sock_name); |
|
rmdir(auth_sock_dir); |
|
auth_sock_name = NULL; |
|
restore_uid(); |
|
} |
|
} |
|
|
|
static int |
|
auth_input_request_forwarding(struct passwd * pw) |
|
{ |
|
Channel *nc; |
|
int sock; |
|
struct sockaddr_un sunaddr; |
|
|
|
if (auth_sock_name != NULL) { |
|
error("authentication forwarding requested twice."); |
|
return 0; |
|
} |
|
|
|
/* Temporarily drop privileged uid for mkdir/bind. */ |
|
temporarily_use_uid(pw); |
|
|
|
/* Allocate a buffer for the socket name, and format the name. */ |
|
auth_sock_name = xmalloc(MAXPATHLEN); |
|
auth_sock_dir = xmalloc(MAXPATHLEN); |
|
strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXX", MAXPATHLEN); |
|
|
|
/* Create private directory for socket */ |
|
if (mkdtemp(auth_sock_dir) == NULL) { |
|
packet_send_debug("Agent forwarding disabled: " |
|
"mkdtemp() failed: %.100s", strerror(errno)); |
|
restore_uid(); |
|
xfree(auth_sock_name); |
|
xfree(auth_sock_dir); |
|
auth_sock_name = NULL; |
|
auth_sock_dir = NULL; |
|
return 0; |
|
} |
|
snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", |
|
auth_sock_dir, (long) getpid()); |
|
|
|
/* delete agent socket on fatal() */ |
|
fatal_add_cleanup(auth_sock_cleanup_proc, pw); |
|
|
|
/* Create the socket. */ |
|
sock = socket(AF_UNIX, SOCK_STREAM, 0); |
|
if (sock < 0) |
|
packet_disconnect("socket: %.100s", strerror(errno)); |
|
|
|
/* Bind it to the name. */ |
|
memset(&sunaddr, 0, sizeof(sunaddr)); |
|
sunaddr.sun_family = AF_UNIX; |
|
strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); |
|
|
|
if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) |
|
packet_disconnect("bind: %.100s", strerror(errno)); |
|
|
|
/* Restore the privileged uid. */ |
|
restore_uid(); |
|
|
|
/* Start listening on the socket. */ |
|
if (listen(sock, 5) < 0) |
|
packet_disconnect("listen: %.100s", strerror(errno)); |
|
|
|
/* Allocate a channel for the authentication agent socket. */ |
|
nc = channel_new("auth socket", |
|
SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1, |
|
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, |
|
0, xstrdup("auth socket"), 1); |
|
strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); |
|
return 1; |
|
} |
|
|
|
|
void |
void |
do_authenticated(Authctxt *authctxt) |
do_authenticated(Authctxt *authctxt) |
{ |
{ |
|
|
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_authenticated1(authctxt); |
do_authenticated1(authctxt); |
|
|
/* remove agent socket */ |
/* remove agent socket */ |
if (auth_get_socket_name()) |
if (auth_sock_name != NULL) |
auth_sock_cleanup_proc(authctxt->pw); |
auth_sock_cleanup_proc(authctxt->pw); |
#ifdef KRB4 |
#ifdef KRB4 |
if (options.kerberos_ticket_cleanup) |
if (options.kerberos_ticket_cleanup) |
|
|
{ |
{ |
Session *s; |
Session *s; |
char *command; |
char *command; |
int success, type, plen, screen_flag; |
int success, type, screen_flag; |
int compression_level = 0, enable_compression_after_reply = 0; |
int compression_level = 0, enable_compression_after_reply = 0; |
u_int proto_len, data_len, dlen; |
u_int proto_len, data_len, dlen; |
|
|
|
|
success = 0; |
success = 0; |
|
|
/* Get a packet from the client. */ |
/* Get a packet from the client. */ |
type = packet_read(&plen); |
type = packet_read(); |
|
|
/* Process the packet. */ |
/* Process the packet. */ |
switch (type) { |
switch (type) { |
case SSH_CMSG_REQUEST_COMPRESSION: |
case SSH_CMSG_REQUEST_COMPRESSION: |
packet_integrity_check(plen, 4, type); |
|
compression_level = packet_get_int(); |
compression_level = packet_get_int(); |
|
packet_check_eom(); |
if (compression_level < 1 || compression_level > 9) { |
if (compression_level < 1 || compression_level > 9) { |
packet_send_debug("Received illegal compression level %d.", |
packet_send_debug("Received illegal compression level %d.", |
compression_level); |
compression_level); |
break; |
break; |
} |
} |
|
if (!options.compression) { |
|
debug2("compression disabled"); |
|
break; |
|
} |
/* Enable compression after we have responded with SUCCESS. */ |
/* Enable compression after we have responded with SUCCESS. */ |
enable_compression_after_reply = 1; |
enable_compression_after_reply = 1; |
success = 1; |
success = 1; |
|
|
} else { |
} else { |
s->screen = 0; |
s->screen = 0; |
} |
} |
packet_done(); |
packet_check_eom(); |
success = session_setup_x11fwd(s); |
success = session_setup_x11fwd(s); |
if (!success) { |
if (!success) { |
xfree(s->auth_proto); |
xfree(s->auth_proto); |
|
|
if (packet_set_maxsize(packet_get_int()) > 0) |
if (packet_set_maxsize(packet_get_int()) > 0) |
success = 1; |
success = 1; |
break; |
break; |
|
|
#if defined(AFS) || defined(KRB5) |
#if defined(AFS) || defined(KRB5) |
case SSH_CMSG_HAVE_KERBEROS_TGT: |
case SSH_CMSG_HAVE_KERBEROS_TGT: |
if (!options.kerberos_tgt_passing) { |
if (!options.kerberos_tgt_passing) { |
verbose("Kerberos TGT passing disabled."); |
verbose("Kerberos TGT passing disabled."); |
} else { |
} else { |
char *kdata = packet_get_string(&dlen); |
char *kdata = packet_get_string(&dlen); |
packet_integrity_check(plen, 4 + dlen, type); |
packet_check_eom(); |
|
|
/* XXX - 0x41, see creds_to_radix version */ |
/* XXX - 0x41, see creds_to_radix version */ |
if (kdata[0] != 0x41) { |
if (kdata[0] != 0x41) { |
#ifdef KRB5 |
#ifdef KRB5 |
krb5_data tgt; |
krb5_data tgt; |
tgt.data = kdata; |
tgt.data = kdata; |
tgt.length = dlen; |
tgt.length = dlen; |
|
|
if (auth_krb5_tgt(s->authctxt, &tgt)) |
if (auth_krb5_tgt(s->authctxt, &tgt)) |
success = 1; |
success = 1; |
else |
else |
|
|
} |
} |
break; |
break; |
#endif /* AFS || KRB5 */ |
#endif /* AFS || KRB5 */ |
|
|
#ifdef AFS |
#ifdef AFS |
case SSH_CMSG_HAVE_AFS_TOKEN: |
case SSH_CMSG_HAVE_AFS_TOKEN: |
if (!options.afs_token_passing || !k_hasafs()) { |
if (!options.afs_token_passing || !k_hasafs()) { |
|
|
} else { |
} else { |
/* Accept AFS token. */ |
/* Accept AFS token. */ |
char *token = packet_get_string(&dlen); |
char *token = packet_get_string(&dlen); |
packet_integrity_check(plen, 4 + dlen, type); |
packet_check_eom(); |
|
|
if (auth_afs_token(s->authctxt, token)) |
if (auth_afs_token(s->authctxt, token)) |
success = 1; |
success = 1; |
else |
else |
|
|
} else { |
} else { |
do_exec(s, NULL); |
do_exec(s, NULL); |
} |
} |
packet_done(); |
packet_check_eom(); |
session_close(s); |
session_close(s); |
return; |
return; |
|
|
|
|
void |
void |
do_exec_no_pty(Session *s, const char *command) |
do_exec_no_pty(Session *s, const char *command) |
{ |
{ |
int pid; |
pid_t pid; |
|
|
#ifdef USE_PIPES |
#ifdef USE_PIPES |
int pin[2], pout[2], perr[2]; |
int pin[2], pout[2], perr[2]; |
|
|
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(); |
|
|
|
|
if (packet_connection_is_on_socket()) { |
if (packet_connection_is_on_socket()) { |
fromlen = sizeof(from); |
fromlen = sizeof(from); |
if (getpeername(packet_get_connection_in(), |
if (getpeername(packet_get_connection_in(), |
(struct sockaddr *) & from, &fromlen) < 0) { |
(struct sockaddr *) & from, &fromlen) < 0) { |
debug("getpeername: %.100s", strerror(errno)); |
debug("getpeername: %.100s", strerror(errno)); |
fatal_cleanup(); |
fatal_cleanup(); |
} |
} |
} |
} |
|
|
/* 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.reverse_mapping_check), |
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(); |
|
|
*/ |
*/ |
static void |
static void |
child_set_env(char ***envp, u_int *envsizep, const char *name, |
child_set_env(char ***envp, u_int *envsizep, const char *name, |
const char *value) |
const char *value) |
{ |
{ |
u_int i, namelen; |
u_int i, namelen; |
char **env; |
char **env; |
|
|
*/ |
*/ |
static void |
static void |
read_environment_file(char ***env, u_int *envsize, |
read_environment_file(char ***env, u_int *envsize, |
const char *filename) |
const char *filename) |
{ |
{ |
FILE *f; |
FILE *f; |
char buf[4096]; |
char buf[4096]; |
|
|
fclose(f); |
fclose(f); |
} |
} |
|
|
/* |
static char ** |
* Performs common processing for the child, such as setting up the |
do_setup_env(Session *s, const char *shell) |
* environment, closing extra file descriptors, setting the user and group |
|
* ids, and executing the command or shell. |
|
*/ |
|
void |
|
do_child(Session *s, const char *command) |
|
{ |
{ |
const char *shell, *hostname = NULL, *cp = NULL; |
|
struct passwd *pw = s->pw; |
|
char buf[256]; |
char buf[256]; |
char cmd[1024]; |
u_int i, envsize; |
FILE *f = NULL; |
|
u_int envsize, i; |
|
char **env; |
char **env; |
extern char **environ; |
struct passwd *pw = s->pw; |
struct stat st; |
|
char *argv[10]; |
|
int do_xauth; |
|
|
|
do_xauth = |
|
s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL; |
|
|
|
/* remove hostkey from the child's memory */ |
|
destroy_sensitive_data(); |
|
|
|
/* login(1) is only called if we execute the login shell */ |
|
if (options.use_login && command != NULL) |
|
options.use_login = 0; |
|
|
|
if (!options.use_login) { |
|
#ifdef HAVE_LOGIN_CAP |
|
if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) |
|
f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN, |
|
_PATH_NOLOGIN), "r"); |
|
#else |
|
if (pw->pw_uid) |
|
f = fopen(_PATH_NOLOGIN, "r"); |
|
#endif |
|
if (f) { |
|
/* /etc/nologin exists. Print its contents and exit. */ |
|
while (fgets(buf, sizeof(buf), f)) |
|
fputs(buf, stderr); |
|
fclose(f); |
|
exit(254); |
|
} |
|
} |
|
/* Set login name, uid, gid, and groups. */ |
|
/* Login(1) does this as well, and it needs uid 0 for the "-h" |
|
switch, so we let login(1) to this for us. */ |
|
if (!options.use_login) { |
|
if (getuid() == 0 || geteuid() == 0) { |
|
#ifdef HAVE_LOGIN_CAP |
|
if (setusercontext(lc, pw, pw->pw_uid, |
|
(LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { |
|
perror("unable to set user context"); |
|
exit(1); |
|
} |
|
#else |
|
if (setlogin(pw->pw_name) < 0) |
|
error("setlogin failed: %s", strerror(errno)); |
|
if (setgid(pw->pw_gid) < 0) { |
|
perror("setgid"); |
|
exit(1); |
|
} |
|
/* Initialize the group list. */ |
|
if (initgroups(pw->pw_name, pw->pw_gid) < 0) { |
|
perror("initgroups"); |
|
exit(1); |
|
} |
|
endgrent(); |
|
|
|
/* Permanently switch to the desired uid. */ |
|
permanently_set_uid(pw); |
|
#endif |
|
} |
|
if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid) |
|
fatal("Failed to set uids to %u.", (u_int) pw->pw_uid); |
|
} |
|
/* |
|
* Get the shell from the password data. An empty shell field is |
|
* legal, and means /bin/sh. |
|
*/ |
|
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; |
|
#ifdef HAVE_LOGIN_CAP |
|
shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); |
|
#endif |
|
|
|
/* Initialize the environment. */ |
/* Initialize the environment. */ |
envsize = 100; |
envsize = 100; |
env = xmalloc(envsize * sizeof(char *)); |
env = xmalloc(envsize * sizeof(char *)); |
|
|
child_set_env(&env, &envsize, "TZ", getenv("TZ")); |
child_set_env(&env, &envsize, "TZ", getenv("TZ")); |
|
|
/* Set custom environment options from RSA authentication. */ |
/* Set custom environment options from RSA authentication. */ |
while (custom_environment) { |
if (!options.use_login) { |
struct envstring *ce = custom_environment; |
while (custom_environment) { |
char *s = ce->s; |
struct envstring *ce = custom_environment; |
int i; |
char *s = ce->s; |
for (i = 0; s[i] != '=' && s[i]; i++); |
|
if (s[i] == '=') { |
for (i = 0; s[i] != '=' && s[i]; i++) |
s[i] = 0; |
; |
child_set_env(&env, &envsize, s, s + i + 1); |
if (s[i] == '=') { |
|
s[i] = 0; |
|
child_set_env(&env, &envsize, s, s + i + 1); |
|
} |
|
custom_environment = ce->next; |
|
xfree(ce->s); |
|
xfree(ce); |
} |
} |
custom_environment = ce->next; |
|
xfree(ce->s); |
|
xfree(ce); |
|
} |
} |
|
|
snprintf(buf, sizeof buf, "%.50s %d %d", |
snprintf(buf, sizeof buf, "%.50s %d %d", |
get_remote_ipaddr(), get_remote_port(), get_local_port()); |
get_remote_ipaddr(), get_remote_port(), get_local_port()); |
child_set_env(&env, &envsize, "SSH_CLIENT", buf); |
child_set_env(&env, &envsize, "SSH_CLIENT", buf); |
|
|
if (s->ttyfd != -1) |
if (s->ttyfd != -1) |
|
|
#ifdef KRB4 |
#ifdef KRB4 |
if (s->authctxt->krb4_ticket_file) |
if (s->authctxt->krb4_ticket_file) |
child_set_env(&env, &envsize, "KRBTKFILE", |
child_set_env(&env, &envsize, "KRBTKFILE", |
s->authctxt->krb4_ticket_file); |
s->authctxt->krb4_ticket_file); |
#endif |
#endif |
#ifdef KRB5 |
#ifdef KRB5 |
if (s->authctxt->krb5_ticket_file) |
if (s->authctxt->krb5_ticket_file) |
child_set_env(&env, &envsize, "KRB5CCNAME", |
child_set_env(&env, &envsize, "KRB5CCNAME", |
s->authctxt->krb5_ticket_file); |
s->authctxt->krb5_ticket_file); |
#endif |
#endif |
if (auth_get_socket_name() != NULL) |
if (auth_sock_name != NULL) |
child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, |
child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, |
auth_get_socket_name()); |
auth_sock_name); |
|
|
/* read $HOME/.ssh/environment. */ |
/* read $HOME/.ssh/environment. */ |
if (!options.use_login) { |
if (!options.use_login) { |
|
|
for (i = 0; env[i]; i++) |
for (i = 0; env[i]; i++) |
fprintf(stderr, " %.200s\n", env[i]); |
fprintf(stderr, " %.200s\n", env[i]); |
} |
} |
|
return env; |
|
} |
|
|
|
/* |
|
* Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found |
|
* first in this order). |
|
*/ |
|
static void |
|
do_rc_files(Session *s, const char *shell) |
|
{ |
|
FILE *f = NULL; |
|
char cmd[1024]; |
|
int do_xauth; |
|
struct stat st; |
|
|
|
do_xauth = |
|
s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL; |
|
|
|
/* ignore _PATH_SSH_USER_RC for subsystems */ |
|
if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) { |
|
snprintf(cmd, sizeof cmd, "%s -c '%s %s'", |
|
shell, _PATH_BSHELL, _PATH_SSH_USER_RC); |
|
if (debug_flag) |
|
fprintf(stderr, "Running %s\n", cmd); |
|
f = popen(cmd, "w"); |
|
if (f) { |
|
if (do_xauth) |
|
fprintf(f, "%s %s\n", s->auth_proto, |
|
s->auth_data); |
|
pclose(f); |
|
} else |
|
fprintf(stderr, "Could not run %s\n", |
|
_PATH_SSH_USER_RC); |
|
} else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) { |
|
if (debug_flag) |
|
fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, |
|
_PATH_SSH_SYSTEM_RC); |
|
f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); |
|
if (f) { |
|
if (do_xauth) |
|
fprintf(f, "%s %s\n", s->auth_proto, |
|
s->auth_data); |
|
pclose(f); |
|
} else |
|
fprintf(stderr, "Could not run %s\n", |
|
_PATH_SSH_SYSTEM_RC); |
|
} else if (do_xauth && options.xauth_location != NULL) { |
|
/* Add authority data to .Xauthority if appropriate. */ |
|
if (debug_flag) { |
|
fprintf(stderr, |
|
"Running %.500s add " |
|
"%.100s %.100s %.100s\n", |
|
options.xauth_location, s->auth_display, |
|
s->auth_proto, s->auth_data); |
|
} |
|
snprintf(cmd, sizeof cmd, "%s -q -", |
|
options.xauth_location); |
|
f = popen(cmd, "w"); |
|
if (f) { |
|
fprintf(f, "add %s %s %s\n", |
|
s->auth_display, s->auth_proto, |
|
s->auth_data); |
|
pclose(f); |
|
} else { |
|
fprintf(stderr, "Could not run %s\n", |
|
cmd); |
|
} |
|
} |
|
} |
|
|
|
static void |
|
do_nologin(struct passwd *pw) |
|
{ |
|
FILE *f = NULL; |
|
char buf[1024]; |
|
|
|
#ifdef HAVE_LOGIN_CAP |
|
if (!login_getcapbool(lc, "ignorenologin", 0) && pw->pw_uid) |
|
f = fopen(login_getcapstr(lc, "nologin", _PATH_NOLOGIN, |
|
_PATH_NOLOGIN), "r"); |
|
#else |
|
if (pw->pw_uid) |
|
f = fopen(_PATH_NOLOGIN, "r"); |
|
#endif |
|
if (f) { |
|
/* /etc/nologin exists. Print its contents and exit. */ |
|
while (fgets(buf, sizeof(buf), f)) |
|
fputs(buf, stderr); |
|
fclose(f); |
|
exit(254); |
|
} |
|
} |
|
|
|
/* Set login name, uid, gid, and groups. */ |
|
void |
|
do_setusercontext(struct passwd *pw) |
|
{ |
|
if (getuid() == 0 || geteuid() == 0) { |
|
#ifdef HAVE_LOGIN_CAP |
|
if (setusercontext(lc, pw, pw->pw_uid, |
|
(LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { |
|
perror("unable to set user context"); |
|
exit(1); |
|
} |
|
#else |
|
if (setlogin(pw->pw_name) < 0) |
|
error("setlogin failed: %s", strerror(errno)); |
|
if (setgid(pw->pw_gid) < 0) { |
|
perror("setgid"); |
|
exit(1); |
|
} |
|
/* Initialize the group list. */ |
|
if (initgroups(pw->pw_name, pw->pw_gid) < 0) { |
|
perror("initgroups"); |
|
exit(1); |
|
} |
|
endgrent(); |
|
|
|
/* Permanently switch to the desired uid. */ |
|
permanently_set_uid(pw); |
|
#endif |
|
} |
|
if (getuid() != pw->pw_uid || geteuid() != 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 |
|
* environment, closing extra file descriptors, setting the user and group |
|
* ids, and executing the command or shell. |
|
*/ |
|
void |
|
do_child(Session *s, const char *command) |
|
{ |
|
extern char **environ; |
|
char **env; |
|
char *argv[10]; |
|
const char *shell, *shell0, *hostname = NULL; |
|
struct passwd *pw = s->pw; |
|
u_int i; |
|
|
|
/* remove hostkey from the child's memory */ |
|
destroy_sensitive_data(); |
|
|
|
/* login(1) is only called if we execute the login shell */ |
|
if (options.use_login && command != NULL) |
|
options.use_login = 0; |
|
|
|
/* |
|
* Login(1) does this as well, and it needs uid 0 for the "-h" |
|
* switch, so we let login(1) to this for us. |
|
*/ |
|
if (!options.use_login) { |
|
do_nologin(pw); |
|
do_setusercontext(pw); |
|
} |
|
|
|
/* |
|
* Get the shell from the password data. An empty shell field is |
|
* legal, and means /bin/sh. |
|
*/ |
|
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; |
|
#ifdef HAVE_LOGIN_CAP |
|
shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); |
|
#endif |
|
|
|
env = do_setup_env(s, shell); |
|
|
/* we have to stash the hostname before we close our socket. */ |
/* we have to stash the hostname before we close our socket. */ |
if (options.use_login) |
if (options.use_login) |
hostname = get_remote_name_or_ip(utmp_len, |
hostname = get_remote_name_or_ip(utmp_len, |
options.reverse_mapping_check); |
options.verify_reverse_mapping); |
/* |
/* |
* Close the connection descriptors; note that this is the child, and |
* Close the connection descriptors; note that this is the child, and |
* the server will still have the socket open, and it is important |
* the server will still have the socket open, and it is important |
|
|
close(i); |
close(i); |
|
|
/* |
/* |
* Must take new environment into use so that .ssh/rc, /etc/sshrc and |
* Must take new environment into use so that .ssh/rc, |
* xauth are run in the proper environment. |
* /etc/sshrc and xauth are run in the proper environment. |
*/ |
*/ |
environ = env; |
environ = env; |
|
|
|
|
/* Try to get AFS tokens for the local cell. */ |
/* Try to get AFS tokens for the local cell. */ |
if (k_hasafs()) { |
if (k_hasafs()) { |
char cell[64]; |
char cell[64]; |
|
|
if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) |
if (k_afs_cell_of_file(pw->pw_dir, cell, sizeof(cell)) == 0) |
krb_afslog(cell, 0); |
krb_afslog(cell, 0); |
|
|
krb_afslog(0, 0); |
krb_afslog(0, 0); |
} |
} |
#endif /* AFS */ |
#endif /* AFS */ |
|
|
#endif |
#endif |
} |
} |
|
|
/* |
if (!options.use_login) |
* Run $HOME/.ssh/rc, /etc/sshrc, or xauth (whichever is found first |
do_rc_files(s, shell); |
* in this order). |
|
*/ |
|
if (!options.use_login) { |
|
/* ignore _PATH_SSH_USER_RC for subsystems */ |
|
if (!s->is_subsystem && (stat(_PATH_SSH_USER_RC, &st) >= 0)) { |
|
snprintf(cmd, sizeof cmd, "%s -c '%s %s'", |
|
shell, _PATH_BSHELL, _PATH_SSH_USER_RC); |
|
if (debug_flag) |
|
fprintf(stderr, "Running %s\n", cmd); |
|
f = popen(cmd, "w"); |
|
if (f) { |
|
if (do_xauth) |
|
fprintf(f, "%s %s\n", s->auth_proto, |
|
s->auth_data); |
|
pclose(f); |
|
} else |
|
fprintf(stderr, "Could not run %s\n", |
|
_PATH_SSH_USER_RC); |
|
} else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) { |
|
if (debug_flag) |
|
fprintf(stderr, "Running %s %s\n", _PATH_BSHELL, |
|
_PATH_SSH_SYSTEM_RC); |
|
f = popen(_PATH_BSHELL " " _PATH_SSH_SYSTEM_RC, "w"); |
|
if (f) { |
|
if (do_xauth) |
|
fprintf(f, "%s %s\n", s->auth_proto, |
|
s->auth_data); |
|
pclose(f); |
|
} else |
|
fprintf(stderr, "Could not run %s\n", |
|
_PATH_SSH_SYSTEM_RC); |
|
} else if (do_xauth && options.xauth_location != NULL) { |
|
/* Add authority data to .Xauthority if appropriate. */ |
|
char *screen = strchr(s->display, ':'); |
|
|
|
if (debug_flag) { |
|
fprintf(stderr, |
|
"Running %.100s add " |
|
"%.100s %.100s %.100s\n", |
|
options.xauth_location, s->display, |
|
s->auth_proto, s->auth_data); |
|
if (screen != NULL) |
|
fprintf(stderr, |
|
"Adding %.*s/unix%s %s %s\n", |
|
(int)(screen - s->display), |
|
s->display, screen, |
|
s->auth_proto, s->auth_data); |
|
} |
|
snprintf(cmd, sizeof cmd, "%s -q -", |
|
options.xauth_location); |
|
f = popen(cmd, "w"); |
|
if (f) { |
|
fprintf(f, "add %s %s %s\n", s->display, |
|
s->auth_proto, s->auth_data); |
|
if (screen != NULL) |
|
fprintf(f, "add %.*s/unix%s %s %s\n", |
|
(int)(screen - s->display), |
|
s->display, screen, |
|
s->auth_proto, |
|
s->auth_data); |
|
pclose(f); |
|
} else { |
|
fprintf(stderr, "Could not run %s\n", |
|
cmd); |
|
} |
|
} |
|
/* Get the last component of the shell name. */ |
|
cp = strrchr(shell, '/'); |
|
if (cp) |
|
cp++; |
|
else |
|
cp = shell; |
|
} |
|
|
|
/* restore SIGPIPE for child */ |
/* restore SIGPIPE for child */ |
signal(SIGPIPE, SIG_DFL); |
signal(SIGPIPE, SIG_DFL); |
|
|
|
if (options.use_login) { |
|
launch_login(pw, hostname); |
|
/* NEVERREACHED */ |
|
} |
|
|
|
/* Get the last component of the shell name. */ |
|
if ((shell0 = strrchr(shell, '/')) != NULL) |
|
shell0++; |
|
else |
|
shell0 = shell; |
|
|
/* |
/* |
* If we have no command, execute the shell. In this case, the shell |
* If we have no command, execute the shell. In this case, the shell |
* name to be passed in argv[0] is preceded by '-' to indicate that |
* name to be passed in argv[0] is preceded by '-' to indicate that |
* this is a login shell. |
* this is a login shell. |
*/ |
*/ |
if (!command) { |
if (!command) { |
if (!options.use_login) { |
char argv0[256]; |
char buf[256]; |
|
|
|
/* Start the shell. Set initial character to '-'. */ |
/* Start the shell. Set initial character to '-'. */ |
buf[0] = '-'; |
argv0[0] = '-'; |
strncpy(buf + 1, cp, sizeof(buf) - 1); |
|
buf[sizeof(buf) - 1] = 0; |
|
|
|
/* Execute the shell. */ |
if (strlcpy(argv0 + 1, shell0, sizeof(argv0) - 1) |
argv[0] = buf; |
>= sizeof(argv0) - 1) { |
argv[1] = NULL; |
errno = EINVAL; |
execve(shell, argv, env); |
|
|
|
/* Executing the shell failed. */ |
|
perror(shell); |
perror(shell); |
exit(1); |
exit(1); |
|
} |
|
|
} else { |
/* Execute the shell. */ |
/* Launch login(1). */ |
argv[0] = argv0; |
|
argv[1] = NULL; |
|
execve(shell, argv, env); |
|
|
execl("/usr/bin/login", "login", "-h", hostname, |
/* Executing the shell failed. */ |
"-p", "-f", "--", pw->pw_name, (char *)NULL); |
perror(shell); |
|
exit(1); |
/* Login couldn't be executed, die. */ |
|
|
|
perror("login"); |
|
exit(1); |
|
} |
|
} |
} |
/* |
/* |
* Execute the command using the user's shell. This uses the -c |
* Execute the command using the user's shell. This uses the -c |
* option to execute the command. |
* option to execute the command. |
*/ |
*/ |
argv[0] = (char *) cp; |
argv[0] = (char *) shell0; |
argv[1] = "-c"; |
argv[1] = "-c"; |
argv[2] = (char *) command; |
argv[2] = (char *) command; |
argv[3] = NULL; |
argv[3] = NULL; |
|
|
static int did_init = 0; |
static int did_init = 0; |
if (!did_init) { |
if (!did_init) { |
debug("session_new: init"); |
debug("session_new: init"); |
for(i = 0; i < MAX_SESSIONS; i++) { |
for (i = 0; i < MAX_SESSIONS; i++) { |
sessions[i].used = 0; |
sessions[i].used = 0; |
} |
} |
did_init = 1; |
did_init = 1; |
} |
} |
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) { |
memset(s, 0, sizeof(*s)); |
memset(s, 0, sizeof(*s)); |
|
|
session_dump(void) |
session_dump(void) |
{ |
{ |
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]; |
debug("dump: used %d session %d %p channel %d pid %d", |
debug("dump: used %d session %d %p channel %d pid %ld", |
s->used, |
s->used, |
s->self, |
s->self, |
s, |
s, |
s->chanid, |
s->chanid, |
s->pid); |
(long)s->pid); |
} |
} |
} |
} |
|
|
|
|
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) |
{ |
{ |
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 && s->chanid == id) { |
if (s->used && s->chanid == id) { |
debug("session_by_channel: session %d channel %d", i, id); |
debug("session_by_channel: session %d channel %d", i, id); |
|
|
session_by_pid(pid_t pid) |
session_by_pid(pid_t pid) |
{ |
{ |
int i; |
int i; |
debug("session_by_pid: pid %d", pid); |
debug("session_by_pid: pid %ld", (long)pid); |
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 && s->pid == pid) |
if (s->used && s->pid == pid) |
return s; |
return s; |
} |
} |
error("session_by_pid: unknown pid %d", pid); |
error("session_by_pid: unknown pid %ld", (long)pid); |
session_dump(); |
session_dump(); |
return NULL; |
return NULL; |
} |
} |
|
|
s->row = packet_get_int(); |
s->row = packet_get_int(); |
s->xpixel = packet_get_int(); |
s->xpixel = packet_get_int(); |
s->ypixel = packet_get_int(); |
s->ypixel = packet_get_int(); |
packet_done(); |
packet_check_eom(); |
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); |
return 1; |
return 1; |
} |
} |
|
|
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); |
|
|
packet_done(); |
packet_check_eom(); |
session_proctitle(s); |
session_proctitle(s); |
return 1; |
return 1; |
} |
} |
|
|
char *cmd, *subsys = packet_get_string(&len); |
char *cmd, *subsys = packet_get_string(&len); |
int i; |
int i; |
|
|
packet_done(); |
packet_check_eom(); |
log("subsystem request for %s", subsys); |
log("subsystem request for %.100s", subsys); |
|
|
for (i = 0; i < options.num_subsystems; i++) { |
for (i = 0; i < options.num_subsystems; i++) { |
if (strcmp(subsys, options.subsystem_name[i]) == 0) { |
if (strcmp(subsys, options.subsystem_name[i]) == 0) { |
|
|
s->is_subsystem = 1; |
s->is_subsystem = 1; |
do_exec(s, cmd); |
do_exec(s, cmd); |
success = 1; |
success = 1; |
|
break; |
} |
} |
} |
} |
|
|
if (!success) |
if (!success) |
log("subsystem request for %s failed, subsystem not found", |
log("subsystem request for %.100s failed, subsystem not found", |
subsys); |
subsys); |
|
|
xfree(subsys); |
xfree(subsys); |
|
|
s->auth_proto = packet_get_string(NULL); |
s->auth_proto = packet_get_string(NULL); |
s->auth_data = packet_get_string(NULL); |
s->auth_data = packet_get_string(NULL); |
s->screen = packet_get_int(); |
s->screen = packet_get_int(); |
packet_done(); |
packet_check_eom(); |
|
|
success = session_setup_x11fwd(s); |
success = session_setup_x11fwd(s); |
if (!success) { |
if (!success) { |
|
|
static int |
static int |
session_shell_req(Session *s) |
session_shell_req(Session *s) |
{ |
{ |
packet_done(); |
packet_check_eom(); |
do_exec(s, NULL); |
do_exec(s, NULL); |
return 1; |
return 1; |
} |
} |
|
|
{ |
{ |
u_int len; |
u_int len; |
char *command = packet_get_string(&len); |
char *command = packet_get_string(&len); |
packet_done(); |
packet_check_eom(); |
do_exec(s, command); |
do_exec(s, command); |
xfree(command); |
xfree(command); |
return 1; |
return 1; |
|
|
session_auth_agent_req(Session *s) |
session_auth_agent_req(Session *s) |
{ |
{ |
static int called = 0; |
static int called = 0; |
packet_done(); |
packet_check_eom(); |
if (no_agent_forwarding_flag) { |
if (no_agent_forwarding_flag) { |
debug("session_auth_agent_req: no_agent_forwarding_flag"); |
debug("session_auth_agent_req: no_agent_forwarding_flag"); |
return 0; |
return 0; |
|
|
} |
} |
} |
} |
|
|
void |
int |
session_input_channel_req(int id, void *arg) |
session_input_channel_req(Channel *c, const char *rtype) |
{ |
{ |
u_int len; |
|
int reply; |
|
int success = 0; |
int success = 0; |
char *rtype; |
|
Session *s; |
Session *s; |
Channel *c; |
|
|
|
rtype = packet_get_string(&len); |
if ((s = session_by_channel(c->self)) == NULL) { |
reply = packet_get_char(); |
log("session_input_channel_req: no session %d req %.100s", |
|
c->self, rtype); |
|
return 0; |
|
} |
|
debug("session_input_channel_req: session %d req %s", s->self, rtype); |
|
|
s = session_by_channel(id); |
|
if (s == NULL) |
|
fatal("session_input_channel_req: channel %d: no session", id); |
|
c = channel_lookup(id); |
|
if (c == NULL) |
|
fatal("session_input_channel_req: channel %d: bad channel", id); |
|
|
|
debug("session_input_channel_req: session %d channel %d request %s reply %d", |
|
s->self, id, rtype, reply); |
|
|
|
/* |
/* |
* a session is in LARVAL state until a shell, a command |
* a session is in LARVAL state until a shell, a command |
* or a subsystem is executed |
* or a subsystem is executed |
|
|
if (strcmp(rtype, "window-change") == 0) { |
if (strcmp(rtype, "window-change") == 0) { |
success = session_window_change_req(s); |
success = session_window_change_req(s); |
} |
} |
|
return success; |
if (reply) { |
|
packet_start(success ? |
|
SSH2_MSG_CHANNEL_SUCCESS : SSH2_MSG_CHANNEL_FAILURE); |
|
packet_put_int(c->remote_id); |
|
packet_send(); |
|
} |
|
xfree(rtype); |
|
} |
} |
|
|
void |
void |
|
|
channel_set_fds(s->chanid, |
channel_set_fds(s->chanid, |
fdout, fdin, fderr, |
fdout, fdin, fderr, |
fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, |
fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, |
1); |
1, |
|
CHAN_SES_WINDOW_DEFAULT); |
} |
} |
|
|
/* |
/* |
* 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) |
{ |
{ |
Channel *c; |
Channel *c; |
if (s == NULL) |
|
fatal("session_close: no session"); |
if ((c = channel_lookup(s->chanid)) == NULL) |
c = channel_lookup(s->chanid); |
|
if (c == NULL) |
|
fatal("session_exit_message: session %d: no channel %d", |
fatal("session_exit_message: session %d: no channel %d", |
s->self, s->chanid); |
s->self, s->chanid); |
debug("session_exit_message: session %d channel %d pid %d", |
debug("session_exit_message: session %d channel %d pid %ld", |
s->self, s->chanid, s->pid); |
s->self, s->chanid, (long)s->pid); |
|
|
if (WIFEXITED(status)) { |
if (WIFEXITED(status)) { |
channel_request_start(s->chanid, |
channel_request_start(s->chanid, "exit-status", 0); |
"exit-status", 0); |
|
packet_put_int(WEXITSTATUS(status)); |
packet_put_int(WEXITSTATUS(status)); |
packet_send(); |
packet_send(); |
} else if (WIFSIGNALED(status)) { |
} else if (WIFSIGNALED(status)) { |
channel_request_start(s->chanid, |
channel_request_start(s->chanid, "exit-signal", 0); |
"exit-signal", 0); |
|
packet_put_int(WTERMSIG(status)); |
packet_put_int(WTERMSIG(status)); |
packet_put_char(WCOREDUMP(status)); |
packet_put_char(WCOREDUMP(status)); |
packet_put_cstring(""); |
packet_put_cstring(""); |
|
|
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 %ld", s->self, (long)s->pid); |
if (s->ttyfd != -1) { |
if (s->ttyfd != -1) { |
fatal_remove_cleanup(session_pty_cleanup, (void *)s); |
fatal_remove_cleanup(session_pty_cleanup, (void *)s); |
session_pty_cleanup(s); |
session_pty_cleanup(s); |
|
|
xfree(s->term); |
xfree(s->term); |
if (s->display) |
if (s->display) |
xfree(s->display); |
xfree(s->display); |
|
if (s->auth_display) |
|
xfree(s->auth_display); |
if (s->auth_data) |
if (s->auth_data) |
xfree(s->auth_data); |
xfree(s->auth_data); |
if (s->auth_proto) |
if (s->auth_proto) |
|
|
{ |
{ |
Session *s = session_by_pid(pid); |
Session *s = session_by_pid(pid); |
if (s == NULL) { |
if (s == NULL) { |
debug("session_close_by_pid: no session for pid %d", pid); |
debug("session_close_by_pid: no session for pid %ld", |
|
(long)pid); |
return; |
return; |
} |
} |
if (s->chanid != -1) |
if (s->chanid != -1) |
|
|
debug("session_close_by_channel: no session for id %d", id); |
debug("session_close_by_channel: no session for id %d", id); |
return; |
return; |
} |
} |
debug("session_close_by_channel: channel %d child %d", id, s->pid); |
debug("session_close_by_channel: channel %d child %ld", |
|
id, (long)s->pid); |
if (s->pid != 0) { |
if (s->pid != 0) { |
debug("session_close_by_channel: channel %d: has child", id); |
debug("session_close_by_channel: channel %d: has child", id); |
/* |
/* |
|
|
} |
} |
|
|
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); |
|
} |
} |
} |
} |
} |
|
|
|
|
static char buf[1024]; |
static char buf[1024]; |
int i; |
int i; |
buf[0] = '\0'; |
buf[0] = '\0'; |
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 && s->ttyfd != -1) { |
if (s->used && s->ttyfd != -1) { |
if (buf[0] != '\0') |
if (buf[0] != '\0') |
|
|
session_setup_x11fwd(Session *s) |
session_setup_x11fwd(Session *s) |
{ |
{ |
struct stat st; |
struct stat st; |
|
char display[512], auth_display[512]; |
|
char hostname[MAXHOSTNAMELEN]; |
|
|
if (no_x11_forwarding_flag) { |
if (no_x11_forwarding_flag) { |
packet_send_debug("X11 forwarding disabled in user configuration file."); |
packet_send_debug("X11 forwarding disabled in user configuration file."); |
|
|
debug("X11 display already set."); |
debug("X11 display already set."); |
return 0; |
return 0; |
} |
} |
s->display = x11_create_display_inet(s->screen, options.x11_display_offset); |
s->display_number = x11_create_display_inet(options.x11_display_offset, |
if (s->display == NULL) { |
options.x11_use_localhost, s->single_connection); |
|
if (s->display_number == -1) { |
debug("x11_create_display_inet failed."); |
debug("x11_create_display_inet failed."); |
return 0; |
return 0; |
} |
} |
|
|
|
/* Set up a suitable value for the DISPLAY variable. */ |
|
if (gethostname(hostname, sizeof(hostname)) < 0) |
|
fatal("gethostname: %.100s", strerror(errno)); |
|
/* |
|
* auth_display must be used as the displayname when the |
|
* authorization entry is added with xauth(1). This will be |
|
* different than the DISPLAY string for localhost displays. |
|
*/ |
|
if (options.x11_use_localhost) { |
|
snprintf(display, sizeof display, "localhost:%d.%d", |
|
s->display_number, s->screen); |
|
snprintf(auth_display, sizeof auth_display, "unix:%d.%d", |
|
s->display_number, s->screen); |
|
s->display = xstrdup(display); |
|
s->auth_display = xstrdup(auth_display); |
|
} else { |
|
snprintf(display, sizeof display, "%.400s:%d.%d", hostname, |
|
s->display_number, s->screen); |
|
s->display = xstrdup(display); |
|
s->auth_display = xstrdup(display); |
|
} |
|
|
return 1; |
return 1; |
} |
} |
|
|