version 1.134.2.3, 2003/04/03 22:35:17 |
version 1.135, 2002/05/16 22:09:59 |
|
|
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) |
{ |
{ |
setproctitle("%s", authctxt->pw->pw_name); |
|
|
|
/* |
/* |
* Cancel the alarm we set to limit the time taken for |
* Cancel the alarm we set to limit the time taken for |
* authentication. |
* authentication. |
|
|
do_authenticated1(authctxt); |
do_authenticated1(authctxt); |
|
|
/* remove agent socket */ |
/* remove agent socket */ |
if (auth_sock_name != NULL) |
if (auth_get_socket_name()) |
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, screen_flag; |
int success, type, screen_flag; |
int enable_compression_after_reply = 0; |
int compression_level = 0, enable_compression_after_reply = 0; |
u_int proto_len, data_len, dlen, compression_level = 0; |
u_int proto_len, data_len, dlen; |
|
|
s = session_new(); |
s = session_new(); |
s->authctxt = authctxt; |
s->authctxt = authctxt; |
|
|
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; |
|
|
void |
void |
do_exec_no_pty(Session *s, const char *command) |
do_exec_no_pty(Session *s, const char *command) |
{ |
{ |
pid_t pid; |
int pid; |
|
|
#ifdef USE_PIPES |
#ifdef USE_PIPES |
int pin[2], pout[2], perr[2]; |
int pin[2], pout[2], perr[2]; |
|
|
|
|
/* Fork the child. */ |
/* Fork the child. */ |
if ((pid = fork()) == 0) { |
if ((pid = fork()) == 0) { |
fatal_remove_all_cleanups(); |
|
|
|
/* Child. Reinitialize the log since the pid has changed. */ |
/* Child. Reinitialize the log since the pid has changed. */ |
log_init(__progname, options.log_level, options.log_facility, log_stderr); |
log_init(__progname, options.log_level, options.log_facility, log_stderr); |
|
|
|
|
|
|
/* Fork the child. */ |
/* Fork the child. */ |
if ((pid = fork()) == 0) { |
if ((pid = fork()) == 0) { |
fatal_remove_all_cleanups(); |
|
|
|
/* Child. Reinitialize the log because the pid has changed. */ |
/* Child. Reinitialize the log because the pid has changed. */ |
log_init(__progname, options.log_level, options.log_facility, log_stderr); |
log_init(__progname, options.log_level, options.log_facility, log_stderr); |
|
|
* the address be 0.0.0.0. |
* the address be 0.0.0.0. |
*/ |
*/ |
memset(&from, 0, sizeof(from)); |
memset(&from, 0, sizeof(from)); |
fromlen = sizeof(from); |
|
if (packet_connection_is_on_socket()) { |
if (packet_connection_is_on_socket()) { |
|
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)); |
|
|
record_login(pid, s->tty, pw->pw_name, pw->pw_uid, |
record_login(pid, s->tty, pw->pw_name, pw->pw_uid, |
get_remote_name_or_ip(utmp_len, |
get_remote_name_or_ip(utmp_len, |
options.verify_reverse_mapping), |
options.verify_reverse_mapping), |
(struct sockaddr *)&from, fromlen); |
(struct sockaddr *)&from); |
|
|
if (check_quietlogin(s, command)) |
if (check_quietlogin(s, command)) |
return; |
return; |
|
|
} else { |
} else { |
/* New variable. Expand if necessary. */ |
/* New variable. Expand if necessary. */ |
if (i >= (*envsizep) - 1) { |
if (i >= (*envsizep) - 1) { |
if (*envsizep >= 1000) |
|
fatal("child_set_env: too many env vars," |
|
" skipping: %.100s", name); |
|
(*envsizep) += 50; |
(*envsizep) += 50; |
env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *)); |
env = (*envp) = xrealloc(env, (*envsizep) * sizeof(char *)); |
} |
} |
|
|
FILE *f; |
FILE *f; |
char buf[4096]; |
char buf[4096]; |
char *cp, *value; |
char *cp, *value; |
u_int lineno = 0; |
|
|
|
f = fopen(filename, "r"); |
f = fopen(filename, "r"); |
if (!f) |
if (!f) |
return; |
return; |
|
|
while (fgets(buf, sizeof(buf), f)) { |
while (fgets(buf, sizeof(buf), f)) { |
if (++lineno > 1000) |
|
fatal("Too many lines in environment file %s", filename); |
|
for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) |
for (cp = buf; *cp == ' ' || *cp == '\t'; cp++) |
; |
; |
if (!*cp || *cp == '#' || *cp == '\n') |
if (!*cp || *cp == '#' || *cp == '\n') |
|
|
*strchr(cp, '\n') = '\0'; |
*strchr(cp, '\n') = '\0'; |
value = strchr(cp, '='); |
value = strchr(cp, '='); |
if (value == NULL) { |
if (value == NULL) { |
fprintf(stderr, "Bad line %u in %.100s\n", lineno, |
fprintf(stderr, "Bad line in %.100s: %.200s\n", filename, buf); |
filename); |
|
continue; |
continue; |
} |
} |
/* |
/* |
|
|
{ |
{ |
char buf[256]; |
char buf[256]; |
u_int i, envsize; |
u_int i, envsize; |
char **env, *laddr; |
char **env; |
struct passwd *pw = s->pw; |
struct passwd *pw = s->pw; |
|
|
/* Initialize the environment. */ |
/* Initialize the environment. */ |
|
|
child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); |
child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); |
child_set_env(&env, &envsize, "HOME", pw->pw_dir); |
child_set_env(&env, &envsize, "HOME", pw->pw_dir); |
#ifdef HAVE_LOGIN_CAP |
#ifdef HAVE_LOGIN_CAP |
if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0) |
(void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH); |
child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); |
child_set_env(&env, &envsize, "PATH", getenv("PATH")); |
else |
|
child_set_env(&env, &envsize, "PATH", getenv("PATH")); |
|
#else |
#else |
child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); |
child_set_env(&env, &envsize, "PATH", _PATH_STDPATH); |
#endif |
#endif |
|
|
if (!options.use_login) { |
if (!options.use_login) { |
while (custom_environment) { |
while (custom_environment) { |
struct envstring *ce = custom_environment; |
struct envstring *ce = custom_environment; |
char *str = ce->s; |
char *s = ce->s; |
|
|
for (i = 0; str[i] != '=' && str[i]; i++) |
for (i = 0; s[i] != '=' && s[i]; i++) |
; |
; |
if (str[i] == '=') { |
if (s[i] == '=') { |
str[i] = 0; |
s[i] = 0; |
child_set_env(&env, &envsize, str, str + i + 1); |
child_set_env(&env, &envsize, s, s + i + 1); |
} |
} |
custom_environment = ce->next; |
custom_environment = ce->next; |
xfree(ce->s); |
xfree(ce->s); |
|
|
} |
} |
} |
} |
|
|
/* SSH_CLIENT deprecated */ |
|
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); |
|
|
laddr = get_local_ipaddr(packet_get_connection_in()); |
|
snprintf(buf, sizeof buf, "%.50s %d %.50s %d", |
|
get_remote_ipaddr(), get_remote_port(), laddr, get_local_port()); |
|
xfree(laddr); |
|
child_set_env(&env, &envsize, "SSH_CONNECTION", buf); |
|
|
|
if (s->ttyfd != -1) |
if (s->ttyfd != -1) |
child_set_env(&env, &envsize, "SSH_TTY", s->tty); |
child_set_env(&env, &envsize, "SSH_TTY", s->tty); |
if (s->term) |
if (s->term) |
|
|
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_sock_name != NULL) |
if (auth_get_socket_name() != NULL) |
child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, |
child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME, |
auth_sock_name); |
auth_get_socket_name()); |
|
|
/* read $HOME/.ssh/environment. */ |
/* read $HOME/.ssh/environment. */ |
if (options.permit_user_env && !options.use_login) { |
if (!options.use_login) { |
snprintf(buf, sizeof buf, "%.200s/.ssh/environment", |
snprintf(buf, sizeof buf, "%.200s/.ssh/environment", |
pw->pw_dir); |
pw->pw_dir); |
read_environment_file(&env, &envsize, buf); |
read_environment_file(&env, &envsize, buf); |
|
|
/* Add authority data to .Xauthority if appropriate. */ |
/* Add authority data to .Xauthority if appropriate. */ |
if (debug_flag) { |
if (debug_flag) { |
fprintf(stderr, |
fprintf(stderr, |
"Running %.500s remove %.100s\n", |
"Running %.500s add " |
options.xauth_location, s->auth_display); |
"%.100s %.100s %.100s\n", |
fprintf(stderr, |
|
"%.500s add %.100s %.100s %.100s\n", |
|
options.xauth_location, s->auth_display, |
options.xauth_location, s->auth_display, |
s->auth_proto, s->auth_data); |
s->auth_proto, s->auth_data); |
} |
} |
|
|
options.xauth_location); |
options.xauth_location); |
f = popen(cmd, "w"); |
f = popen(cmd, "w"); |
if (f) { |
if (f) { |
fprintf(f, "remove %s\n", |
|
s->auth_display); |
|
fprintf(f, "add %s %s %s\n", |
fprintf(f, "add %s %s %s\n", |
s->auth_display, s->auth_proto, |
s->auth_display, s->auth_proto, |
s->auth_data); |
s->auth_data); |
|
|
#endif |
#endif |
if (f) { |
if (f) { |
/* /etc/nologin exists. Print its contents and exit. */ |
/* /etc/nologin exists. Print its contents and exit. */ |
log("User %.100s not allowed because %s exists", |
|
pw->pw_name, _PATH_NOLOGIN); |
|
while (fgets(buf, sizeof(buf), f)) |
while (fgets(buf, sizeof(buf), f)) |
fputs(buf, stderr); |
fputs(buf, stderr); |
fclose(f); |
fclose(f); |
|
|
* legal, and means /bin/sh. |
* legal, and means /bin/sh. |
*/ |
*/ |
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; |
shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; |
|
|
/* |
|
* Make sure $SHELL points to the shell from the password file, |
|
* even if shell is overridden from login.conf |
|
*/ |
|
env = do_setup_env(s, shell); |
|
|
|
#ifdef HAVE_LOGIN_CAP |
#ifdef HAVE_LOGIN_CAP |
shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); |
shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell); |
#endif |
#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, |
|
|
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 %ld", |
debug("dump: used %d session %d %p channel %d pid %d", |
s->used, |
s->used, |
s->self, |
s->self, |
s, |
s, |
s->chanid, |
s->chanid, |
(long)s->pid); |
s->pid); |
} |
} |
} |
} |
|
|
|
|
session_by_pid(pid_t pid) |
session_by_pid(pid_t pid) |
{ |
{ |
int i; |
int i; |
debug("session_by_pid: pid %ld", (long)pid); |
debug("session_by_pid: pid %d", 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 %ld", (long)pid); |
error("session_by_pid: unknown pid %d", pid); |
session_dump(); |
session_dump(); |
return NULL; |
return NULL; |
} |
} |
|
|
PRIVSEP(session_pty_cleanup2(session)); |
PRIVSEP(session_pty_cleanup2(session)); |
} |
} |
|
|
static char * |
|
sig2name(int sig) |
|
{ |
|
#define SSH_SIG(x) if (sig == SIG ## x) return #x |
|
SSH_SIG(ABRT); |
|
SSH_SIG(ALRM); |
|
SSH_SIG(FPE); |
|
SSH_SIG(HUP); |
|
SSH_SIG(ILL); |
|
SSH_SIG(INT); |
|
SSH_SIG(KILL); |
|
SSH_SIG(PIPE); |
|
SSH_SIG(QUIT); |
|
SSH_SIG(SEGV); |
|
SSH_SIG(TERM); |
|
SSH_SIG(USR1); |
|
SSH_SIG(USR2); |
|
#undef SSH_SIG |
|
return "SIG@openssh.com"; |
|
} |
|
|
|
static void |
static void |
session_exit_message(Session *s, int status) |
session_exit_message(Session *s, int status) |
{ |
{ |
|
|
if ((c = channel_lookup(s->chanid)) == NULL) |
if ((c = channel_lookup(s->chanid)) == 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 %ld", |
debug("session_exit_message: session %d channel %d pid %d", |
s->self, s->chanid, (long)s->pid); |
s->self, s->chanid, s->pid); |
|
|
if (WIFEXITED(status)) { |
if (WIFEXITED(status)) { |
channel_request_start(s->chanid, "exit-status", 0); |
channel_request_start(s->chanid, "exit-status", 0); |
|
|
packet_send(); |
packet_send(); |
} else if (WIFSIGNALED(status)) { |
} else if (WIFSIGNALED(status)) { |
channel_request_start(s->chanid, "exit-signal", 0); |
channel_request_start(s->chanid, "exit-signal", 0); |
packet_put_cstring(sig2name(WTERMSIG(status))); |
packet_put_int(WTERMSIG(status)); |
packet_put_char(WCOREDUMP(status)); |
packet_put_char(WCOREDUMP(status)); |
packet_put_cstring(""); |
packet_put_cstring(""); |
packet_put_cstring(""); |
packet_put_cstring(""); |
|
|
void |
void |
session_close(Session *s) |
session_close(Session *s) |
{ |
{ |
debug("session_close: session %d pid %ld", s->self, (long)s->pid); |
debug("session_close: session %d pid %d", s->self, 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); |
|
|
{ |
{ |
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 %ld", |
debug("session_close_by_pid: no session for pid %d", pid); |
(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 %ld", |
debug("session_close_by_channel: channel %d child %d", id, s->pid); |
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); |
/* |
/* |
|
|
debug("X11 display already set."); |
debug("X11 display already set."); |
return 0; |
return 0; |
} |
} |
if (x11_create_display_inet(options.x11_display_offset, |
s->display_number = x11_create_display_inet(options.x11_display_offset, |
options.x11_use_localhost, s->single_connection, |
options.x11_use_localhost, s->single_connection); |
&s->display_number) == -1) { |
if (s->display_number == -1) { |
debug("x11_create_display_inet failed."); |
debug("x11_create_display_inet failed."); |
return 0; |
return 0; |
} |
} |
|
|
* different than the DISPLAY string for localhost displays. |
* different than the DISPLAY string for localhost displays. |
*/ |
*/ |
if (options.x11_use_localhost) { |
if (options.x11_use_localhost) { |
snprintf(display, sizeof display, "localhost:%u.%u", |
snprintf(display, sizeof display, "localhost:%d.%d", |
s->display_number, s->screen); |
s->display_number, s->screen); |
snprintf(auth_display, sizeof auth_display, "unix:%u.%u", |
snprintf(auth_display, sizeof auth_display, "unix:%d.%d", |
s->display_number, s->screen); |
s->display_number, s->screen); |
s->display = xstrdup(display); |
s->display = xstrdup(display); |
s->auth_display = xstrdup(auth_display); |
s->auth_display = xstrdup(auth_display); |
} else { |
} else { |
snprintf(display, sizeof display, "%.400s:%u.%u", hostname, |
snprintf(display, sizeof display, "%.400s:%d.%d", hostname, |
s->display_number, s->screen); |
s->display_number, s->screen); |
s->display = xstrdup(display); |
s->display = xstrdup(display); |
s->auth_display = xstrdup(display); |
s->auth_display = xstrdup(display); |