version 1.276, 2003/08/28 12:54:34 |
version 1.276.2.1, 2004/02/28 03:51:34 |
|
|
|
|
/* variables used for privilege separation */ |
/* variables used for privilege separation */ |
int use_privsep; |
int use_privsep; |
struct monitor *pmonitor; |
struct monitor *pmonitor = NULL; |
|
|
|
/* global authentication context */ |
|
Authctxt *the_authctxt = NULL; |
|
|
/* Prototypes for various functions defined later in this file. */ |
/* Prototypes for various functions defined later in this file. */ |
void destroy_sensitive_data(void); |
void destroy_sensitive_data(void); |
void demote_sensitive_data(void); |
void demote_sensitive_data(void); |
|
|
{ |
{ |
/* XXX no idea how fix this signal handler */ |
/* XXX no idea how fix this signal handler */ |
|
|
|
if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0) |
|
kill(pmonitor->m_pid, SIGALRM); |
|
|
/* Log error and exit. */ |
/* Log error and exit. */ |
fatal("Timeout before authentication for %s", get_remote_ipaddr()); |
fatal("Timeout before authentication for %s", get_remote_ipaddr()); |
} |
} |
|
|
strlen(server_version_string)) |
strlen(server_version_string)) |
!= strlen(server_version_string)) { |
!= strlen(server_version_string)) { |
logit("Could not write ident string to %s", get_remote_ipaddr()); |
logit("Could not write ident string to %s", get_remote_ipaddr()); |
fatal_cleanup(); |
cleanup_exit(255); |
} |
} |
|
|
/* Read other sides version identification. */ |
/* Read other sides version identification. */ |
|
|
if (atomicio(read, sock_in, &buf[i], 1) != 1) { |
if (atomicio(read, sock_in, &buf[i], 1) != 1) { |
logit("Did not receive identification string from %s", |
logit("Did not receive identification string from %s", |
get_remote_ipaddr()); |
get_remote_ipaddr()); |
fatal_cleanup(); |
cleanup_exit(255); |
} |
} |
if (buf[i] == '\r') { |
if (buf[i] == '\r') { |
buf[i] = 0; |
buf[i] = 0; |
|
|
close(sock_out); |
close(sock_out); |
logit("Bad protocol version identification '%.100s' from %s", |
logit("Bad protocol version identification '%.100s' from %s", |
client_version_string, get_remote_ipaddr()); |
client_version_string, get_remote_ipaddr()); |
fatal_cleanup(); |
cleanup_exit(255); |
} |
} |
debug("Client protocol version %d.%d; client software version %.100s", |
debug("Client protocol version %d.%d; client software version %.100s", |
remote_major, remote_minor, remote_version); |
remote_major, remote_minor, remote_version); |
|
|
if (datafellows & SSH_BUG_PROBE) { |
if (datafellows & SSH_BUG_PROBE) { |
logit("probed from %s with %s. Don't panic.", |
logit("probed from %s with %s. Don't panic.", |
get_remote_ipaddr(), client_version_string); |
get_remote_ipaddr(), client_version_string); |
fatal_cleanup(); |
cleanup_exit(255); |
} |
} |
|
|
if (datafellows & SSH_BUG_SCANNER) { |
if (datafellows & SSH_BUG_SCANNER) { |
logit("scanned from %s with %s. Don't panic.", |
logit("scanned from %s with %s. Don't panic.", |
get_remote_ipaddr(), client_version_string); |
get_remote_ipaddr(), client_version_string); |
fatal_cleanup(); |
cleanup_exit(255); |
} |
} |
|
|
mismatch = 0; |
mismatch = 0; |
|
|
logit("Protocol major versions differ for %s: %.200s vs. %.200s", |
logit("Protocol major versions differ for %s: %.200s vs. %.200s", |
get_remote_ipaddr(), |
get_remote_ipaddr(), |
server_version_string, client_version_string); |
server_version_string, client_version_string); |
fatal_cleanup(); |
cleanup_exit(255); |
} |
} |
} |
} |
|
|
|
|
#endif |
#endif |
} |
} |
|
|
static Authctxt * |
static int |
privsep_preauth(void) |
privsep_preauth(Authctxt *authctxt) |
{ |
{ |
Authctxt *authctxt = NULL; |
|
int status; |
int status; |
pid_t pid; |
pid_t pid; |
|
|
|
|
if (pid == -1) { |
if (pid == -1) { |
fatal("fork of unprivileged child failed"); |
fatal("fork of unprivileged child failed"); |
} else if (pid != 0) { |
} else if (pid != 0) { |
fatal_remove_cleanup((void (*) (void *)) packet_close, NULL); |
|
|
|
debug2("Network child is on pid %ld", (long)pid); |
debug2("Network child is on pid %ld", (long)pid); |
|
|
close(pmonitor->m_recvfd); |
close(pmonitor->m_recvfd); |
authctxt = monitor_child_preauth(pmonitor); |
pmonitor->m_pid = pid; |
|
monitor_child_preauth(authctxt, pmonitor); |
close(pmonitor->m_sendfd); |
close(pmonitor->m_sendfd); |
|
|
/* Sync memory */ |
/* Sync memory */ |
|
|
while (waitpid(pid, &status, 0) < 0) |
while (waitpid(pid, &status, 0) < 0) |
if (errno != EINTR) |
if (errno != EINTR) |
break; |
break; |
|
return (1); |
/* Reinstall, since the child has finished */ |
|
fatal_add_cleanup((void (*) (void *)) packet_close, NULL); |
|
|
|
return (authctxt); |
|
} else { |
} else { |
/* child */ |
/* child */ |
|
|
|
|
privsep_preauth_child(); |
privsep_preauth_child(); |
setproctitle("%s", "[net]"); |
setproctitle("%s", "[net]"); |
} |
} |
return (NULL); |
return (0); |
} |
} |
|
|
static void |
static void |
privsep_postauth(Authctxt *authctxt) |
privsep_postauth(Authctxt *authctxt) |
{ |
{ |
extern Authctxt *x_authctxt; |
|
|
|
/* XXX - Remote port forwarding */ |
|
x_authctxt = authctxt; |
|
|
|
if (authctxt->pw->pw_uid == 0 || options.use_login) { |
if (authctxt->pw->pw_uid == 0 || options.use_login) { |
/* File descriptor passing is broken or root login */ |
/* File descriptor passing is broken or root login */ |
monitor_apply_keystate(pmonitor); |
monitor_apply_keystate(pmonitor); |
|
|
if (pmonitor->m_pid == -1) |
if (pmonitor->m_pid == -1) |
fatal("fork of unprivileged child failed"); |
fatal("fork of unprivileged child failed"); |
else if (pmonitor->m_pid != 0) { |
else if (pmonitor->m_pid != 0) { |
fatal_remove_cleanup((void (*) (void *)) packet_close, NULL); |
|
|
|
debug2("User child is on pid %ld", (long)pmonitor->m_pid); |
debug2("User child is on pid %ld", (long)pmonitor->m_pid); |
close(pmonitor->m_recvfd); |
close(pmonitor->m_recvfd); |
monitor_child_postauth(pmonitor); |
monitor_child_postauth(pmonitor); |
|
|
list_hostkey_types(void) |
list_hostkey_types(void) |
{ |
{ |
Buffer b; |
Buffer b; |
char *p; |
const char *p; |
|
char *ret; |
int i; |
int i; |
|
|
buffer_init(&b); |
buffer_init(&b); |
|
|
} |
} |
} |
} |
buffer_append(&b, "\0", 1); |
buffer_append(&b, "\0", 1); |
p = xstrdup(buffer_ptr(&b)); |
ret = xstrdup(buffer_ptr(&b)); |
buffer_free(&b); |
buffer_free(&b); |
debug("list_hostkey_types: %s", p); |
debug("list_hostkey_types: %s", ret); |
return p; |
return ret; |
} |
} |
|
|
Key * |
Key * |
|
|
static void |
static void |
usage(void) |
usage(void) |
{ |
{ |
fprintf(stderr, "sshd version %s\n", SSH_VERSION); |
fprintf(stderr, "sshd version %s, %s\n", |
|
SSH_VERSION, SSLeay_version(SSLEAY_VERSION)); |
fprintf(stderr, "Usage: %s [options]\n", __progname); |
fprintf(stderr, "Usage: %s [options]\n", __progname); |
fprintf(stderr, "Options:\n"); |
fprintf(stderr, "Options:\n"); |
fprintf(stderr, " -f file Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE); |
fprintf(stderr, " -f file Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE); |
|
|
FILE *f; |
FILE *f; |
struct addrinfo *ai; |
struct addrinfo *ai; |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
char ntop[NI_MAXHOST], strport[NI_MAXSERV]; |
|
char *line; |
int listen_sock, maxfd; |
int listen_sock, maxfd; |
int startup_p[2]; |
int startup_p[2]; |
int startups = 0; |
int startups = 0; |
Authctxt *authctxt; |
|
Key *key; |
Key *key; |
|
Authctxt *authctxt; |
int ret, key_used = 0; |
int ret, key_used = 0; |
|
|
/* Save argv. */ |
/* Save argv. */ |
|
|
} |
} |
break; |
break; |
case 'o': |
case 'o': |
if (process_server_config_line(&options, optarg, |
line = xstrdup(optarg); |
|
if (process_server_config_line(&options, line, |
"command-line", 0) != 0) |
"command-line", 0) != 0) |
exit(1); |
exit(1); |
|
xfree(line); |
break; |
break; |
case '?': |
case '?': |
default: |
default: |
|
|
|
|
/* Start listening on the port. */ |
/* Start listening on the port. */ |
logit("Server listening on %s port %s.", ntop, strport); |
logit("Server listening on %s port %s.", ntop, strport); |
if (listen(listen_sock, 5) < 0) |
if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) |
fatal("listen: %.100s", strerror(errno)); |
fatal("listen: %.100s", strerror(errno)); |
|
|
} |
} |
|
|
signal(SIGQUIT, SIG_DFL); |
signal(SIGQUIT, SIG_DFL); |
signal(SIGCHLD, SIG_DFL); |
signal(SIGCHLD, SIG_DFL); |
|
|
/* Set keepalives if requested. */ |
/* Set SO_KEEPALIVE if requested. */ |
if (options.keepalives && |
if (options.tcp_keep_alive && |
setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, |
setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, |
sizeof(on)) < 0) |
sizeof(on)) < 0) |
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); |
error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); |
|
|
|
|
packet_set_nonblocking(); |
packet_set_nonblocking(); |
|
|
|
/* allocate authentication context */ |
|
authctxt = xmalloc(sizeof(*authctxt)); |
|
memset(authctxt, 0, sizeof(*authctxt)); |
|
|
|
/* XXX global for cleanup, access from other modules */ |
|
the_authctxt = authctxt; |
|
|
if (use_privsep) |
if (use_privsep) |
if ((authctxt = privsep_preauth()) != NULL) |
if (privsep_preauth(authctxt) == 1) |
goto authenticated; |
goto authenticated; |
|
|
/* perform the key exchange */ |
/* perform the key exchange */ |
/* authenticate user and start session */ |
/* authenticate user and start session */ |
if (compat20) { |
if (compat20) { |
do_ssh2_kex(); |
do_ssh2_kex(); |
authctxt = do_authentication2(); |
do_authentication2(authctxt); |
} else { |
} else { |
do_ssh1_kex(); |
do_ssh1_kex(); |
authctxt = do_authentication(); |
do_authentication(authctxt); |
} |
} |
/* |
/* |
* If we use privilege separation, the unprivileged child transfers |
* If we use privilege separation, the unprivileged child transfers |
|
|
destroy_sensitive_data(); |
destroy_sensitive_data(); |
} |
} |
|
|
/* Perform session preparation. */ |
/* Start session. */ |
do_authenticated(authctxt); |
do_authenticated(authctxt); |
|
|
/* The connection has been terminated. */ |
/* The connection has been terminated. */ |
|
|
packet_write_wait(); |
packet_write_wait(); |
#endif |
#endif |
debug("KEX done"); |
debug("KEX done"); |
|
} |
|
|
|
/* server specific fatal cleanup */ |
|
void |
|
cleanup_exit(int i) |
|
{ |
|
if (the_authctxt) |
|
do_cleanup(the_authctxt); |
|
_exit(i); |
} |
} |