1
0
mirror of https://github.com/tmate-io/tmate-ssh-server.git synced 2020-11-18 19:53:51 -08:00

Update libssh with a couple of fixes

see here: https://github.com/nviennot/libssh/commits/master
This commit is contained in:
Nicolas Viennot 2013-11-02 17:28:36 -04:00
parent e1eae8d1c2
commit 8d44dc33f9
25 changed files with 302 additions and 140 deletions

View File

@ -93,6 +93,7 @@ endif (NOT WITH_GCRYPT)
# FUNCTIONS # FUNCTIONS
check_function_exists(isblank HAVE_ISBLANK)
check_function_exists(strncpy HAVE_STRNCPY) check_function_exists(strncpy HAVE_STRNCPY)
check_function_exists(vsnprintf HAVE_VSNPRINTF) check_function_exists(vsnprintf HAVE_VSNPRINTF)
check_function_exists(snprintf HAVE_SNPRINTF) check_function_exists(snprintf HAVE_SNPRINTF)

View File

@ -79,6 +79,9 @@
/* Define to 1 if you have the `_vsnprintf_s' function. */ /* Define to 1 if you have the `_vsnprintf_s' function. */
#cmakedefine HAVE__VSNPRINTF_S 1 #cmakedefine HAVE__VSNPRINTF_S 1
/* Define to 1 if you have the `isblank' function. */
#cmakedefine HAVE_ISBLANK 1
/* Define to 1 if you have the `strncpy' function. */ /* Define to 1 if you have the `strncpy' function. */
#cmakedefine HAVE_STRNCPY 1 #cmakedefine HAVE_STRNCPY 1

View File

@ -1628,7 +1628,7 @@ INCLUDE_FILE_PATTERNS =
# undefined via #undef or recursively expanded use the := operator # undefined via #undef or recursively expanded use the := operator
# instead of the = operator. # instead of the = operator.
PREDEFINED = PREDEFINED = WITH_SERVER WITH_SFTP WITH_PCAP
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
# this tag can be used to specify a list of macro names that should be expanded. # this tag can be used to specify a list of macro names that should be expanded.

View File

@ -210,52 +210,63 @@ results to come.
Synchronous read is done with sftp_read(). Synchronous read is done with sftp_read().
The following example prints the contents of remote file "/etc/profile". For Files are normally transferred in chunks. A good chunk size is 16 KB. The following
each 1024 bytes of information read, it waits until the end of the read operation: example transfers the remote file "/etc/profile" in 16 KB chunks. For each chunk we
request, sftp_read blocks till the data has been received:
@code @code
// Good chunk size
#define MAX_XFER_BUF_SIZE 16384
int sftp_read_sync(ssh_session session, sftp_session sftp) int sftp_read_sync(ssh_session session, sftp_session sftp)
{ {
int access_type; int access_type;
sftp_file file; sftp_file file;
char buffer[1024]; char buffer[MAX_XFER_BUF_SIZE];
int nbytes, rc; int nbytes, nwritten, rc;
int fd;
access_type = O_RDONLY; access_type = O_RDONLY;
file = sftp_open(sftp, "/etc/profile", file = sftp_open(sftp, "/etc/profile",
access_type, 0); access_type, 0);
if (file == NULL) if (file == NULL) {
{ fprintf(stderr, "Can't open file for reading: %s\n",
fprintf(stderr, "Can't open file for reading: %s\n", ssh_get_error(session));
ssh_get_error(session));
return SSH_ERROR;
}
nbytes = sftp_read(file, buffer, sizeof(buffer));
while (nbytes > 0)
{
if (write(1, buffer, nbytes) != nbytes)
{
sftp_close(file);
return SSH_ERROR; return SSH_ERROR;
}
nbytes = sftp_read(file, buffer, sizeof(buffer));
} }
if (nbytes < 0) fd = open("/path/to/profile", O_CREAT);
{ if (fd < 0) {
fprintf(stderr, "Error while reading file: %s\n", fprintf(stderr, "Can't open file for writing: %s\n",
ssh_get_error(session)); strerror(errno));
sftp_close(file); return SSH_ERROR;
return SSH_ERROR; }
for (;;) {
nbytes = sftp_read(file, buffer, sizeof(buffer));
if (nbytes == 0) {
break; // EOF
} else if (nbytes < 0) {
fprintf(stderr, "Error while reading file: %s\n",
ssh_get_error(session));
sftp_close(file);
return SSH_ERROR;
}
nwritten = write(fd, buf, nbytes);
if (nwritten != nbytes) {
fprintf(stderr, "Error writing: %s\n",
strerror(errno));
sftp_close(file);
return SSH_ERROR;
}
} }
rc = sftp_close(file); rc = sftp_close(file);
if (rc != SSH_OK) if (rc != SSH_OK) {
{ fprintf(stderr, "Can't close the read file: %s\n",
fprintf(stderr, "Can't close the read file: %s\n", ssh_get_error(session));
ssh_get_error(session)); return rc;
return rc;
} }
return SSH_OK; return SSH_OK;
@ -274,11 +285,14 @@ The example below reads a very big file in asynchronous, nonblocking, mode. Each
time the data are not ready yet, a counter is incrementer. time the data are not ready yet, a counter is incrementer.
@code @code
// Good chunk size
#define MAX_XFER_BUF_SIZE 16384
int sftp_read_async(ssh_session session, sftp_session sftp) int sftp_read_async(ssh_session session, sftp_session sftp)
{ {
int access_type; int access_type;
sftp_file file; sftp_file file;
char buffer[1024]; char buffer[MAX_XFER_BUF_SIZE];
int async_request; int async_request;
int nbytes; int nbytes;
long counter; long counter;
@ -287,8 +301,7 @@ int sftp_read_async(ssh_session session, sftp_session sftp)
access_type = O_RDONLY; access_type = O_RDONLY;
file = sftp_open(sftp, "some_very_big_file", file = sftp_open(sftp, "some_very_big_file",
access_type, 0); access_type, 0);
if (file == NULL) if (file == NULL) {
{
fprintf(stderr, "Can't open file for reading: %s\n", fprintf(stderr, "Can't open file for reading: %s\n",
ssh_get_error(session)); ssh_get_error(session));
return SSH_ERROR; return SSH_ERROR;
@ -298,27 +311,31 @@ int sftp_read_async(ssh_session session, sftp_session sftp)
async_request = sftp_async_read_begin(file, sizeof(buffer)); async_request = sftp_async_read_begin(file, sizeof(buffer));
counter = 0L; counter = 0L;
usleep(10000); usleep(10000);
if (async_request >= 0) if (async_request >= 0) {
nbytes = sftp_async_read(file, buffer, sizeof(buffer), nbytes = sftp_async_read(file, buffer, sizeof(buffer),
async_request); async_request);
else nbytes = -1; } else {
while (nbytes > 0 || nbytes == SSH_AGAIN) nbytes = -1;
{
if (nbytes > 0)
{
write(1, buffer, nbytes);
async_request = sftp_async_read_begin(file, sizeof(buffer));
}
else counter++;
usleep(10000);
if (async_request >= 0)
nbytes = sftp_async_read(file, buffer, sizeof(buffer),
async_request);
else nbytes = -1;
} }
if (nbytes < 0) while (nbytes > 0 || nbytes == SSH_AGAIN) {
{ if (nbytes > 0) {
write(1, buffer, nbytes);
async_request = sftp_async_read_begin(file, sizeof(buffer));
} else {
counter++;
}
usleep(10000);
if (async_request >= 0) {
nbytes = sftp_async_read(file, buffer, sizeof(buffer),
async_request);
} else {
nbytes = -1;
}
}
if (nbytes < 0) {
fprintf(stderr, "Error while reading file: %s\n", fprintf(stderr, "Error while reading file: %s\n",
ssh_get_error(session)); ssh_get_error(session));
sftp_close(file); sftp_close(file);
@ -328,8 +345,7 @@ int sftp_read_async(ssh_session session, sftp_session sftp)
printf("The counter has reached value: %ld\n", counter); printf("The counter has reached value: %ld\n", counter);
rc = sftp_close(file); rc = sftp_close(file);
if (rc != SSH_OK) if (rc != SSH_OK) {
{
fprintf(stderr, "Can't close the read file: %s\n", fprintf(stderr, "Can't close the read file: %s\n",
ssh_get_error(session)); ssh_get_error(session));
return rc; return rc;

View File

@ -166,7 +166,7 @@ typedef struct ssh_callbacks_struct *ssh_callbacks;
* @param user User that wants to authenticate * @param user User that wants to authenticate
* @param password Password used for authentication * @param password Password used for authentication
* @param userdata Userdata to be passed to the callback function. * @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_OK Authentication is accepted. * @returns SSH_AUTH_SUCCESS Authentication is accepted.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. * @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
* @returns SSH_AUTH_DENIED Authentication failed. * @returns SSH_AUTH_DENIED Authentication failed.
*/ */
@ -179,7 +179,7 @@ typedef int (*ssh_auth_password_callback) (ssh_session session, const char *user
* @param session Current session handler * @param session Current session handler
* @param user User that wants to authenticate * @param user User that wants to authenticate
* @param userdata Userdata to be passed to the callback function. * @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_OK Authentication is accepted. * @returns SSH_AUTH_SUCCESS Authentication is accepted.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. * @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
* @returns SSH_AUTH_DENIED Authentication failed. * @returns SSH_AUTH_DENIED Authentication failed.
*/ */
@ -191,7 +191,7 @@ typedef int (*ssh_auth_none_callback) (ssh_session session, const char *user, vo
* @param user Username of the user (can be spoofed) * @param user Username of the user (can be spoofed)
* @param principal Authenticated principal of the user, including realm. * @param principal Authenticated principal of the user, including realm.
* @param userdata Userdata to be passed to the callback function. * @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_OK Authentication is accepted. * @returns SSH_AUTH_SUCCESS Authentication is accepted.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. * @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
* @returns SSH_AUTH_DENIED Authentication failed. * @returns SSH_AUTH_DENIED Authentication failed.
* @warning Implementations should verify that parameter user matches in some way the principal. * @warning Implementations should verify that parameter user matches in some way the principal.
@ -209,7 +209,7 @@ typedef int (*ssh_auth_gssapi_mic_callback) (ssh_session session, const char *us
* SSH_PUBLICKEY_STATE_VALID if the signature is valid. Others values should be * SSH_PUBLICKEY_STATE_VALID if the signature is valid. Others values should be
* replied with a SSH_AUTH_DENIED. * replied with a SSH_AUTH_DENIED.
* @param userdata Userdata to be passed to the callback function. * @param userdata Userdata to be passed to the callback function.
* @returns SSH_AUTH_OK Authentication is accepted. * @returns SSH_AUTH_SUCCESS Authentication is accepted.
* @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed. * @returns SSH_AUTH_PARTIAL Partial authentication, more authentication means are needed.
* @returns SSH_AUTH_DENIED Authentication failed. * @returns SSH_AUTH_DENIED Authentication failed.
*/ */

View File

@ -38,6 +38,11 @@ typedef SHA_CTX* SHACTX;
typedef SHA256_CTX* SHA256CTX; typedef SHA256_CTX* SHA256CTX;
typedef MD5_CTX* MD5CTX; typedef MD5_CTX* MD5CTX;
typedef HMAC_CTX* HMACCTX; typedef HMAC_CTX* HMACCTX;
#ifdef HAVE_ECC
typedef EVP_MD_CTX *EVPCTX;
#else
typedef void *EVPCTX;
#endif
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH #define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
#ifdef MD5_DIGEST_LEN #ifdef MD5_DIGEST_LEN

View File

@ -29,6 +29,7 @@
typedef gcry_md_hd_t SHACTX; typedef gcry_md_hd_t SHACTX;
typedef gcry_md_hd_t MD5CTX; typedef gcry_md_hd_t MD5CTX;
typedef gcry_md_hd_t HMACCTX; typedef gcry_md_hd_t HMACCTX;
typedef void *EVPCTX;
#define SHA_DIGEST_LENGTH 20 #define SHA_DIGEST_LENGTH 20
#define SHA_DIGEST_LEN SHA_DIGEST_LENGTH #define SHA_DIGEST_LEN SHA_DIGEST_LENGTH
#define MD5_DIGEST_LEN 16 #define MD5_DIGEST_LEN 16

View File

@ -60,6 +60,7 @@ struct ssh_key_struct {
struct ssh_signature_struct { struct ssh_signature_struct {
enum ssh_keytypes_e type; enum ssh_keytypes_e type;
const char *type_c;
#ifdef HAVE_LIBGCRYPT #ifdef HAVE_LIBGCRYPT
gcry_sexp_t dsa_sig; gcry_sexp_t dsa_sig;
gcry_sexp_t rsa_sig; gcry_sexp_t rsa_sig;

View File

@ -67,7 +67,9 @@
# define strcasecmp _stricmp # define strcasecmp _stricmp
# define strncasecmp _strnicmp # define strncasecmp _strnicmp
# define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r') # if ! defined(HAVE_ISBLANK)
# define isblank(ch) ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r')
# endif
# define usleep(X) Sleep(((X)+1000)/1000) # define usleep(X) Sleep(((X)+1000)/1000)

View File

@ -53,6 +53,9 @@ void sha1(unsigned char *digest,int len,unsigned char *hash);
void sha256(unsigned char *digest, int len, unsigned char *hash); void sha256(unsigned char *digest, int len, unsigned char *hash);
void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen); void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned int *hlen);
EVPCTX evp_init(int nid);
void evp_update(EVPCTX ctx, const void *data, unsigned long len);
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen);
ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type); ssh_mac_ctx ssh_mac_ctx_init(enum ssh_mac_e type);
void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len); void ssh_mac_update(ssh_mac_ctx ctx, const void *data, unsigned long len);

View File

@ -355,7 +355,7 @@ int ssh_userauth_list(ssh_session session, const char *username)
* later. * later.
* *
* @note Most server implementations do not permit changing the username during * @note Most server implementations do not permit changing the username during
* authentication. The username should only be set with ssh_optoins_set() only * authentication. The username should only be set with ssh_options_set() only
* before you connect to the server. * before you connect to the server.
*/ */
int ssh_userauth_none(ssh_session session, const char *username) { int ssh_userauth_none(ssh_session session, const char *username) {
@ -478,7 +478,7 @@ fail:
* later. * later.
* *
* @note Most server implementations do not permit changing the username during * @note Most server implementations do not permit changing the username during
* authentication. The username should only be set with ssh_optoins_set() only * authentication. The username should only be set with ssh_options_set() only
* before you connect to the server. * before you connect to the server.
*/ */
int ssh_userauth_try_publickey(ssh_session session, int ssh_userauth_try_publickey(ssh_session session,
@ -640,7 +640,7 @@ fail:
* later. * later.
* *
* @note Most server implementations do not permit changing the username during * @note Most server implementations do not permit changing the username during
* authentication. The username should only be set with ssh_optoins_set() only * authentication. The username should only be set with ssh_options_set() only
* before you connect to the server. * before you connect to the server.
*/ */
int ssh_userauth_publickey(ssh_session session, int ssh_userauth_publickey(ssh_session session,
@ -961,7 +961,7 @@ struct ssh_agent_state_struct {
* later. * later.
* *
* @note Most server implementations do not permit changing the username during * @note Most server implementations do not permit changing the username during
* authentication. The username should only be set with ssh_optoins_set() only * authentication. The username should only be set with ssh_options_set() only
* before you connect to the server. * before you connect to the server.
*/ */
int ssh_userauth_agent(ssh_session session, int ssh_userauth_agent(ssh_session session,
@ -1083,7 +1083,7 @@ struct ssh_auth_auto_state_struct {
* later. * later.
* *
* @note Most server implementations do not permit changing the username during * @note Most server implementations do not permit changing the username during
* authentication. The username should only be set with ssh_optoins_set() only * authentication. The username should only be set with ssh_options_set() only
* before you connect to the server. * before you connect to the server.
*/ */
int ssh_userauth_publickey_auto(ssh_session session, int ssh_userauth_publickey_auto(ssh_session session,
@ -1297,7 +1297,7 @@ int ssh_userauth_publickey_auto(ssh_session session,
* later. * later.
* *
* @note Most server implementations do not permit changing the username during * @note Most server implementations do not permit changing the username during
* authentication. The username should only be set with ssh_optoins_set() only * authentication. The username should only be set with ssh_options_set() only
* before you connect to the server. * before you connect to the server.
* *
* @see ssh_userauth_none() * @see ssh_userauth_none()

View File

@ -454,8 +454,7 @@ int ssh_bind_accept(ssh_bind sshbind, ssh_session session) {
#else #else
close(fd); close(fd);
#endif #endif
if (session->socket) ssh_socket_free(session->socket);
ssh_socket_close(session->socket);
} }
return rc; return rc;
} }

View File

@ -2089,7 +2089,7 @@ SSH_PACKET_CALLBACK(ssh_request_denied){
static int ssh_global_request_termination(void *s){ static int ssh_global_request_termination(void *s){
ssh_session session = (ssh_session) s; ssh_session session = (ssh_session) s;
if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING || if (session->global_req_state != SSH_CHANNEL_REQ_STATE_PENDING ||
session->session_state != SSH_SESSION_STATE_ERROR) session->session_state == SSH_SESSION_STATE_ERROR)
return 1; return 1;
else else
return 0; return 0;
@ -2117,43 +2117,66 @@ static int ssh_global_request_termination(void *s){
static int global_request(ssh_session session, const char *request, static int global_request(ssh_session session, const char *request,
ssh_buffer buffer, int reply) { ssh_buffer buffer, int reply) {
ssh_string req = NULL; ssh_string req = NULL;
int rc = SSH_ERROR; int rc;
if(session->global_req_state != SSH_CHANNEL_REQ_STATE_NONE) switch (session->global_req_state) {
case SSH_CHANNEL_REQ_STATE_NONE:
break;
default:
goto pending; goto pending;
}
rc = buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST);
if (rc < 0) {
goto error;
}
req = ssh_string_from_char(request); req = ssh_string_from_char(request);
if (req == NULL) { if (req == NULL) {
ssh_set_error_oom(session); ssh_set_error_oom(session);
goto error; rc = SSH_ERROR;
goto error;
} }
if (buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST) < 0 || rc = buffer_add_ssh_string(session->out_buffer, req);
buffer_add_ssh_string(session->out_buffer, req) < 0 ||
buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) {
ssh_set_error_oom(session);
goto error;
}
ssh_string_free(req); ssh_string_free(req);
req=NULL; if (rc < 0) {
ssh_set_error_oom(session);
rc = SSH_ERROR;
goto error;
}
rc = buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1);
if (rc < 0) {
ssh_set_error_oom(session);
rc = SSH_ERROR;
goto error;
}
if (buffer != NULL) { if (buffer != NULL) {
if (buffer_add_data(session->out_buffer, buffer_get_rest(buffer), rc = buffer_add_data(session->out_buffer,
buffer_get_rest_len(buffer)) < 0) { buffer_get_rest(buffer),
ssh_set_error_oom(session); buffer_get_rest_len(buffer));
goto error; if (rc < 0) {
} ssh_set_error_oom(session);
rc = SSH_ERROR;
goto error;
}
} }
session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING; session->global_req_state = SSH_CHANNEL_REQ_STATE_PENDING;
if (packet_send(session) == SSH_ERROR) { rc = packet_send(session);
return rc; if (rc == SSH_ERROR) {
return rc;
} }
SSH_LOG(SSH_LOG_PACKET, SSH_LOG(SSH_LOG_PACKET,
"Sent a SSH_MSG_GLOBAL_REQUEST %s", request); "Sent a SSH_MSG_GLOBAL_REQUEST %s", request);
if (reply == 0) {
session->global_req_state=SSH_CHANNEL_REQ_STATE_NONE;
return SSH_OK; if (reply == 0) {
session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE;
return SSH_OK;
} }
pending: pending:
rc = ssh_handle_packets_termination(session, rc = ssh_handle_packets_termination(session,
@ -2178,16 +2201,16 @@ pending:
break; break;
case SSH_CHANNEL_REQ_STATE_ERROR: case SSH_CHANNEL_REQ_STATE_ERROR:
case SSH_CHANNEL_REQ_STATE_NONE: case SSH_CHANNEL_REQ_STATE_NONE:
rc=SSH_ERROR; rc = SSH_ERROR;
break; break;
case SSH_CHANNEL_REQ_STATE_PENDING: case SSH_CHANNEL_REQ_STATE_PENDING:
rc=SSH_AGAIN; return SSH_AGAIN;
break;
} }
session->global_req_state = SSH_CHANNEL_REQ_STATE_NONE;
return rc; return rc;
error: error:
ssh_string_free(req); buffer_reinit(session->out_buffer);
return rc; return rc;
} }

View File

@ -105,14 +105,18 @@ static int callback_receive_banner(const void *data, size_t len, void *user) {
ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,i+1); ssh_pcap_context_write(session->pcap_ctx,SSH_PCAP_DIR_IN,buffer,i+1,i+1);
} }
#endif #endif
if(buffer[i]=='\r') if(buffer[i]=='\r') {
buffer[i]='\0'; buffer[i]='\0';
if(buffer[i]=='\n'){ }
buffer[i]='\0'; if (buffer[i]=='\n') {
str=strdup(buffer); buffer[i] = '\0';
/* number of bytes read */ str = strdup(buffer);
ret=i+1; if (str == NULL) {
session->serverbanner=str; return SSH_ERROR;
}
/* number of bytes read */
ret = i + 1;
session->serverbanner = str;
session->session_state=SSH_SESSION_STATE_BANNER_RECEIVED; session->session_state=SSH_SESSION_STATE_BANNER_RECEIVED;
SSH_LOG(SSH_LOG_PACKET,"Received banner: %s",str); SSH_LOG(SSH_LOG_PACKET,"Received banner: %s",str);
session->ssh_connection_callback(session); session->ssh_connection_callback(session);

View File

@ -436,6 +436,7 @@ static int ssh_select_cb (socket_t fd, int revents, void *userdata){
*/ */
int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd, int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
fd_set *readfds, struct timeval *timeout) { fd_set *readfds, struct timeval *timeout) {
fd_set origfds;
socket_t fd; socket_t fd;
int i,j; int i,j;
int rc; int rc;
@ -449,9 +450,11 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
ssh_event_add_session(event, channels[i]->session); ssh_event_add_session(event, channels[i]->session);
} }
FD_ZERO(&origfds);
for (fd = 0; fd < maxfd ; fd++) { for (fd = 0; fd < maxfd ; fd++) {
if (FD_ISSET(fd, readfds)) { if (FD_ISSET(fd, readfds)) {
ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds); ssh_event_add_fd(event, fd, POLLIN, ssh_select_cb, readfds);
FD_SET(fd, &origfds);
} }
} }
outchannels[0] = NULL; outchannels[0] = NULL;
@ -485,13 +488,17 @@ int ssh_select(ssh_channel *channels, ssh_channel *outchannels, socket_t maxfd,
/* since there's nothing, let's fire the polling */ /* since there's nothing, let's fire the polling */
rc = ssh_event_dopoll(event,tm); rc = ssh_event_dopoll(event,tm);
if (rc == SSH_ERROR){ if (rc == SSH_ERROR){
ssh_event_free(event); goto out;
return SSH_ERROR;
} }
tm = ssh_timeout_update(&ts, base_tm); tm = ssh_timeout_update(&ts, base_tm);
firstround=0; firstround=0;
} while (1); } while (1);
out: out:
for (fd = 0; fd < maxfd; fd++) {
if (FD_ISSET(fd, &origfds)) {
ssh_event_remove_fd(event, fd);
}
}
ssh_event_free(event); ssh_event_free(event);
return SSH_OK; return SSH_OK;
} }

View File

@ -123,6 +123,30 @@ void evp(int nid, unsigned char *digest, int len, unsigned char *hash, unsigned
EVP_DigestUpdate(&md, digest, len); EVP_DigestUpdate(&md, digest, len);
EVP_DigestFinal(&md, hash, hlen); EVP_DigestFinal(&md, hash, hlen);
} }
EVPCTX evp_init(int nid)
{
const EVP_MD *evp_md = nid_to_evpmd(nid);
EVPCTX ctx = malloc(sizeof(EVP_MD_CTX));
if (ctx == NULL) {
return NULL;
}
EVP_DigestInit(ctx, evp_md);
return ctx;
}
void evp_update(EVPCTX ctx, const void *data, unsigned long len)
{
EVP_DigestUpdate(ctx, data, len);
}
void evp_final(EVPCTX ctx, unsigned char *md, unsigned int *mdlen)
{
EVP_DigestFinal(ctx, md, mdlen);
}
#endif #endif
SHA256CTX sha256_init(void){ SHA256CTX sha256_init(void){

View File

@ -120,10 +120,18 @@ static int ssh_execute_server_request(ssh_session session, ssh_message msg)
msg->auth_request.username, msg->auth_request.pubkey, msg->auth_request.username, msg->auth_request.pubkey,
msg->auth_request.signature_state, msg->auth_request.signature_state,
session->server_callbacks->userdata); session->server_callbacks->userdata);
if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL){ if (msg->auth_request.signature_state != SSH_PUBLICKEY_STATE_NONE) {
if (rc == SSH_AUTH_SUCCESS || rc == SSH_AUTH_PARTIAL) {
ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL); ssh_message_auth_reply_success(msg, rc == SSH_AUTH_PARTIAL);
} else { } else {
ssh_message_reply_default(msg); ssh_message_reply_default(msg);
}
} else {
if (rc == SSH_AUTH_SUCCESS) {
ssh_message_auth_reply_pk_ok_simple(msg);
} else {
ssh_message_reply_default(msg);
}
} }
return SSH_OK; return SSH_OK;
@ -304,7 +312,7 @@ static int ssh_execute_server_callbacks(ssh_session session, ssh_message msg){
} }
/* This one is in fact a client callback... */ /* This one is in fact a client callback... */
if (session->common.callbacks != NULL) { else if (session->common.callbacks != NULL) {
rc = ssh_execute_client_request(session, msg); rc = ssh_execute_client_request(session, msg);
} }

View File

@ -856,6 +856,11 @@ int ssh_options_get_port(ssh_session session, unsigned int* port_target) {
* It may include "%s" which will be replaced by the * It may include "%s" which will be replaced by the
* user home directory. * user home directory.
* *
* - SSH_OPTIONS_PROXYCOMMAND:
* Get the proxycommand necessary to log into the
* remote host. When not explicitly set, it will be read
* from the ~/.ssh/config file.
*
* @param value The value to get into. As a char**, space will be * @param value The value to get into. As a char**, space will be
* allocated by the function for the value, it is * allocated by the function for the value, it is
* your responsibility to free the memory using * your responsibility to free the memory using
@ -894,6 +899,10 @@ int ssh_options_get(ssh_session session, enum ssh_options_e type, char** value)
src = ssh_iterator_value(char *, it); src = ssh_iterator_value(char *, it);
break; break;
} }
case SSH_OPTIONS_PROXYCOMMAND: {
src = session->opts.ProxyCommand;
break;
}
default: default:
ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type); ssh_set_error(session, SSH_REQUEST_DENIED, "Unknown ssh option %d", type);
return SSH_ERROR; return SSH_ERROR;

View File

@ -1118,7 +1118,7 @@ int ssh_pki_export_signature_blob(const ssh_signature sig,
return SSH_ERROR; return SSH_ERROR;
} }
str = ssh_string_from_char(ssh_key_type_to_char(sig->type)); str = ssh_string_from_char(sig->type_c);
if (str == NULL) { if (str == NULL) {
ssh_buffer_free(buf); ssh_buffer_free(buf);
return SSH_ERROR; return SSH_ERROR;
@ -1271,11 +1271,9 @@ ssh_string ssh_pki_do_sign(ssh_session session,
struct ssh_crypto_struct *crypto = struct ssh_crypto_struct *crypto =
session->current_crypto ? session->current_crypto : session->current_crypto ? session->current_crypto :
session->next_crypto; session->next_crypto;
unsigned char hash[SHA_DIGEST_LEN] = {0};
ssh_signature sig; ssh_signature sig;
ssh_string sig_blob; ssh_string sig_blob;
ssh_string session_id; ssh_string session_id;
SHACTX ctx;
int rc; int rc;
if (privkey == NULL || !ssh_key_is_private(privkey)) { if (privkey == NULL || !ssh_key_is_private(privkey)) {
@ -1287,24 +1285,46 @@ ssh_string ssh_pki_do_sign(ssh_session session,
return NULL; return NULL;
} }
ssh_string_fill(session_id, crypto->session_id, crypto->digest_len); ssh_string_fill(session_id, crypto->session_id, crypto->digest_len);
/* TODO: change when supporting ECDSA keys */
ctx = sha1_init();
if (ctx == NULL) {
ssh_string_free(session_id);
return NULL;
}
sha1_update(ctx, session_id, ssh_string_len(session_id) + 4); if (privkey->type == SSH_KEYTYPE_ECDSA) {
ssh_string_free(session_id); #ifdef HAVE_ECC
unsigned char ehash[EVP_DIGEST_LEN] = {0};
uint32_t elen;
EVPCTX ctx;
sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf)); ctx = evp_init(privkey->ecdsa_nid);
sha1_final(hash, ctx); if (ctx == NULL) {
ssh_string_free(session_id);
return NULL;
}
evp_update(ctx, session_id, ssh_string_len(session_id) + 4);
evp_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf));
evp_final(ctx, ehash, &elen);
sig = pki_do_sign(privkey, ehash, elen);
#endif
} else {
unsigned char hash[SHA_DIGEST_LEN] = {0};
SHACTX ctx;
ctx = sha1_init();
if (ctx == NULL) {
ssh_string_free(session_id);
return NULL;
}
sha1_update(ctx, session_id, ssh_string_len(session_id) + 4);
sha1_update(ctx, buffer_get_rest(sigbuf), buffer_get_rest_len(sigbuf));
sha1_final(hash, ctx);
#ifdef DEBUG_CRYPTO #ifdef DEBUG_CRYPTO
ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN); ssh_print_hexa("Hash being signed", hash, SHA_DIGEST_LEN);
#endif #endif
sig = pki_do_sign(privkey, hash, SHA_DIGEST_LEN); sig = pki_do_sign(privkey, hash, SHA_DIGEST_LEN);
}
ssh_string_free(session_id);
if (sig == NULL) { if (sig == NULL) {
return NULL; return NULL;
} }

View File

@ -1018,36 +1018,52 @@ ssh_string pki_signature_to_blob(const ssh_signature sig)
break; break;
case SSH_KEYTYPE_ECDSA: case SSH_KEYTYPE_ECDSA:
#ifdef HAVE_OPENSSL_ECC #ifdef HAVE_OPENSSL_ECC
{
ssh_buffer b;
int rc;
b = ssh_buffer_new();
if (b == NULL) {
return NULL;
}
r = make_bignum_string(sig->ecdsa_sig->r); r = make_bignum_string(sig->ecdsa_sig->r);
if (r == NULL) { if (r == NULL) {
ssh_buffer_free(b);
return NULL; return NULL;
} }
rc = buffer_add_ssh_string(b, r);
ssh_string_free(r);
if (rc < 0) {
ssh_buffer_free(b);
return NULL;
}
s = make_bignum_string(sig->ecdsa_sig->s); s = make_bignum_string(sig->ecdsa_sig->s);
if (s == NULL) { if (s == NULL) {
ssh_string_free(r); ssh_buffer_free(b);
return NULL; return NULL;
} }
rc = buffer_add_ssh_string(b, s);
memcpy(buffer,
((char *)ssh_string_data(r)) + ssh_string_len(r) - 20,
20);
memcpy(buffer + 20,
((char *)ssh_string_data(s)) + ssh_string_len(s) - 20,
20);
ssh_string_free(r);
ssh_string_free(s); ssh_string_free(s);
if (rc < 0) {
sig_blob = ssh_string_new(40); ssh_buffer_free(b);
if (sig_blob == NULL) {
return NULL; return NULL;
} }
ssh_string_fill(sig_blob, buffer, 40); sig_blob = ssh_string_new(buffer_get_rest_len(b));
if (sig_blob == NULL) {
ssh_buffer_free(b);
return NULL;
}
ssh_string_fill(sig_blob, buffer_get_rest(b), buffer_get_rest_len(b));
ssh_buffer_free(b);
break; break;
}
#endif #endif
case SSH_KEYTYPE_UNKNOWN: case SSH_KEYTYPE_UNKNOWN:
ssh_pki_log("Unknown signature key type: %d", sig->type); ssh_pki_log("Unknown signature key type: %s", sig->type_c);
return NULL; return NULL;
} }
@ -1070,6 +1086,7 @@ ssh_signature pki_signature_from_blob(const ssh_key pubkey,
} }
sig->type = type; sig->type = type;
sig->type_c = ssh_key_type_to_char(type);
len = ssh_string_len(sig_blob); len = ssh_string_len(sig_blob);
@ -1309,6 +1326,7 @@ ssh_signature pki_do_sign(const ssh_key privkey,
} }
sig->type = privkey->type; sig->type = privkey->type;
sig->type_c = privkey->type_c;
switch(privkey->type) { switch(privkey->type) {
case SSH_KEYTYPE_DSS: case SSH_KEYTYPE_DSS:
@ -1368,6 +1386,7 @@ ssh_signature pki_do_sign_sessionid(const ssh_key key,
return NULL; return NULL;
} }
sig->type = key->type; sig->type = key->type;
sig->type_c = key->type_c;
switch(key->type) { switch(key->type) {
case SSH_KEYTYPE_DSS: case SSH_KEYTYPE_DSS:

View File

@ -450,7 +450,11 @@ void ssh_poll_ctx_free(ssh_poll_ctx ctx) {
if (ctx->polls_allocated > 0) { if (ctx->polls_allocated > 0) {
while (ctx->polls_used > 0){ while (ctx->polls_used > 0){
ssh_poll_handle p = ctx->pollptrs[0]; ssh_poll_handle p = ctx->pollptrs[0];
ssh_poll_ctx_remove(ctx, p); /*
* The free function calls ssh_poll_ctx_remove() and decrements
* ctx->polls_used
*/
ssh_poll_free(p);
} }
SAFE_FREE(ctx->pollptrs); SAFE_FREE(ctx->pollptrs);

View File

@ -814,7 +814,7 @@ int ssh_scp_integer_mode(const char *mode){
*/ */
char *ssh_scp_string_mode(int mode){ char *ssh_scp_string_mode(int mode){
char buffer[16]; char buffer[16];
snprintf(buffer,sizeof(buffer),"%.4o",mode); snprintf(buffer,sizeof(buffer),"%.4d",mode);
return strdup(buffer); return strdup(buffer);
} }

View File

@ -317,8 +317,12 @@ int crypt_set_algorithms_server(ssh_session session){
session->next_crypto->do_compress_in=1; session->next_crypto->do_compress_in=1;
} }
if(strcmp(method,"zlib@openssh.com") == 0){ if(strcmp(method,"zlib@openssh.com") == 0){
SSH_LOG(SSH_LOG_PACKET,"enabling C->S compression"); SSH_LOG(SSH_LOG_PACKET,"enabling C->S delayed compression");
session->next_crypto->delayed_compress_in=1;
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
session->next_crypto->do_compress_in=1;
else
session->next_crypto->delayed_compress_in=1;
} }
method = session->next_crypto->kex_methods[SSH_COMP_S_C]; method = session->next_crypto->kex_methods[SSH_COMP_S_C];
@ -328,7 +332,11 @@ int crypt_set_algorithms_server(ssh_session session){
} }
if(strcmp(method,"zlib@openssh.com") == 0){ if(strcmp(method,"zlib@openssh.com") == 0){
SSH_LOG(SSH_LOG_PACKET,"enabling S->C delayed compression\n"); SSH_LOG(SSH_LOG_PACKET,"enabling S->C delayed compression\n");
session->next_crypto->delayed_compress_out=1;
if (session->flags & SSH_SESSION_FLAG_AUTHENTICATED)
session->next_crypto->do_compress_out=1;
else
session->next_crypto->delayed_compress_out=1;
} }
method = session->next_crypto->kex_methods[SSH_HOSTKEYS]; method = session->next_crypto->kex_methods[SSH_HOSTKEYS];

View File

@ -6,7 +6,10 @@ add_cmocka_test(torture_connect torture_connect.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_knownhosts torture_knownhosts.c ${TORTURE_LIBRARY}) add_cmocka_test(torture_knownhosts torture_knownhosts.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_proxycommand torture_proxycommand.c ${TORTURE_LIBRARY}) add_cmocka_test(torture_proxycommand torture_proxycommand.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_session torture_session.c ${TORTURE_LIBRARY}) add_cmocka_test(torture_session torture_session.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_forward torture_forward.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_request_env torture_request_env.c ${TORTURE_LIBRARY})
if (WITH_SFTP) if (WITH_SFTP)
add_cmocka_test(torture_sftp_static torture_sftp_static.c ${TORTURE_LIBRARY}) add_cmocka_test(torture_sftp_static torture_sftp_static.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_sftp_dir torture_sftp_dir.c ${TORTURE_LIBRARY}) add_cmocka_test(torture_sftp_dir torture_sftp_dir.c ${TORTURE_LIBRARY})
add_cmocka_test(torture_sftp_read torture_sftp_read.c ${TORTURE_LIBRARY})
endif (WITH_SFTP) endif (WITH_SFTP)

View File

@ -13,4 +13,6 @@ if (UNIX AND NOT WIN32)
add_cmocka_test(torture_pki torture_pki.c ${TORTURE_LIBRARY}) add_cmocka_test(torture_pki torture_pki.c ${TORTURE_LIBRARY})
# requires pthread # requires pthread
add_cmocka_test(torture_rand torture_rand.c ${TORTURE_LIBRARY}) add_cmocka_test(torture_rand torture_rand.c ${TORTURE_LIBRARY})
# requires /dev/null
add_cmocka_test(torture_channel torture_channel.c ${TORTURE_LIBRARY})
endif (UNIX AND NOT WIN32) endif (UNIX AND NOT WIN32)