diff options
Diffstat (limited to 'libssh/server.c')
-rw-r--r-- | libssh/server.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/libssh/server.c b/libssh/server.c index 3872849a..5625229d 100644 --- a/libssh/server.c +++ b/libssh/server.c @@ -526,6 +526,336 @@ int channel_write_stderr(ssh_channel channel, const void *data, uint32_t len) { 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_PASSWORD; + } + 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 disconnect */ + 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.service); + 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_string 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; +} + +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 returns + * 0 if the message has been parsed and treated sucessfuly, 1 otherwise (libssh + * must take care of the response). + */ +void ssh_set_message_callback(SSH_SESSION *session, + int(*ssh_message_callback)(ssh_session session, struct 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: */ |