diff options
Diffstat (limited to 'src/auth1.c')
-rw-r--r-- | src/auth1.c | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/src/auth1.c b/src/auth1.c new file mode 100644 index 00000000..06f05497 --- /dev/null +++ b/src/auth1.c @@ -0,0 +1,206 @@ +/* + * auth1.c - authentication with SSH-1 protocol + * + * This file is part of the SSH Library + * + * Copyright (c) 2005-2008 by Aris Adamantiadis + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#include <string.h> +#include <stdlib.h> + +#include "libssh/priv.h" +#include "libssh/ssh1.h" +#include "libssh/buffer.h" +#include "libssh/packet.h" +#include "libssh/session.h" +#include "libssh/string.h" + +#ifdef WITH_SSH1 +static int wait_auth1_status(ssh_session session) { + enter_function(); + /* wait for a packet */ + while(session->auth_state == SSH_AUTH_STATE_NONE) + if (ssh_handle_packets(session,-1) != SSH_OK) + break; + ssh_log(session,SSH_LOG_PROTOCOL,"Auth state : %d",session->auth_state); + leave_function(); + switch(session->auth_state) { + case SSH_AUTH_STATE_SUCCESS: + return SSH_AUTH_SUCCESS; + case SSH_AUTH_STATE_FAILED: + return SSH_AUTH_DENIED; + default: + return SSH_AUTH_ERROR; + } + return SSH_AUTH_ERROR; +} + +void ssh_auth1_handler(ssh_session session, uint8_t type){ + if(session->session_state != SSH_SESSION_STATE_AUTHENTICATING){ + ssh_set_error(session,SSH_FATAL,"SSH_SMSG_SUCCESS or FAILED received in wrong state"); + return; + } + if(type==SSH_SMSG_SUCCESS){ + session->auth_state=SSH_AUTH_STATE_SUCCESS; + session->session_state=SSH_SESSION_STATE_AUTHENTICATED; + } else if(type==SSH_SMSG_FAILURE) + session->auth_state=SSH_AUTH_STATE_FAILED; +} + +static int send_username(ssh_session session, const char *username) { + ssh_string user = NULL; + /* returns SSH_AUTH_SUCCESS or SSH_AUTH_DENIED */ + if(session->auth_service_state == SSH_AUTH_SERVICE_USER_SENT) { + if(session->auth_state == SSH_AUTH_STATE_FAILED) + return SSH_AUTH_DENIED; + if(session->auth_state == SSH_AUTH_STATE_SUCCESS) + return SSH_AUTH_SUCCESS; + return SSH_AUTH_ERROR; + } + + if (!username) { + if(!(username = session->username)) { + if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) { + session->auth_service_state = SSH_AUTH_SERVICE_DENIED; + return SSH_ERROR; + } else { + username = session->username; + } + } + } + user = ssh_string_from_char(username); + if (user == NULL) { + return SSH_AUTH_ERROR; + } + + if (buffer_add_u8(session->out_buffer, SSH_CMSG_USER) < 0) { + ssh_string_free(user); + return SSH_AUTH_ERROR; + } + if (buffer_add_ssh_string(session->out_buffer, user) < 0) { + ssh_string_free(user); + return SSH_AUTH_ERROR; + } + ssh_string_free(user); + session->auth_state=SSH_AUTH_STATE_NONE; + if (packet_send(session) == SSH_ERROR) { + return SSH_AUTH_ERROR; + } + + if(wait_auth1_status(session) == SSH_AUTH_SUCCESS){ + session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT; + session->auth_state=SSH_AUTH_STATE_SUCCESS; + return SSH_AUTH_SUCCESS; + } else { + session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT; + ssh_set_error(session,SSH_REQUEST_DENIED,"Password authentication necessary for user %s",username); + return SSH_AUTH_DENIED; + } + +} + +/* use the "none" authentication question */ +int ssh_userauth1_none(ssh_session session, const char *username){ + return send_username(session, username); +} + +/** \internal + * \todo implement ssh1 public key + */ +int ssh_userauth1_offer_pubkey(ssh_session session, const char *username, + int type, ssh_string pubkey) { + (void) session; + (void) username; + (void) type; + (void) pubkey; + enter_function(); + leave_function(); + return SSH_AUTH_DENIED; +} + +int ssh_userauth1_password(ssh_session session, const char *username, + const char *password) { + ssh_string pwd = NULL; + int rc; + enter_function(); + rc = send_username(session, username); + if (rc != SSH_AUTH_DENIED) { + leave_function(); + return rc; + } + + /* we trick a bit here. A known flaw in SSH1 protocol is that it's + * easy to guess password sizes. + * not that sure ... + */ + + /* XXX fix me here ! */ + /* cisco IOS doesn't like when a password is followed by zeroes and random pad. */ + if(1 || strlen(password) >= 128) { + /* not risky to disclose the size of such a big password .. */ + pwd = ssh_string_from_char(password); + if (pwd == NULL) { + leave_function(); + return SSH_AUTH_ERROR; + } + } else { + /* fill the password string from random things. the strcpy + * ensure there is at least a nul byte after the password. + * most implementation won't see the garbage at end. + * why garbage ? because nul bytes will be compressed by + * gzip and disclose password len. + */ + pwd = ssh_string_new(128); + if (pwd == NULL) { + leave_function(); + return SSH_AUTH_ERROR; + } + ssh_get_random( pwd->string, 128, 0); + strcpy((char *) pwd->string, password); + } + + if (buffer_add_u8(session->out_buffer, SSH_CMSG_AUTH_PASSWORD) < 0) { + ssh_string_burn(pwd); + ssh_string_free(pwd); + leave_function(); + return SSH_AUTH_ERROR; + } + if (buffer_add_ssh_string(session->out_buffer, pwd) < 0) { + ssh_string_burn(pwd); + ssh_string_free(pwd); + leave_function(); + return SSH_AUTH_ERROR; + } + + ssh_string_burn(pwd); + ssh_string_free(pwd); + session->auth_state=SSH_AUTH_STATE_NONE; + if (packet_send(session) == SSH_ERROR) { + leave_function(); + return SSH_AUTH_ERROR; + } + rc = wait_auth1_status(session); + leave_function(); + return rc; +} + +#endif /* WITH_SSH1 */ +/* vim: set ts=2 sw=2 et cindent: */ |