server.c | server.c | |||
---|---|---|---|---|
skipping to change at line 30 | skipping to change at line 30 | |||
* the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |||
* MA 02111-1307, USA. | * MA 02111-1307, USA. | |||
*/ | */ | |||
/** | /** | |||
* \defgroup ssh_server SSH Server | * \defgroup ssh_server SSH Server | |||
* \addtogroup ssh_server | * \addtogroup ssh_server | |||
* @{ | * @{ | |||
*/ | */ | |||
#include "config.h" | ||||
#include <errno.h> | #include <errno.h> | |||
#include <fcntl.h> | #include <fcntl.h> | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <string.h> | #include <string.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <unistd.h> | ||||
#include "libssh/priv.h" | #include "libssh/priv.h" | |||
#include "libssh/libssh.h" | #include "libssh/libssh.h" | |||
#include "libssh/server.h" | #include "libssh/server.h" | |||
#include "libssh/ssh2.h" | #include "libssh/ssh2.h" | |||
#include "libssh/keyfiles.h" | ||||
#include "libssh/buffer.h" | ||||
#include "libssh/packet.h" | ||||
#include "libssh/socket.h" | ||||
#include "libssh/channels.h" | ||||
#include "libssh/session.h" | ||||
#include "libssh/misc.h" | ||||
#include "libssh/keys.h" | ||||
#include "libssh/dh.h" | ||||
#include "libssh/messages.h" | ||||
#ifdef _WIN32 | #ifdef _WIN32 | |||
#include <winsock2.h> | #include <winsock2.h> | |||
#define SOCKOPT_TYPE_ARG4 char | #define SOCKOPT_TYPE_ARG4 char | |||
/* We need to provide hstrerror. Not we can't call the parameter h_errno be cause it's #defined */ | /* We need to provide hstrerror. Not we can't call the parameter h_errno be cause it's #defined */ | |||
inline char *hstrerror(int h_errno_val) { | static char *hstrerror(int h_errno_val) { | |||
static char text[50] = {0}; | static char text[50] = {0}; | |||
snprintf(text, sizeof(text), "gethostbyname error %d\n", h_errno_val); | snprintf(text, sizeof(text), "gethostbyname error %d\n", h_errno_val); | |||
return text; | return text; | |||
} | } | |||
#else /* _WIN32 */ | #else /* _WIN32 */ | |||
#include <sys/socket.h> | #include <sys/socket.h> | |||
#include <netinet/in.h> | #include <netinet/in.h> | |||
#include <netdb.h> | #include <netdb.h> | |||
#define SOCKOPT_TYPE_ARG4 int | #define SOCKOPT_TYPE_ARG4 int | |||
#endif /* _WIN32 */ | #endif /* _WIN32 */ | |||
/* TODO FIXME: must use getaddrinfo */ | /* TODO FIXME: must use getaddrinfo */ | |||
static socket_t bind_socket(SSH_BIND *ssh_bind, const char *hostname, | static socket_t bind_socket(ssh_bind sshbind, const char *hostname, | |||
int port) { | int port) { | |||
struct sockaddr_in myaddr; | struct sockaddr_in myaddr; | |||
struct hostent *hp=NULL; | struct hostent *hp=NULL; | |||
socket_t s; | socket_t s; | |||
int opt = 1; | int opt = 1; | |||
s = socket(PF_INET, SOCK_STREAM, 0); | s = socket(PF_INET, SOCK_STREAM, 0); | |||
if (s < 0) { | if (s < 0) { | |||
ssh_set_error(ssh_bind, SSH_FATAL, "%s", strerror(errno)); | ssh_set_error(sshbind, SSH_FATAL, "%s", strerror(errno)); | |||
return -1; | return -1; | |||
} | } | |||
#ifdef HAVE_GETHOSTBYNAME | #ifdef HAVE_GETHOSTBYNAME | |||
hp = gethostbyname(hostname); | hp = gethostbyname(hostname); | |||
#endif | #endif | |||
if (hp == NULL) { | if (hp == NULL) { | |||
ssh_set_error(ssh_bind, SSH_FATAL, | ssh_set_error(sshbind, SSH_FATAL, | |||
"Resolving %s: %s", hostname, hstrerror(h_errno)); | "Resolving %s: %s", hostname, hstrerror(h_errno)); | |||
close(s); | close(s); | |||
return -1; | return -1; | |||
} | } | |||
memset(&myaddr, 0, sizeof(myaddr)); | memset(&myaddr, 0, sizeof(myaddr)); | |||
memcpy(&myaddr.sin_addr, hp->h_addr, hp->h_length); | memcpy(&myaddr.sin_addr, hp->h_addr, hp->h_length); | |||
myaddr.sin_family = hp->h_addrtype; | myaddr.sin_family = hp->h_addrtype; | |||
myaddr.sin_port = htons(port); | myaddr.sin_port = htons(port); | |||
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) { | if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) { | |||
ssh_set_error(ssh_bind, SSH_FATAL, | ssh_set_error(sshbind, SSH_FATAL, | |||
"Setting socket options failed: %s", hstrerror(h_errno)); | "Setting socket options failed: %s", hstrerror(h_errno)); | |||
close(s); | close(s); | |||
return -1; | return -1; | |||
} | } | |||
if (bind(s, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0) { | if (bind(s, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0) { | |||
ssh_set_error(ssh_bind, SSH_FATAL, "Binding to %s:%d: %s", | ssh_set_error(sshbind, SSH_FATAL, "Binding to %s:%d: %s", | |||
hostname, | hostname, | |||
port, | port, | |||
strerror(errno)); | strerror(errno)); | |||
close(s); | close(s); | |||
return -1; | return -1; | |||
} | } | |||
return s; | return s; | |||
} | } | |||
SSH_BIND *ssh_bind_new(void) { | ssh_bind ssh_bind_new(void) { | |||
SSH_BIND *ptr; | ssh_bind ptr; | |||
ptr = malloc(sizeof(SSH_BIND)); | ptr = malloc(sizeof(struct ssh_bind_struct)); | |||
if (ptr == NULL) { | if (ptr == NULL) { | |||
return NULL; | return NULL; | |||
} | } | |||
ZERO_STRUCTP(ptr); | ZERO_STRUCTP(ptr); | |||
ptr->bindfd = -1; | ptr->bindfd = -1; | |||
ptr->bindport= 22; | ||||
ptr->log_verbosity = 0; | ||||
return ptr; | return ptr; | |||
} | } | |||
void ssh_bind_set_options(SSH_BIND *ssh_bind, SSH_OPTIONS *options) { | int ssh_bind_listen(ssh_bind sshbind) { | |||
ssh_bind->options = options; | ||||
} | ||||
int ssh_bind_listen(SSH_BIND *ssh_bind) { | ||||
const char *host; | const char *host; | |||
int fd; | int fd; | |||
if (ssh_bind->options == NULL) { | ||||
return -1; | ||||
} | ||||
if (ssh_init() < 0) { | if (ssh_init() < 0) { | |||
return -1; | return -1; | |||
} | } | |||
host = ssh_bind->options->bindaddr; | host = sshbind->bindaddr; | |||
if (host == NULL) { | if (host == NULL) { | |||
host = "0.0.0.0"; | host = "0.0.0.0"; | |||
} | } | |||
fd = bind_socket(ssh_bind, host, ssh_bind->options->bindport); | fd = bind_socket(sshbind, host, sshbind->bindport); | |||
if (fd < 0) { | if (fd < 0) { | |||
return -1; | return -1; | |||
} | } | |||
ssh_bind->bindfd = fd; | sshbind->bindfd = fd; | |||
if (listen(fd, 10) < 0) { | if (listen(fd, 10) < 0) { | |||
ssh_set_error(ssh_bind, SSH_FATAL, | ssh_set_error(sshbind, SSH_FATAL, | |||
"Listening to socket %d: %s", | "Listening to socket %d: %s", | |||
fd, strerror(errno)); | fd, strerror(errno)); | |||
close(fd); | close(fd); | |||
return -1; | return -1; | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
void ssh_bind_set_blocking(SSH_BIND *ssh_bind, int blocking) { | void ssh_bind_set_blocking(ssh_bind sshbind, int blocking) { | |||
ssh_bind->blocking = blocking ? 1 : 0; | sshbind->blocking = blocking ? 1 : 0; | |||
} | } | |||
socket_t ssh_bind_get_fd(SSH_BIND *ssh_bind) { | socket_t ssh_bind_get_fd(ssh_bind sshbind) { | |||
return ssh_bind->bindfd; | return sshbind->bindfd; | |||
} | } | |||
void ssh_bind_set_fd(SSH_BIND *ssh_bind, socket_t fd) { | void ssh_bind_set_fd(ssh_bind sshbind, socket_t fd) { | |||
ssh_bind->bindfd = fd; | sshbind->bindfd = fd; | |||
} | } | |||
void ssh_bind_fd_toaccept(SSH_BIND *ssh_bind) { | void ssh_bind_fd_toaccept(ssh_bind sshbind) { | |||
ssh_bind->toaccept = 1; | sshbind->toaccept = 1; | |||
} | } | |||
SSH_SESSION *ssh_bind_accept(SSH_BIND *ssh_bind) { | int ssh_bind_accept(ssh_bind sshbind, ssh_session session) { | |||
SSH_SESSION *session; | ssh_private_key dsa = NULL; | |||
PRIVATE_KEY *dsa = NULL; | ssh_private_key rsa = NULL; | |||
PRIVATE_KEY *rsa = NULL; | ||||
int fd = -1; | int fd = -1; | |||
int i; | ||||
if (ssh_bind->bindfd < 0) { | if (sshbind->bindfd < 0) { | |||
ssh_set_error(ssh_bind, SSH_FATAL, | ssh_set_error(sshbind, SSH_FATAL, | |||
"Can't accept new clients on a not bound socket."); | "Can't accept new clients on a not bound socket."); | |||
return NULL; | return SSH_ERROR; | |||
} | } | |||
if(session == NULL){ | ||||
if (ssh_bind->options->dsakey == NULL || ssh_bind->options->rsakey == NUL | ssh_set_error(sshbind, SSH_FATAL,"session is null"); | |||
L) { | return SSH_ERROR; | |||
ssh_set_error(ssh_bind, SSH_FATAL, | } | |||
if (sshbind->dsakey == NULL && sshbind->rsakey == NULL) { | ||||
ssh_set_error(sshbind, SSH_FATAL, | ||||
"DSA or RSA host key file must be set before accept()"); | "DSA or RSA host key file must be set before accept()"); | |||
return NULL; | return SSH_ERROR; | |||
} | } | |||
if (ssh_bind->options->dsakey) { | if (sshbind->dsakey) { | |||
dsa = _privatekey_from_file(ssh_bind, ssh_bind->options->dsakey, TYPE_D | dsa = _privatekey_from_file(sshbind, sshbind->dsakey, TYPE_DSS); | |||
SS); | ||||
if (dsa == NULL) { | if (dsa == NULL) { | |||
return NULL; | return SSH_ERROR; | |||
} | } | |||
} | } | |||
if (ssh_bind->options->rsakey) { | if (sshbind->rsakey) { | |||
rsa = _privatekey_from_file(ssh_bind, ssh_bind->options->rsakey, TYPE_R | rsa = _privatekey_from_file(sshbind, sshbind->rsakey, TYPE_RSA); | |||
SA); | ||||
if (rsa == NULL) { | if (rsa == NULL) { | |||
privatekey_free(dsa); | privatekey_free(dsa); | |||
return NULL; | return SSH_ERROR; | |||
} | } | |||
} | } | |||
fd = accept(ssh_bind->bindfd, NULL, NULL); | fd = accept(sshbind->bindfd, NULL, NULL); | |||
if (fd < 0) { | if (fd < 0) { | |||
ssh_set_error(ssh_bind, SSH_FATAL, | ssh_set_error(sshbind, SSH_FATAL, | |||
"Accepting a new connection: %s", | "Accepting a new connection: %s", | |||
strerror(errno)); | strerror(errno)); | |||
privatekey_free(dsa); | privatekey_free(dsa); | |||
privatekey_free(rsa); | privatekey_free(rsa); | |||
return NULL; | return SSH_ERROR; | |||
} | } | |||
session = ssh_new(); | ||||
if (session == NULL) { | ||||
ssh_set_error(ssh_bind, SSH_FATAL, "Not enough space"); | ||||
privatekey_free(dsa); | ||||
privatekey_free(rsa); | ||||
return NULL; | ||||
} | ||||
session->server = 1; | session->server = 1; | |||
session->version = 2; | session->version = 2; | |||
session->options = ssh_options_copy(ssh_bind->options); | ||||
if (session->options == NULL) { | /* copy options */ | |||
ssh_set_error(ssh_bind, SSH_FATAL, "No space left"); | for (i = 0; i < 10; ++i) { | |||
privatekey_free(dsa); | if (sshbind->wanted_methods[i]) { | |||
privatekey_free(rsa); | session->wanted_methods[i] = strdup(sshbind->wanted_methods[i]); | |||
ssh_cleanup(session); | if (session->wanted_methods[i] == NULL) { | |||
return NULL; | privatekey_free(dsa); | |||
privatekey_free(rsa); | ||||
return SSH_ERROR; | ||||
} | ||||
} | ||||
} | ||||
if (sshbind->bindaddr == NULL) | ||||
session->bindaddr = NULL; | ||||
else { | ||||
session->bindaddr = strdup(sshbind->bindaddr); | ||||
if (session->bindaddr == NULL) { | ||||
privatekey_free(dsa); | ||||
privatekey_free(rsa); | ||||
return SSH_ERROR; | ||||
} | ||||
} | } | |||
session->log_verbosity = sshbind->log_verbosity; | ||||
ssh_socket_free(session->socket); | ssh_socket_free(session->socket); | |||
session->socket = ssh_socket_new(session); | session->socket = ssh_socket_new(session); | |||
if (session->socket == NULL) { | if (session->socket == NULL) { | |||
privatekey_free(dsa); | privatekey_free(dsa); | |||
privatekey_free(rsa); | privatekey_free(rsa); | |||
ssh_cleanup(session); | return SSH_ERROR; | |||
return NULL; | ||||
} | } | |||
ssh_socket_set_fd(session->socket,fd); | ssh_socket_set_fd(session->socket, fd); | |||
session->dsa_key = dsa; | session->dsa_key = dsa; | |||
session->rsa_key = rsa; | session->rsa_key = rsa; | |||
return session; | return SSH_OK; | |||
} | } | |||
void ssh_bind_free(SSH_BIND *ssh_bind){ | void ssh_bind_free(ssh_bind sshbind){ | |||
if (ssh_bind == NULL) { | int i; | |||
if (sshbind == NULL) { | ||||
return; | return; | |||
} | } | |||
if (ssh_bind->bindfd >= 0) { | if (sshbind->bindfd >= 0) { | |||
close(ssh_bind->bindfd); | close(sshbind->bindfd); | |||
} | } | |||
ssh_bind->bindfd = -1; | sshbind->bindfd = -1; | |||
if (ssh_bind->options) { | ||||
ssh_options_free(ssh_bind->options); | /* options */ | |||
SAFE_FREE(sshbind->banner); | ||||
SAFE_FREE(sshbind->dsakey); | ||||
SAFE_FREE(sshbind->rsakey); | ||||
SAFE_FREE(sshbind->bindaddr); | ||||
for (i = 0; i < 10; i++) { | ||||
if (sshbind->wanted_methods[i]) { | ||||
SAFE_FREE(sshbind->wanted_methods[i]); | ||||
} | ||||
} | } | |||
SAFE_FREE(ssh_bind); | ||||
SAFE_FREE(sshbind); | ||||
} | } | |||
extern char *supported_methods[]; | extern char *supported_methods[]; | |||
/** @internal | ||||
* This functions sets the Key Exchange protocols to be accepted | ||||
* by the server. They depend on | ||||
* -What the user asked (via options) | ||||
* -What is available (keys) | ||||
* It should then accept the intersection of what the user asked | ||||
* and what is available, and return an error if nothing matches | ||||
*/ | ||||
static int server_set_kex(SSH_SESSION * session) { | static int server_set_kex(ssh_session session) { | |||
KEX *server = &session->server_kex; | KEX *server = &session->server_kex; | |||
SSH_OPTIONS *options = session->options; | ||||
int i, j; | int i, j; | |||
char *wanted; | char *wanted; | |||
ZERO_STRUCTP(server); | ZERO_STRUCTP(server); | |||
/* | ssh_get_random(server->cookie, 16, 0); | |||
* The program might ask for a specific cookie to be sent. Useful for ser | ||||
ver | ||||
* debugging | ||||
*/ | ||||
if (options->wanted_cookie) { | ||||
memcpy(server->cookie, options->wanted_cookie, 16); | ||||
} else { | ||||
ssh_get_random(server->cookie, 16, 0); | ||||
} | ||||
if (session->dsa_key != NULL && session->rsa_key != NULL) { | if (session->dsa_key != NULL && session->rsa_key != NULL) { | |||
if (ssh_options_set_wanted_algos(options, SSH_HOSTKEYS, | if (ssh_options_set_algo(session, SSH_HOSTKEYS, | |||
"ssh-dss,ssh-rsa") < 0) { | "ssh-dss,ssh-rsa") < 0) { | |||
return -1; | return -1; | |||
} | } | |||
} else if (session->dsa_key != NULL) { | } else if (session->dsa_key != NULL) { | |||
if (ssh_options_set_wanted_algos(options, SSH_HOSTKEYS, "ssh-dss") < 0) { | if (ssh_options_set_algo(session, SSH_HOSTKEYS, "ssh-dss") < 0) { | |||
return -1; | return -1; | |||
} | } | |||
} else { | } else { | |||
if (ssh_options_set_wanted_algos(options, SSH_HOSTKEYS, "ssh-rsa") < 0) { | if (ssh_options_set_algo(session, SSH_HOSTKEYS, "ssh-rsa") < 0) { | |||
return -1; | return -1; | |||
} | } | |||
} | } | |||
server->methods = malloc(10 * sizeof(char **)); | server->methods = malloc(10 * sizeof(char **)); | |||
if (server->methods == NULL) { | if (server->methods == NULL) { | |||
return -1; | return -1; | |||
} | } | |||
for (i = 0; i < 10; i++) { | for (i = 0; i < 10; i++) { | |||
if ((wanted = options->wanted_methods[i]) == NULL) { | if ((wanted = session->wanted_methods[i]) == NULL) { | |||
wanted = supported_methods[i]; | wanted = supported_methods[i]; | |||
} | } | |||
server->methods[i] = strdup(wanted); | server->methods[i] = strdup(wanted); | |||
if (server->methods[i] == NULL) { | if (server->methods[i] == NULL) { | |||
for (j = i - 1; j <= 0; j--) { | for (j = i - 1; j <= 0; j--) { | |||
SAFE_FREE(server->methods[j]); | SAFE_FREE(server->methods[j]); | |||
} | } | |||
SAFE_FREE(server->methods); | SAFE_FREE(server->methods); | |||
return -1; | return -1; | |||
} | } | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
static int dh_handshake_server(SSH_SESSION *session) { | static int dh_handshake_server(ssh_session session) { | |||
STRING *e; | ssh_string e; | |||
STRING *f; | ssh_string f; | |||
STRING *pubkey; | ssh_string pubkey; | |||
STRING *sign; | ssh_string sign; | |||
PUBLIC_KEY *pub; | ssh_public_key pub; | |||
PRIVATE_KEY *prv; | ssh_private_key prv; | |||
if (packet_wait(session, SSH2_MSG_KEXDH_INIT, 1) != SSH_OK) { | if (packet_wait(session, SSH2_MSG_KEXDH_INIT, 1) != SSH_OK) { | |||
return -1; | return -1; | |||
} | } | |||
e = buffer_get_ssh_string(session->in_buffer); | e = buffer_get_ssh_string(session->in_buffer); | |||
if (e == NULL) { | if (e == NULL) { | |||
ssh_set_error(session, SSH_FATAL, "No e number in client request"); | ssh_set_error(session, SSH_FATAL, "No e number in client request"); | |||
return -1; | return -1; | |||
} | } | |||
skipping to change at line 477 | skipping to change at line 504 | |||
session->current_crypto = session->next_crypto; | session->current_crypto = session->next_crypto; | |||
session->next_crypto = crypto_new(); | session->next_crypto = crypto_new(); | |||
if (session->next_crypto == NULL) { | if (session->next_crypto == NULL) { | |||
return -1; | return -1; | |||
} | } | |||
return 0; | return 0; | |||
} | } | |||
/* Do the banner and key exchange */ | /* Do the banner and key exchange */ | |||
int ssh_accept(SSH_SESSION *session) { | int ssh_accept(ssh_session session) { | |||
if (ssh_send_banner(session, 1) < 0) { | if (ssh_send_banner(session, 1) < 0) { | |||
return -1; | return -1; | |||
} | } | |||
session->alive = 1; | session->alive = 1; | |||
session->clientbanner = ssh_get_banner(session); | session->clientbanner = ssh_get_banner(session); | |||
if (session->clientbanner == NULL) { | if (session->clientbanner == NULL) { | |||
return -1; | return -1; | |||
} | } | |||
skipping to change at line 513 | skipping to change at line 540 | |||
if (dh_handshake_server(session) < 0) { | if (dh_handshake_server(session) < 0) { | |||
return -1; | return -1; | |||
} | } | |||
session->connected = 1; | session->connected = 1; | |||
return 0; | return 0; | |||
} | } | |||
/** | ||||
* @brief Blocking write on channel for stderr. | ||||
* | ||||
* @param channel The channel to write to. | ||||
* | ||||
* @param data A pointer to the data to write. | ||||
* | ||||
* @param len The length of the buffer to write to. | ||||
* | ||||
* @return The number of bytes written, SSH_ERROR on error. | ||||
* | ||||
* @see channel_read() | ||||
*/ | ||||
int channel_write_stderr(ssh_channel channel, const void *data, uint32_t le | ||||
n) { | ||||
return channel_write_common(channel, data, len, 1); | ||||
} | ||||
/* messages */ | ||||
static int ssh_message_auth_reply_default(ssh_message msg,int partial) { | ||||
ssh_session session = msg->session; | ||||
char methods_c[128] = {0}; | ||||
ssh_string methods = NULL; | ||||
int rc = SSH_ERROR; | ||||
enter_function(); | ||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_USERAUTH_FAILURE) < 0) { | ||||
return rc; | ||||
} | ||||
if (session->auth_methods == 0) { | ||||
session->auth_methods = SSH_AUTH_METHOD_PUBLICKEY | SSH_AUTH_METHOD_PAS | ||||
SWORD; | ||||
} | ||||
if (session->auth_methods & SSH_AUTH_METHOD_PUBLICKEY) { | ||||
strcat(methods_c, "publickey,"); | ||||
} | ||||
if (session->auth_methods & SSH_AUTH_METHOD_INTERACTIVE) { | ||||
strcat(methods_c, "keyboard-interactive,"); | ||||
} | ||||
if (session->auth_methods & SSH_AUTH_METHOD_PASSWORD) { | ||||
strcat(methods_c, "password,"); | ||||
} | ||||
if (session->auth_methods & SSH_AUTH_METHOD_HOSTBASED) { | ||||
strcat(methods_c, "hostbased,"); | ||||
} | ||||
/* Strip the comma. */ | ||||
methods_c[strlen(methods_c) - 1] = '\0'; // strip the comma. We are sure | ||||
there is at | ||||
ssh_log(session, SSH_LOG_PACKET, | ||||
"Sending a auth failure. methods that can continue: %s", methods_c); | ||||
methods = string_from_char(methods_c); | ||||
if (methods == NULL) { | ||||
goto error; | ||||
} | ||||
if (buffer_add_ssh_string(msg->session->out_buffer, methods) < 0) { | ||||
goto error; | ||||
} | ||||
if (partial) { | ||||
if (buffer_add_u8(session->out_buffer, 1) < 0) { | ||||
goto error; | ||||
} | ||||
} else { | ||||
if (buffer_add_u8(session->out_buffer, 0) < 0) { | ||||
goto error; | ||||
} | ||||
} | ||||
rc = packet_send(msg->session); | ||||
error: | ||||
string_free(methods); | ||||
leave_function(); | ||||
return rc; | ||||
} | ||||
static int ssh_message_channel_request_open_reply_default(ssh_message msg) | ||||
{ | ||||
ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Refusing a channel"); | ||||
if (buffer_add_u8(msg->session->out_buffer | ||||
, SSH2_MSG_CHANNEL_OPEN_FAILURE) < 0) { | ||||
goto error; | ||||
} | ||||
if (buffer_add_u32(msg->session->out_buffer, | ||||
htonl(msg->channel_request_open.sender)) < 0) { | ||||
goto error; | ||||
} | ||||
if (buffer_add_u32(msg->session->out_buffer, | ||||
htonl(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED)) < 0) { | ||||
goto error; | ||||
} | ||||
/* reason is an empty string */ | ||||
if (buffer_add_u32(msg->session->out_buffer, 0) < 0) { | ||||
goto error; | ||||
} | ||||
/* language too */ | ||||
if (buffer_add_u32(msg->session->out_buffer, 0) < 0) { | ||||
goto error; | ||||
} | ||||
return packet_send(msg->session); | ||||
error: | ||||
return SSH_ERROR; | ||||
} | ||||
static int ssh_message_channel_request_reply_default(ssh_message msg) { | ||||
uint32_t channel; | ||||
if (msg->channel_request.want_reply) { | ||||
channel = msg->channel_request.channel->remote_channel; | ||||
ssh_log(msg->session, SSH_LOG_PACKET, | ||||
"Sending a default channel_request denied to channel %d", channel); | ||||
if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_CHANNEL_FAILURE) < | ||||
0) { | ||||
return SSH_ERROR; | ||||
} | ||||
if (buffer_add_u32(msg->session->out_buffer, htonl(channel)) < 0) { | ||||
return SSH_ERROR; | ||||
} | ||||
return packet_send(msg->session); | ||||
} | ||||
ssh_log(msg->session, SSH_LOG_PACKET, | ||||
"The client doesn't want to know the request failed!"); | ||||
return SSH_OK; | ||||
} | ||||
static int ssh_message_service_request_reply_default(ssh_message msg) { | ||||
/* The only return code accepted by specifications are success or disconn | ||||
ect */ | ||||
return ssh_message_service_reply_success(msg); | ||||
} | ||||
int ssh_message_service_reply_success(ssh_message msg) { | ||||
struct ssh_string_struct *service; | ||||
ssh_session session=msg->session; | ||||
if (msg == NULL) { | ||||
return SSH_ERROR; | ||||
} | ||||
ssh_log(session, SSH_LOG_PACKET, | ||||
"Sending a SERVICE_ACCEPT for service %s", msg->service_request.servi | ||||
ce); | ||||
if (buffer_add_u8(session->out_buffer, SSH2_MSG_SERVICE_ACCEPT) < 0) { | ||||
return -1; | ||||
} | ||||
service=string_from_char(msg->service_request.service); | ||||
if (buffer_add_ssh_string(session->out_buffer, service) < 0) { | ||||
string_free(service); | ||||
return -1; | ||||
} | ||||
string_free(service); | ||||
return packet_send(msg->session); | ||||
} | ||||
int ssh_message_reply_default(ssh_message msg) { | ||||
if (msg == NULL) { | ||||
return -1; | ||||
} | ||||
switch(msg->type) { | ||||
case SSH_REQUEST_AUTH: | ||||
return ssh_message_auth_reply_default(msg, 0); | ||||
case SSH_REQUEST_CHANNEL_OPEN: | ||||
return ssh_message_channel_request_open_reply_default(msg); | ||||
case SSH_REQUEST_CHANNEL: | ||||
return ssh_message_channel_request_reply_default(msg); | ||||
case SSH_REQUEST_SERVICE: | ||||
return ssh_message_service_request_reply_default(msg); | ||||
default: | ||||
ssh_log(msg->session, SSH_LOG_PACKET, | ||||
"Don't know what to default reply to %d type", | ||||
msg->type); | ||||
break; | ||||
} | ||||
return -1; | ||||
} | ||||
char *ssh_message_service_service(ssh_message msg){ | ||||
if (msg == NULL) { | ||||
return NULL; | ||||
} | ||||
return msg->service_request.service; | ||||
} | ||||
char *ssh_message_auth_user(ssh_message msg) { | ||||
if (msg == NULL) { | ||||
return NULL; | ||||
} | ||||
return msg->auth_request.username; | ||||
} | ||||
char *ssh_message_auth_password(ssh_message msg){ | ||||
if (msg == NULL) { | ||||
return NULL; | ||||
} | ||||
return msg->auth_request.password; | ||||
} | ||||
/* Get the publickey of an auth request */ | ||||
ssh_public_key ssh_message_auth_publickey(ssh_message msg){ | ||||
if (msg == NULL) { | ||||
return NULL; | ||||
} | ||||
return msg->auth_request.public_key; | ||||
} | ||||
int ssh_message_auth_set_methods(ssh_message msg, int methods) { | ||||
if (msg == NULL || msg->session == NULL) { | ||||
return -1; | ||||
} | ||||
msg->session->auth_methods = methods; | ||||
return 0; | ||||
} | ||||
int ssh_message_auth_reply_success(ssh_message msg, int partial) { | ||||
if (msg == NULL) { | ||||
return SSH_ERROR; | ||||
} | ||||
if (partial) { | ||||
return ssh_message_auth_reply_default(msg, partial); | ||||
} | ||||
if (buffer_add_u8(msg->session->out_buffer,SSH2_MSG_USERAUTH_SUCCESS) < 0 | ||||
) { | ||||
return SSH_ERROR; | ||||
} | ||||
return packet_send(msg->session); | ||||
} | ||||
/* Answer OK to a pubkey auth request */ | ||||
int ssh_message_auth_reply_pk_ok(ssh_message msg, ssh_string algo, ssh_stri | ||||
ng pubkey) { | ||||
if (msg == NULL) { | ||||
return SSH_ERROR; | ||||
} | ||||
if (buffer_add_u8(msg->session->out_buffer, SSH2_MSG_USERAUTH_PK_OK) < 0 | ||||
|| | ||||
buffer_add_ssh_string(msg->session->out_buffer, algo) < 0 || | ||||
buffer_add_ssh_string(msg->session->out_buffer, pubkey) < 0) { | ||||
return SSH_ERROR; | ||||
} | ||||
return packet_send(msg->session); | ||||
} | ||||
char *ssh_message_channel_request_open_originator(ssh_message msg){ | ||||
return msg->channel_request_open.originator; | ||||
} | ||||
int ssh_message_channel_request_open_originator_port(ssh_message msg){ | ||||
return msg->channel_request_open.originator_port; | ||||
} | ||||
char *ssh_message_channel_request_open_destination(ssh_message msg){ | ||||
return msg->channel_request_open.destination; | ||||
} | ||||
int ssh_message_channel_request_open_destination_port(ssh_message msg){ | ||||
return msg->channel_request_open.destination_port; | ||||
} | ||||
ssh_channel ssh_message_channel_request_channel(ssh_message msg){ | ||||
return msg->channel_request.channel; | ||||
} | ||||
char *ssh_message_channel_request_pty_term(ssh_message msg){ | ||||
return msg->channel_request.TERM; | ||||
} | ||||
int ssh_message_channel_request_pty_width(ssh_message msg){ | ||||
return msg->channel_request.width; | ||||
} | ||||
int ssh_message_channel_request_pty_height(ssh_message msg){ | ||||
return msg->channel_request.height; | ||||
} | ||||
int ssh_message_channel_request_pty_pxwidth(ssh_message msg){ | ||||
return msg->channel_request.pxwidth; | ||||
} | ||||
int ssh_message_channel_request_pty_pxheight(ssh_message msg){ | ||||
return msg->channel_request.pxheight; | ||||
} | ||||
char *ssh_message_channel_request_env_name(ssh_message msg){ | ||||
return msg->channel_request.var_name; | ||||
} | ||||
char *ssh_message_channel_request_env_value(ssh_message msg){ | ||||
return msg->channel_request.var_value; | ||||
} | ||||
char *ssh_message_channel_request_command(ssh_message msg){ | ||||
return msg->channel_request.command; | ||||
} | ||||
char *ssh_message_channel_request_subsystem(ssh_message msg){ | ||||
return msg->channel_request.subsystem; | ||||
} | ||||
/** @brief defines the SSH_MESSAGE callback | ||||
* @param session the current ssh session | ||||
* @param ssh_message_callback a function pointer to a callback taking the | ||||
* current ssh session and received message as parameters. the function ret | ||||
urns | ||||
* 0 if the message has been parsed and treated sucessfuly, 1 otherwise (li | ||||
bssh | ||||
* must take care of the response). | ||||
*/ | ||||
void ssh_set_message_callback(ssh_session session, | ||||
int(*ssh_message_callback)(ssh_session session, ssh_message msg)){ | ||||
session->ssh_message_callback=ssh_message_callback; | ||||
} | ||||
int ssh_execute_message_callbacks(ssh_session session){ | ||||
ssh_message msg=NULL; | ||||
int ret; | ||||
if(!session->ssh_message_list) | ||||
return SSH_OK; | ||||
if(session->ssh_message_callback){ | ||||
while((msg=ssh_list_get_head(ssh_message , session->ssh_message_list)) | ||||
!= NULL){ | ||||
ret=session->ssh_message_callback(session,msg); | ||||
if(ret==1){ | ||||
ret = ssh_message_reply_default(msg); | ||||
if(ret != SSH_OK) | ||||
return ret; | ||||
} | ||||
} | ||||
} else { | ||||
while((msg=ssh_list_get_head(ssh_message , session->ssh_message_list)) | ||||
!= NULL){ | ||||
ret = ssh_message_reply_default(msg); | ||||
if(ret != SSH_OK) | ||||
return ret; | ||||
} | ||||
} | ||||
return SSH_OK; | ||||
} | ||||
/** @} | /** @} | |||
*/ | */ | |||
/* vim: set ts=2 sw=2 et cindent: */ | /* vim: set ts=2 sw=2 et cindent: */ | |||
End of changes. 56 change blocks. | ||||
105 lines changed or deleted | 489 lines changed or added | |||
This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/ |