2005-08-18 10:08:56 +00:00
|
|
|
/*
|
2009-03-29 20:19:18 +00:00
|
|
|
* 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.
|
|
|
|
*/
|
2005-08-18 10:08:56 +00:00
|
|
|
|
2009-10-04 11:47:26 +02:00
|
|
|
#include "config.h"
|
|
|
|
|
2016-05-02 12:18:06 +02:00
|
|
|
#include <errno.h>
|
2005-08-18 10:08:56 +00:00
|
|
|
#include <string.h>
|
2005-10-04 22:11:19 +00:00
|
|
|
#include <stdlib.h>
|
2005-08-18 10:08:56 +00:00
|
|
|
|
2009-04-08 10:45:30 +00:00
|
|
|
#include "libssh/priv.h"
|
|
|
|
#include "libssh/ssh1.h"
|
2009-09-23 23:51:04 +02:00
|
|
|
#include "libssh/buffer.h"
|
|
|
|
#include "libssh/packet.h"
|
|
|
|
#include "libssh/session.h"
|
|
|
|
#include "libssh/string.h"
|
2009-04-08 10:45:30 +00:00
|
|
|
|
2009-07-27 23:17:35 +02:00
|
|
|
#ifdef WITH_SSH1
|
2011-09-14 21:55:54 +02:00
|
|
|
|
|
|
|
static int ssh_auth_status_termination(void *s){
|
|
|
|
ssh_session session=s;
|
|
|
|
if(session->auth_state != SSH_AUTH_STATE_NONE ||
|
|
|
|
session->session_state == SSH_SESSION_STATE_ERROR)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-09-23 21:55:54 +02:00
|
|
|
static int wait_auth1_status(ssh_session session) {
|
2009-04-08 10:45:30 +00:00
|
|
|
/* wait for a packet */
|
2011-09-14 21:55:54 +02:00
|
|
|
if (ssh_handle_packets_termination(session,SSH_TIMEOUT_USER,
|
|
|
|
ssh_auth_status_termination, session) != SSH_OK){
|
2013-07-14 13:31:24 +02:00
|
|
|
|
2011-09-14 21:55:54 +02:00
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
2013-07-14 12:29:45 +02:00
|
|
|
SSH_LOG(SSH_LOG_PROTOCOL,"Auth state : %d",session->auth_state);
|
2013-07-14 13:31:24 +02:00
|
|
|
|
2010-01-24 22:08:20 +01:00
|
|
|
switch(session->auth_state) {
|
|
|
|
case SSH_AUTH_STATE_SUCCESS:
|
2009-04-08 10:45:30 +00:00
|
|
|
return SSH_AUTH_SUCCESS;
|
2010-01-24 22:08:20 +01:00
|
|
|
case SSH_AUTH_STATE_FAILED:
|
2009-04-08 10:45:30 +00:00
|
|
|
return SSH_AUTH_DENIED;
|
2010-01-24 22:08:20 +01:00
|
|
|
default:
|
2011-09-14 21:55:54 +02:00
|
|
|
return SSH_AUTH_AGAIN;
|
2009-04-08 10:45:30 +00:00
|
|
|
}
|
|
|
|
return SSH_AUTH_ERROR;
|
2005-08-18 10:08:56 +00:00
|
|
|
}
|
2009-04-08 10:45:30 +00:00
|
|
|
|
2010-01-24 22:08:20 +01:00
|
|
|
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;
|
|
|
|
}
|
2010-04-24 22:46:19 +02:00
|
|
|
if(type==SSH_SMSG_SUCCESS){
|
2010-01-24 22:08:20 +01:00
|
|
|
session->auth_state=SSH_AUTH_STATE_SUCCESS;
|
2010-04-24 22:46:19 +02:00
|
|
|
session->session_state=SSH_SESSION_STATE_AUTHENTICATED;
|
|
|
|
} else if(type==SSH_SMSG_FAILURE)
|
2010-01-24 22:08:20 +01:00
|
|
|
session->auth_state=SSH_AUTH_STATE_FAILED;
|
|
|
|
}
|
|
|
|
|
2009-09-23 21:55:54 +02:00
|
|
|
static int send_username(ssh_session session, const char *username) {
|
2009-07-24 21:47:23 +02:00
|
|
|
ssh_string user = NULL;
|
2011-09-14 21:55:54 +02:00
|
|
|
int rc;
|
2009-04-08 10:45:30 +00:00
|
|
|
/* returns SSH_AUTH_SUCCESS or SSH_AUTH_DENIED */
|
2010-01-10 21:05:46 +01:00
|
|
|
if(session->auth_service_state == SSH_AUTH_SERVICE_USER_SENT) {
|
2010-01-25 23:23:01 +01:00
|
|
|
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;
|
2009-04-08 10:45:30 +00:00
|
|
|
}
|
2011-09-14 21:55:54 +02:00
|
|
|
if (session->auth_service_state == SSH_AUTH_SERVICE_SENT)
|
|
|
|
goto pending;
|
2009-04-08 10:45:30 +00:00
|
|
|
if (!username) {
|
2012-02-06 09:54:59 +01:00
|
|
|
if(!(username = session->opts.username)) {
|
2009-10-04 11:47:26 +02:00
|
|
|
if (ssh_options_set(session, SSH_OPTIONS_USER, NULL) < 0) {
|
2010-01-10 21:05:46 +01:00
|
|
|
session->auth_service_state = SSH_AUTH_SERVICE_DENIED;
|
|
|
|
return SSH_ERROR;
|
2009-04-08 10:45:30 +00:00
|
|
|
} else {
|
2012-02-06 09:54:59 +01:00
|
|
|
username = session->opts.username;
|
2009-04-08 10:45:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-05-14 00:51:08 +02:00
|
|
|
user = ssh_string_from_char(username);
|
2009-04-08 10:45:30 +00:00
|
|
|
if (user == NULL) {
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
|
2015-09-17 09:43:33 +02:00
|
|
|
if (ssh_buffer_add_u8(session->out_buffer, SSH_CMSG_USER) < 0) {
|
2010-05-14 00:51:08 +02:00
|
|
|
ssh_string_free(user);
|
2009-04-08 10:45:30 +00:00
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
2015-09-17 09:43:33 +02:00
|
|
|
if (ssh_buffer_add_ssh_string(session->out_buffer, user) < 0) {
|
2010-05-14 00:51:08 +02:00
|
|
|
ssh_string_free(user);
|
2009-04-08 10:45:30 +00:00
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
2010-05-14 00:51:08 +02:00
|
|
|
ssh_string_free(user);
|
2010-01-25 23:23:01 +01:00
|
|
|
session->auth_state=SSH_AUTH_STATE_NONE;
|
2011-09-14 21:55:54 +02:00
|
|
|
session->auth_service_state = SSH_AUTH_SERVICE_SENT;
|
2015-09-17 14:11:08 +02:00
|
|
|
if (ssh_packet_send(session) == SSH_ERROR) {
|
2009-04-08 10:45:30 +00:00
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
2016-05-02 12:18:06 +02:00
|
|
|
return SSH_AUTH_AGAIN;
|
2011-09-14 21:55:54 +02:00
|
|
|
pending:
|
|
|
|
rc = wait_auth1_status(session);
|
|
|
|
switch (rc){
|
|
|
|
case SSH_AUTH_SUCCESS:
|
2010-01-25 23:23:01 +01:00
|
|
|
session->auth_service_state=SSH_AUTH_SERVICE_USER_SENT;
|
|
|
|
session->auth_state=SSH_AUTH_STATE_SUCCESS;
|
2012-10-22 18:01:39 +02:00
|
|
|
ssh_set_error(session, SSH_NO_ERROR, "Authentication successful");
|
2010-01-10 21:05:46 +01:00
|
|
|
return SSH_AUTH_SUCCESS;
|
2011-09-14 21:55:54 +02:00
|
|
|
case SSH_AUTH_DENIED:
|
2010-01-25 23:23:01 +01:00
|
|
|
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;
|
2011-09-14 21:55:54 +02:00
|
|
|
case SSH_AUTH_AGAIN:
|
|
|
|
return SSH_AUTH_AGAIN;
|
|
|
|
default:
|
|
|
|
session->auth_service_state = SSH_AUTH_SERVICE_NONE;
|
|
|
|
session->auth_state=SSH_AUTH_STATE_ERROR;
|
|
|
|
return SSH_AUTH_ERROR;
|
2010-01-10 21:05:46 +01:00
|
|
|
}
|
2005-08-18 10:08:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* use the "none" authentication question */
|
2009-09-23 21:55:54 +02:00
|
|
|
int ssh_userauth1_none(ssh_session session, const char *username){
|
2009-04-08 10:45:30 +00:00
|
|
|
return send_username(session, username);
|
2005-08-18 10:08:56 +00:00
|
|
|
}
|
|
|
|
|
2008-11-04 21:59:12 +00:00
|
|
|
/** \internal
|
|
|
|
* \todo implement ssh1 public key
|
|
|
|
*/
|
2009-09-23 21:55:54 +02:00
|
|
|
int ssh_userauth1_offer_pubkey(ssh_session session, const char *username,
|
2009-07-24 21:47:23 +02:00
|
|
|
int type, ssh_string pubkey) {
|
2009-07-27 23:17:35 +02:00
|
|
|
(void) session;
|
|
|
|
(void) username;
|
|
|
|
(void) type;
|
|
|
|
(void) pubkey;
|
2013-07-14 13:31:24 +02:00
|
|
|
|
2009-07-27 23:17:35 +02:00
|
|
|
return SSH_AUTH_DENIED;
|
2005-08-18 10:08:56 +00:00
|
|
|
}
|
|
|
|
|
2009-09-23 21:55:54 +02:00
|
|
|
int ssh_userauth1_password(ssh_session session, const char *username,
|
2009-04-08 10:45:30 +00:00
|
|
|
const char *password) {
|
2009-07-24 21:47:23 +02:00
|
|
|
ssh_string pwd = NULL;
|
2009-04-08 10:45:30 +00:00
|
|
|
int rc;
|
2013-07-14 13:31:24 +02:00
|
|
|
|
2016-05-02 12:18:06 +02:00
|
|
|
if (session->pending_call_state == SSH_PENDING_CALL_AUTH_PASSWORD) {
|
|
|
|
goto pending;
|
|
|
|
}
|
|
|
|
|
2009-04-08 10:45:30 +00:00
|
|
|
rc = send_username(session, username);
|
|
|
|
if (rc != SSH_AUTH_DENIED) {
|
|
|
|
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 .. */
|
2010-05-14 00:51:08 +02:00
|
|
|
pwd = ssh_string_from_char(password);
|
2009-04-08 10:45:30 +00:00
|
|
|
if (pwd == NULL) {
|
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
} else {
|
2011-09-08 15:27:09 +02:00
|
|
|
char buf[128] = {0};
|
2009-04-08 10:45:30 +00:00
|
|
|
/* 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.
|
2005-08-18 10:08:56 +00:00
|
|
|
*/
|
2011-09-08 15:27:09 +02:00
|
|
|
pwd = ssh_string_new(sizeof(buf));
|
2009-04-08 10:45:30 +00:00
|
|
|
if (pwd == NULL) {
|
|
|
|
return SSH_AUTH_ERROR;
|
2005-08-18 10:08:56 +00:00
|
|
|
}
|
2011-09-08 15:27:09 +02:00
|
|
|
ssh_get_random(buf, sizeof(buf), 0);
|
|
|
|
strcpy(buf, password);
|
|
|
|
ssh_string_fill(pwd, buf, sizeof(buf));
|
2009-04-08 10:45:30 +00:00
|
|
|
}
|
2005-08-18 10:08:56 +00:00
|
|
|
|
2015-09-17 09:43:33 +02:00
|
|
|
if (ssh_buffer_add_u8(session->out_buffer, SSH_CMSG_AUTH_PASSWORD) < 0) {
|
2010-05-14 00:51:08 +02:00
|
|
|
ssh_string_burn(pwd);
|
|
|
|
ssh_string_free(pwd);
|
2013-07-14 13:31:24 +02:00
|
|
|
|
2009-04-08 10:45:30 +00:00
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
2015-09-17 09:43:33 +02:00
|
|
|
if (ssh_buffer_add_ssh_string(session->out_buffer, pwd) < 0) {
|
2010-05-14 00:51:08 +02:00
|
|
|
ssh_string_burn(pwd);
|
|
|
|
ssh_string_free(pwd);
|
2013-07-14 13:31:24 +02:00
|
|
|
|
2009-04-08 10:45:30 +00:00
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
|
|
|
|
2010-05-14 00:51:08 +02:00
|
|
|
ssh_string_burn(pwd);
|
|
|
|
ssh_string_free(pwd);
|
2010-01-24 22:08:20 +01:00
|
|
|
session->auth_state=SSH_AUTH_STATE_NONE;
|
2011-09-14 21:55:54 +02:00
|
|
|
session->pending_call_state = SSH_PENDING_CALL_AUTH_PASSWORD;
|
2015-09-17 14:11:08 +02:00
|
|
|
if (ssh_packet_send(session) == SSH_ERROR) {
|
2009-04-08 10:45:30 +00:00
|
|
|
return SSH_AUTH_ERROR;
|
|
|
|
}
|
2011-09-14 21:55:54 +02:00
|
|
|
pending:
|
2010-01-25 23:23:01 +01:00
|
|
|
rc = wait_auth1_status(session);
|
2016-05-02 12:18:06 +02:00
|
|
|
if (rc == SSH_AUTH_ERROR && errno == EAGAIN) {
|
|
|
|
/* Nothing to do */
|
|
|
|
} else if (rc != SSH_AUTH_AGAIN) {
|
|
|
|
session->pending_call_state = SSH_PENDING_CALL_NONE;
|
|
|
|
}
|
2013-07-14 13:31:24 +02:00
|
|
|
|
2010-01-25 23:23:01 +01:00
|
|
|
return rc;
|
2005-08-18 10:08:56 +00:00
|
|
|
}
|
|
|
|
|
2009-07-27 23:17:35 +02:00
|
|
|
#endif /* WITH_SSH1 */
|