diff -Naurw libssh2-0.18.orig/include/libssh2.h libssh2-0.18.agent/include/libssh2.h --- libssh2-0.18.orig/include/libssh2.h 2007-11-11 13:41:52.000000000 +0300 +++ libssh2-0.18.agent/include/libssh2.h 2007-12-26 12:32:49.000000000 +0300 @@ -301,6 +301,11 @@ #define LIBSSH2_ERROR_PUBLICKEY_PROTOCOL -36 #define LIBSSH2_ERROR_EAGAIN -37 +/* Last IO operation */ +#define LIBSSH2_LAST_IO_NONE 0 +#define LIBSSH2_LAST_IO_SEND 1 +#define LIBSSH2_LAST_IO_RECV 2 + /* Session API */ LIBSSH2_API LIBSSH2_SESSION *libssh2_session_init_ex(LIBSSH2_ALLOC_FUNC((*my_alloc)), LIBSSH2_FREE_FUNC((*my_free)), LIBSSH2_REALLOC_FUNC((*my_realloc)), void *abstract); #define libssh2_session_init() libssh2_session_init_ex(NULL, NULL, NULL, NULL) @@ -320,6 +325,7 @@ LIBSSH2_API const char *libssh2_session_methods(LIBSSH2_SESSION *session, int method_type); LIBSSH2_API int libssh2_session_last_error(LIBSSH2_SESSION *session, char **errmsg, int *errmsg_len, int want_buf); LIBSSH2_API int libssh2_session_last_errno(LIBSSH2_SESSION *session); +LIBSSH2_API int libssh2_session_last_io(LIBSSH2_SESSION *session); LIBSSH2_API int libssh2_session_flag(LIBSSH2_SESSION *session, int flag, int value); @@ -342,6 +348,11 @@ #define libssh2_userauth_hostbased_fromfile(session, username, publickey, privatekey, passphrase, hostname) \ libssh2_userauth_hostbased_fromfile_ex((session), (username), strlen(username), (publickey), (privatekey), (passphrase), (hostname), strlen(hostname), (username), strlen(username)) +LIBSSH2_API int libssh2_userauth_sign_with_agent(LIBSSH2_SESSION * session, const char *username, + unsigned int username_len, + unsigned char **signature, + unsigned long *signature_len); + /* * response_callback is provided with filled by library prompts array, * but client must allocate and fill individual responses. Responses diff -Naurw libssh2-0.18.orig/src/agent.c libssh2-0.18.agent/src/agent.c --- libssh2-0.18.orig/src/agent.c 1970-01-01 03:00:00.000000000 +0300 +++ libssh2-0.18.agent/src/agent.c 2008-01-23 20:11:06.000000000 +0300 @@ -0,0 +1,255 @@ +#include "libssh2_priv.h" + +#include +#include +#include + +#define SSH2_AGENTC_REQUEST_IDENTITIES 11 +#define SSH2_AGENT_IDENTITIES_ANSWER 12 +#define SSH_AGENTC_SIGN_REQUEST 13 +#define SSH2_AGENT_SIGN_RESPONSE 14 + +#ifdef LIBSSH2DEBUG +#define UNPRINTABLE_CHAR '.' +static void +debugdump(LIBSSH2_SESSION * session, + const char *desc, unsigned char *ptr, unsigned long size) +{ + size_t i; + size_t c; + FILE *stream = stdout; + unsigned int width = 0x10; + + if (!(session->showmask & (1 << LIBSSH2_DBG_TRANS))) { + /* not asked for, bail out */ + return; + } + + fprintf(stream, "=> %s (%d bytes)\n", desc, (int) size); + + for(i = 0; i < size; i += width) { + + fprintf(stream, "%04lx: ", (long)i); + + /* hex not disabled, show it */ + for(c = 0; c < width; c++) { + if (i + c < size) + fprintf(stream, "%02x ", ptr[i + c]); + else + fputs(" ", stream); + } + + for(c = 0; (c < width) && (i + c < size); c++) { + fprintf(stream, "%c", + (ptr[i + c] >= 0x20) && + (ptr[i + c] < 0x80) ? ptr[i + c] : UNPRINTABLE_CHAR); + } + fputc('\n', stream); /* newline */ + } + fflush(stream); +} +#else +#define debugdump(a,x,y,z) +#endif + + +static int get_agent_socket(LIBSSH2_SESSION *session) +{ + struct sockaddr_un sunaddr; + int sock; + char *sock_name; + + sock_name = getenv("SSH_AUTH_SOCK"); + if (sock_name == NULL) { + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "no SSH_AUTH_SOCK set."); + return -1; + } + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "using %s as agent socket", sock_name); + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "method: %.*s", + (int)session->userauth_pblc_method_len, session->userauth_pblc_method); + *session->userauth_pblc_b = 0x01; + + sunaddr.sun_family = AF_UNIX; + strcpy(sunaddr.sun_path, sock_name); + + sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock < 0) { + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "sock < 0. Returning."); + return -1; + } + + /* TODO: connect may return EINPROGRESS, check it. */ + if (connect(sock, (struct sockaddr *)&sunaddr, sizeof sunaddr) < 0) { + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "connect < 0. Returning."); + close(sock); + return -1; + } + return sock; +} + +/* + * + */ +LIBSSH2_API int +libssh2_userauth_sign_with_agent(LIBSSH2_SESSION *session, + const char *username, + unsigned int username_len, + unsigned char **signature, + unsigned long *signature_len) +{ + int sock; + unsigned char agbuf[4*1024]; + unsigned char xxx[1024]; + unsigned char *p; + int len; + char *pub_key; + int pub_key_len; + int pub_key_cnt; + + /*libssh2_trace(session, 0xFFFFFFFF);*/ + + if (session->agent_state == libssh2_NB_state_idle) { + sock = get_agent_socket(session); + if (sock < 0) + return -1; + session->agent_state = libssh2_NB_state_created; + } + + /* Get public keys from agent. */ + if (session->agent_state == libssh2_NB_state_created) { + memset(agbuf, 0, sizeof(agbuf)); + libssh2_htonu32(agbuf, 1); + agbuf[4] = SSH2_AGENTC_REQUEST_IDENTITIES; + write(sock, agbuf, 5); + session->agent_state = libssh2_NB_state_sent1; + } + + if (session->agent_state == libssh2_NB_state_sent1) { + read(sock, agbuf, 4); + len = libssh2_ntohu32(agbuf); + read(sock, agbuf, len); + + debugdump(session, "pubkey from agent", agbuf, len); + + if (agbuf[0] != SSH2_AGENT_IDENTITIES_ANSWER) { + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Bad authentication reply message type: %d", agbuf[0]); + return -1; + } + pub_key_cnt = libssh2_ntohu32(agbuf+1); + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "found %d keys", pub_key_cnt); + if (pub_key_cnt == 0) { + /* No key found. */ + return -1; + } + pub_key_len = libssh2_ntohu32(agbuf+5); + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "pub_key_len %d", pub_key_len); + pub_key = LIBSSH2_ALLOC(session, pub_key_len); + memcpy(pub_key, agbuf+9, pub_key_len); + + /* Sign */ + agbuf[0] = SSH_AGENTC_SIGN_REQUEST; + p = agbuf + 1; + + libssh2_htonu32(p, pub_key_len); + p += 4; + libssh2_htonu32(p, session->userauth_pblc_method_len); + p += 4; + memcpy(p, session->userauth_pblc_method, session->userauth_pblc_method_len); + p += session->userauth_pblc_method_len; + memcpy(p, pub_key+11, pub_key_len-11); + p += pub_key_len-11; + + len = 4 + session->session_id_len + 1 + 4 + username_len + + 4 + strlen("ssh-connection") + 4 + strlen("publickey") + + 1 + 4 + session->userauth_pblc_method_len + + 4 + pub_key_len - 11 + 4 + session->userauth_pblc_method_len; + + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "len: %d", len); + + libssh2_htonu32(p, len); + p += 4; + + libssh2_htonu32(p, session->session_id_len); + p += 4; + memcpy(p, session->session_id, session->session_id_len); + p += session->session_id_len; + + *p = SSH_MSG_USERAUTH_REQUEST; + p++; + + libssh2_htonu32(p, username_len); + p += 4; + memcpy(p, username, username_len); + p += username_len; + libssh2_htonu32(p, strlen("ssh-connection")); + p += 4; + memcpy(p, "ssh-connection", strlen("ssh-connection")); + p += strlen("ssh-connection"); + libssh2_htonu32(p, strlen("publickey")); + p += 4; + memcpy(p, "publickey", strlen("publickey")); + p += strlen("publickey"); + *p = 1; + p += 1; + + libssh2_htonu32(p, session->userauth_pblc_method_len); + p += 4; + memcpy(p, session->userauth_pblc_method, session->userauth_pblc_method_len); + p += session->userauth_pblc_method_len; + + libssh2_htonu32(p, pub_key_len); + p += 4; + libssh2_htonu32(p, session->userauth_pblc_method_len); + p += 4; + memcpy(p, session->userauth_pblc_method, session->userauth_pblc_method_len); + p += session->userauth_pblc_method_len; + memcpy(p, pub_key+11, pub_key_len-11); + p += pub_key_len-11; + + /* Flags. */ + libssh2_htonu32(p, 0); + p += 4; + + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "len = %d", p - agbuf); + libssh2_htonu32(xxx, p - agbuf); + write(sock, xxx, 4); + + len = write(sock, agbuf, p - agbuf); + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "ret: %d, len: %d", len, p - agbuf); + session->agent_state = libssh2_NB_state_sent2; + } + + if (session->agent_state = libssh2_NB_state_sent2) { + read(sock, agbuf, 4); + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "%02X %02X %02X %02X", + agbuf[0], agbuf[1], agbuf[2], agbuf[3]); + len = libssh2_ntohu32(agbuf); + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "ret len: %d", len); + read(sock, agbuf, len); + if (agbuf[0] != SSH2_AGENT_SIGN_RESPONSE) { + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Agent admitted failure to sign using the key."); + return -1; + } + + debugdump(session, "response", agbuf, len); + + if (memcmp(session->userauth_pblc_method, "ssh-dss", session->userauth_pblc_method_len) == 0) + *signature_len = 40; + else + *signature_len = 256; + _libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "sign_len: %ld", *signature_len); + *signature = LIBSSH2_ALLOC(session, *signature_len); + if (!*signature) { + return -1; + } + + memcpy(*signature, agbuf+20, *signature_len); + close(sock); + LIBSSH2_FREE(session, pub_key); + + libssh2_trace(session, 0); + return 0; + } + return 0; +} + diff -Naurw libssh2-0.18.orig/src/libssh2_priv.h libssh2-0.18.agent/src/libssh2_priv.h --- libssh2-0.18.orig/src/libssh2_priv.h 2007-08-11 02:30:30.000000000 +0400 +++ libssh2-0.18.agent/src/libssh2_priv.h 2008-01-11 16:23:26.000000000 +0300 @@ -827,6 +827,13 @@ char *scpSend_err_msg; long scpSend_err_len; LIBSSH2_CHANNEL *scpSend_channel; + + /* State variable for last IO operation */ + int lastIO_state; + + /* State variables used in libssh2_userauth_sign_with_agent */ + libssh2_nonblocking_states agent_state; + }; /* session.state bits */ @@ -1061,8 +1068,14 @@ void libssh2_htonu32(unsigned char *buf, unsigned long val); void libssh2_htonu64(unsigned char *buf, libssh2_uint64_t val); +#if 1 #define LIBSSH2_READ_TIMEOUT 60 /* generic timeout in seconds used when waiting for more data to arrive */ +#else +/* rushba */ +#define LIBSSH2_READ_TIMEOUT 10 /* generic timeout in seconds used when + waiting for more data to arrive */ +#endif int libssh2_waitsocket(LIBSSH2_SESSION * session, long seconds); diff -Naurw libssh2-0.18.orig/src/session.c libssh2-0.18.agent/src/session.c --- libssh2-0.18.orig/src/session.c 2007-11-08 18:11:33.000000000 +0300 +++ libssh2-0.18.agent/src/session.c 2007-12-26 12:36:22.000000000 +0300 @@ -110,6 +110,7 @@ ret = recv(session->socket_fd, &c, 1, LIBSSH2_SOCKET_RECV_FLAGS(session)); + session->lastIO_state = LIBSSH2_LAST_IO_RECV; if (ret < 0) { #ifdef WIN32 @@ -231,6 +232,7 @@ send(session->socket_fd, banner + session->banner_TxRx_total_send, banner_len - session->banner_TxRx_total_send, LIBSSH2_SOCKET_SEND_FLAGS(session)); + session->lastIO_state = LIBSSH2_LAST_IO_SEND; if (ret != (banner_len - session->banner_TxRx_total_send)) { if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) { @@ -1115,6 +1117,17 @@ /* }}} */ +/* {{{ libssh2_session_last_io +* Returns last IO operation +*/ +LIBSSH2_API int +libssh2_session_last_io(LIBSSH2_SESSION * session) +{ + return session->lastIO_state; +} + +/* }}} */ + /* {{{ libssh2_session_flag * Set/Get session flags * Passing flag==0 will avoid changing session->flags while still returning its current value diff -Naurw libssh2-0.18.orig/src/transport.c libssh2-0.18.agent/src/transport.c --- libssh2-0.18.orig/src/transport.c 2007-11-08 18:11:33.000000000 +0300 +++ libssh2-0.18.agent/src/transport.c 2007-12-26 12:49:20.000000000 +0300 @@ -327,6 +327,7 @@ recv(session->socket_fd, &p->buf[remainbuf], PACKETBUFSIZE - remainbuf, LIBSSH2_SOCKET_RECV_FLAGS(session)); + session->lastIO_state = LIBSSH2_LAST_IO_RECV; if (nread <= 0) { /* check if this is due to EAGAIN and return the special return code if so, error out normally otherwise */ @@ -575,6 +576,7 @@ rc = send(session->socket_fd, &p->outbuf[p->osent], length, LIBSSH2_SOCKET_SEND_FLAGS(session)); + session->lastIO_state = LIBSSH2_LAST_IO_SEND; if (rc == length) { /* the remainder of the package was sent */ @@ -732,6 +734,7 @@ ret = send(session->socket_fd, p->outbuf, total_length, LIBSSH2_SOCKET_SEND_FLAGS(session)); + session->lastIO_state = LIBSSH2_LAST_IO_SEND; if (ret != -1) { debugdump(session, "libssh2_packet_write send()", p->outbuf, ret); diff -Naurw libssh2-0.18.orig/src/userauth.c libssh2-0.18.agent/src/userauth.c --- libssh2-0.18.orig/src/userauth.c 2007-08-07 00:41:31.000000000 +0400 +++ libssh2-0.18.agent/src/userauth.c 2007-12-25 19:15:03.000000000 +0300 @@ -810,7 +810,6 @@ } /* }}} */ - /* {{{ libssh2_userauth_publickey_fromfile_ex * Authenticate using a keypair found in the named files */ @@ -986,6 +985,7 @@ LIBSSH2_FREE(session, session->userauth_pblc_data); session->userauth_pblc_data = NULL; + if (privatekey != NULL) { /* rushba */ if (libssh2_file_read_privatekey (session, &privkeyobj, &abstract, session->userauth_pblc_method, session->userauth_pblc_method_len, privatekey, passphrase)) { @@ -1022,6 +1022,17 @@ if (privkeyobj->dtor) { privkeyobj->dtor(session, &abstract); } + } else { /* rushba */ + /* Getting sig from agent. */ + int ret; + ret = libssh2_userauth_sign_with_agent(session, + username, username_len, + &sig, &sig_len); + if (ret == -1) { + session->userauth_pblc_state = libssh2_NB_state_idle; + return -1; + } + } if (sig_len > pubkeydata_len) { unsigned char *newpacket; diff -Naurw libssh2-0.18.orig/src/Makefile.am libssh2-0.18.agent/src/Makefile.am --- libssh2-0.18.orig/src/Makefile.am 2007-07-29 02:59:21.000000000 +0400 +++ libssh2-0.18.agent/src/Makefile.am 2007-12-25 19:15:03.000000000 +0300 @@ -3,7 +3,7 @@ libssh2_la_SOURCES = channel.c comp.c crypt.c hostkey.c kex.c mac.c \ misc.c packet.c publickey.c scp.c session.c sftp.c userauth.c \ -libssh2_priv.h openssl.h libgcrypt.h pem.c transport.c +libssh2_priv.h openssl.h libgcrypt.h pem.c transport.c agent.c if LIBGCRYPT libssh2_la_SOURCES += libgcrypt.c