summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAris Adamantiadis <aris@0xbadc0de.be>2009-08-23 16:41:29 +0200
committerAris Adamantiadis <aris@0xbadc0de.be>2009-08-23 16:41:29 +0200
commitd4bc6fa954f11b1da0c8881c2826ac4a60f8c41e (patch)
treec24b7b1ec877a102b86a3af47e01bf40e04cb4ac
parent8bae43876fff891e33d48b177778ee4cb882c45a (diff)
parentfbfea94559aa776bca7983ef989d024c2d3b72fe (diff)
downloadlibssh-d4bc6fa954f11b1da0c8881c2826ac4a60f8c41e.tar.gz
libssh-d4bc6fa954f11b1da0c8881c2826ac4a60f8c41e.tar.xz
libssh-d4bc6fa954f11b1da0c8881c2826ac4a60f8c41e.zip
Merge branch 'master' of git://git.libssh.org/projects/libssh/libssh
Conflicts: include/libssh/priv.h
-rw-r--r--ConfigureChecks.cmake43
-rw-r--r--cmake/Modules/FindOpenSSL.cmake1
-rw-r--r--config.h.cmake3
-rw-r--r--include/libssh/libssh.h18
-rw-r--r--include/libssh/priv.h24
-rwxr-xr-xinclude/wspiapi.h999
-rw-r--r--libssh/CMakeLists.txt8
-rw-r--r--libssh/channels.c213
-rw-r--r--libssh/connect.c18
-rw-r--r--libssh/keys.c1
-rw-r--r--libssh/misc.c108
-rw-r--r--libssh/packet.c1
-rw-r--r--libssh/scp.c81
-rw-r--r--libssh/sftp.c56
-rw-r--r--sample.c44
15 files changed, 523 insertions, 1095 deletions
diff --git a/ConfigureChecks.cmake b/ConfigureChecks.cmake
index 3a98758..93e3c1a 100644
--- a/ConfigureChecks.cmake
+++ b/ConfigureChecks.cmake
@@ -23,6 +23,19 @@ endif(CMAKE_COMPILER_IS_GNUC)
# HEADER FILES
check_include_file(pty.h HAVE_PTY_H)
check_include_file(terminos.h HAVE_TERMIOS_H)
+if (WIN32)
+ check_include_file(wspiapi.h HAVE_WSPIAPI_H)
+ if (NOT HAVE_WSPIAPI_H)
+ message(STATUS "WARNING: Without wspiapi.h, this build will only work on Windows XP and newer versions")
+ endif (NOT HAVE_WSPIAPI_H)
+ check_include_file(ws2tcpip.h HAVE_WS2TCPIP_H)
+ if (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
+ set(HAVE_GETADDRINFO TRUE)
+ set(HAVE_GETHOSTBYNAME TRUE)
+ endif (HAVE_WSPIAPI_H OR HAVE_WS2TCPIP_H)
+
+ set(HAVE_SELECT TRUE)
+endif (WIN32)
set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
check_include_file(openssl/aes.h HAVE_OPENSSL_AES_H)
@@ -32,26 +45,26 @@ set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIRS})
check_include_file(openssl/des.h HAVE_OPENSSL_DES_H)
# FUNCTIONS
-check_function_exists(cfmakeraw HAVE_CFMAKERAW)
-if (WIN32)
- set(HAVE_GETADDRINFO TRUE)
- set(HAVE_GETHOSTBYNAME TRUE)
- set(HAVE_SELECT TRUE)
-else (WIN32)
+
+if (UNIX)
+ # libsocket (Solaris)
+ check_library_exists(socket getaddrinfo "" HAVE_LIBSOCKET)
+ if (HAVE_LIBSOCKET)
+ set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} socket)
+ endif (HAVE_LIBSOCKET)
+ # libnsl (Solaris)
+ check_library_exists(nsl gethostbyname "" HAVE_LIBNSL)
+ if (HAVE_LIBNSL)
+ set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} nsl)
+ endif (HAVE_LIBNSL)
+
check_function_exists(getaddrinfo HAVE_GETADDRINFO)
- if (NOT HAVE_GETADDRINFO)
- check_library_exists("socket" "getaddrinfo" "" HAVE_LIB_GETADDRINFO)
- set(HAVE_GETADDRINFO 1)
- endif (NOT HAVE_GETADDRINFO)
check_function_exists(gethostbyname HAVE_GETHOSTBYNAME)
- if (NOT HAVE_GETHOSTBYNAME)
- check_library_exists("nsl" "gethostbyname" "" HAVE_LIB_GETHOSTBYNAME)
- set(HAVE_GETHOSTBYNAME 1)
- endif (NOT HAVE_GETHOSTBYNAME)
check_function_exists(poll HAVE_POLL)
check_function_exists(select HAVE_SELECT)
+ check_function_exists(cfmakeraw HAVE_CFMAKERAW)
check_function_exists(regcomp HAVE_REGCOMP)
-endif (WIN32)
+endif (UNIX)
# LIBRARIES
if (CRYPTO_FOUND)
diff --git a/cmake/Modules/FindOpenSSL.cmake b/cmake/Modules/FindOpenSSL.cmake
index c74ea48..bc40706 100644
--- a/cmake/Modules/FindOpenSSL.cmake
+++ b/cmake/Modules/FindOpenSSL.cmake
@@ -40,6 +40,7 @@ else (OPENSSL_LIBRARIES AND OPENSSL_INCLUDE_DIRS)
/usr/local/ssl/include
/opt/local/include
/sw/include
+ /usr/lib/sfw/include
)
mark_as_advanced(OPENSSL_INCLUDE_DIR)
diff --git a/config.h.cmake b/config.h.cmake
index ad97b11..f905958 100644
--- a/config.h.cmake
+++ b/config.h.cmake
@@ -23,6 +23,9 @@
/* Define to 1 if you have the <openssl/aes.h> header file. */
#cmakedefine HAVE_OPENSSL_AES_H 1
+/* Define to 1 if you have the <wspiapi.h> header file. */
+#cmakedefine HAVE_WSPIAPI_H 1
+
/* Define to 1 if you have the <openssl/blowfish.h> header file. */
#cmakedefine HAVE_OPENSSL_BLOWFISH_H 1
diff --git a/include/libssh/libssh.h b/include/libssh/libssh.h
index e544787..466fb5f 100644
--- a/include/libssh/libssh.h
+++ b/include/libssh/libssh.h
@@ -120,6 +120,7 @@ typedef struct ssh_agent_struct* ssh_agent;
typedef struct ssh_session_struct* ssh_session;
typedef struct ssh_kbdint_struct* ssh_kbdint;
typedef struct ssh_scp_struct* ssh_scp;
+typedef struct ssh_scp_request_struct* ssh_scp_request;
/* Socket type */
#ifdef _WIN32
@@ -336,6 +337,9 @@ LIBSSH_API int channel_request_sftp(ssh_channel channel);
LIBSSH_API int channel_request_x11(ssh_channel channel, int single_connection, const char *protocol,
const char *cookie, int screen_number);
LIBSSH_API ssh_channel channel_accept_x11(ssh_channel channel, int timeout_ms);
+LIBSSH_API int channel_forward_listen(ssh_session session, const char *address, int port, int *bound_port);
+LIBSSH_API ssh_channel channel_forward_accept(ssh_session session, int timeout_ms);
+LIBSSH_API int channel_forward_cancel(ssh_session session, const char *address, int port);
LIBSSH_API int channel_write(ssh_channel channel, const void *data, uint32_t len);
LIBSSH_API int channel_send_eof(ssh_channel channel);
LIBSSH_API int channel_is_eof(ssh_channel channel);
@@ -440,6 +444,10 @@ LIBSSH_API int ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int
LIBSSH_API int ssh_init(void);
LIBSSH_API int ssh_finalize(void);
+/* misc.c */
+LIBSSH_API char *ssh_dirname (const char *path);
+LIBSSH_API char *ssh_basename (const char *path);
+
/* messages.c */
typedef struct ssh_message_struct SSH_MESSAGE;
typedef struct ssh_message_struct *ssh_message;
@@ -461,12 +469,22 @@ enum {
SSH_SCP_READ
};
+enum ssh_scp_request_types {
+ /** A new directory is going to be pulled */
+ SSH_SCP_REQUEST_NEWDIR,
+ /** A new file is going to be pulled */
+ SSH_SCP_REQUEST_NEWFILE
+};
LIBSSH_API ssh_scp ssh_scp_new(ssh_session session, int mode, const char *location);
LIBSSH_API int ssh_scp_init(ssh_scp scp);
LIBSSH_API int ssh_scp_close(ssh_scp scp);
LIBSSH_API void ssh_scp_free(ssh_scp scp);
+LIBSSH_API int ssh_scp_push_directory(ssh_scp scp, const char *dirname, const char *perms);
+LIBSSH_API int ssh_scp_leave_directory(ssh_scp scp);
LIBSSH_API int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, const char *perms);
LIBSSH_API int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len);
+LIBSSH_API ssh_scp_request ssh_scp_pull_request(ssh_scp scp);
+LIBSSH_API int ssh_scp_deny_request(ssh_scp scp, ssh_scp_request request, const char *reason);
#ifdef __cplusplus
}
diff --git a/include/libssh/priv.h b/include/libssh/priv.h
index bf348d4..1cb3f64 100644
--- a/include/libssh/priv.h
+++ b/include/libssh/priv.h
@@ -32,19 +32,16 @@
#ifdef _MSC_VER
#define snprintf _snprintf
+/** Imitate define of inttypes.h */
+#define PRIdS "Id"
#else
#include <unistd.h>
+#define PRIdS "zd"
#endif
#include "config.h"
#include "libssh/libssh.h"
-/* Debugging constants */
-
-/* Define this if you want to debug crypto systems */
-/* it's usefull when you are debugging the lib */
-/*#define DEBUG_CRYPTO */
-
/* some constants */
#define MAX_PACKET_LEN 262144
#define ERROR_BUFFERLEN 1024
@@ -362,6 +359,7 @@ enum ssh_scp_states {
SSH_SCP_READ_READING, //File is opened and reading
SSH_SCP_ERROR //Something bad happened
};
+
struct ssh_scp_struct {
ssh_session session;
int mode;
@@ -372,6 +370,16 @@ struct ssh_scp_struct {
size_t processed;
};
+
+struct ssh_scp_request_struct {
+ ssh_scp scp;
+ enum ssh_scp_request_types type;
+ char *name;
+ char *mode;
+ size_t size;
+ int acked;
+};
+
struct ssh_message_struct;
struct ssh_session_struct {
@@ -860,6 +868,10 @@ int match_hostname(const char *host, const char *pattern, unsigned int len);
void message_handle(SSH_SESSION *session, uint32_t type);
int ssh_execute_message_callbacks(SSH_SESSION *session);
+/* scp.c */
+
+ssh_scp_request ssh_scp_request_new(void);
+
/* log.c */
#ifndef __FUNCTION__
diff --git a/include/wspiapi.h b/include/wspiapi.h
deleted file mode 100755
index eaa4ec2..0000000
--- a/include/wspiapi.h
+++ /dev/null
@@ -1,999 +0,0 @@
-/*++
-
-Copyright (c) 2000, Microsoft Corporation
-
-Module Name:
- wspiapi.h
-
-Abstract:
- The file contains protocol independent API functions.
-
-Revision History:
- Wed Jul 12 10:50:31 2000, Created
-
---*/
-
-#ifndef _WSPIAPI_H_
-#define _WSPIAPI_H_
-
-#include <stdio.h> // sprintf()
-#include <stdlib.h> // calloc(), strtoul()
-#include <malloc.h> // calloc()
-#include <string.h> // strlen(), strcmp(), strstr()
-
-#define WspiapiMalloc(tSize) calloc(1, (tSize))
-#define WspiapiFree(p) free(p)
-#define WspiapiSwap(a, b, c) { (c) = (a); (a) = (b); (b) = (c); }
-#define getaddrinfo WspiapiGetAddrInfo
-#define getnameinfo WspiapiGetNameInfo
-#define freeaddrinfo WspiapiFreeAddrInfo
-
-typedef int (WINAPI *WSPIAPI_PGETADDRINFO) (
- IN const char *nodename,
- IN const char *servname,
- IN const struct addrinfo *hints,
- OUT struct addrinfo **res);
-
-typedef int (WINAPI *WSPIAPI_PGETNAMEINFO) (
- IN const struct sockaddr *sa,
- IN socklen_t salen,
- OUT char *host,
- IN size_t hostlen,
- OUT char *serv,
- IN size_t servlen,
- IN int flags);
-
-typedef void (WINAPI *WSPIAPI_PFREEADDRINFO) (
- IN struct addrinfo *ai);
-
-
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-////////////////////////////////////////////////////////////
-// v4 only versions of getaddrinfo and friends.
-// NOTE: gai_strerror is inlined in ws2tcpip.h
-////////////////////////////////////////////////////////////
-
-__inline
-char *
-WINAPI
-WspiapiStrdup (
- IN const char * pszString)
-/*++
-
-Routine Description
- allocates enough storage via calloc() for a copy of the string,
- copies the string into the new memory, and returns a pointer to it.
-
-Arguments
- pszString string to copy into new memory
-
-Return Value
- a pointer to the newly allocated storage with the string in it.
- NULL if enough memory could not be allocated, or string was NULL.
-
---*/
-{
- char *pszMemory;
-
- if (!pszString)
- return(NULL);
-
- pszMemory = (char *) WspiapiMalloc(strlen(pszString) + 1);
- if (!pszMemory)
- return(NULL);
-
- return(strcpy(pszMemory, pszString));
-}
-
-
-
-__inline
-BOOL
-WINAPI
-WspiapiParseV4Address (
- IN const char * pszAddress,
- OUT PDWORD pdwAddress)
-/*++
-
-Routine Description
- get the IPv4 address (in network byte order) from its string
- representation. the syntax should be a.b.c.d.
-
-Arguments
- pszArgument string representation of the IPv4 address
- ptAddress pointer to the resulting IPv4 address
-
-Return Value
- Returns FALSE if there is an error, TRUE for success.
-
---*/
-{
- DWORD dwAddress = 0;
- const char *pcNext = NULL;
- int iCount = 0;
-
- // ensure there are 3 '.' (periods)
- for (pcNext = pszAddress; *pcNext != '\0'; pcNext++)
- if (*pcNext == '.')
- iCount++;
- if (iCount != 3)
- return FALSE;
-
- // return an error if dwAddress is INADDR_NONE (255.255.255.255)
- // since this is never a valid argument to getaddrinfo.
- dwAddress = inet_addr(pszAddress);
- if (dwAddress == INADDR_NONE)
- return FALSE;
-
- *pdwAddress = dwAddress;
- return TRUE;
-}
-
-
-
-__inline
-struct addrinfo *
-WINAPI
-WspiapiNewAddrInfo (
- IN int iSocketType,
- IN int iProtocol,
- IN WORD wPort,
- IN DWORD dwAddress)
-/*++
-
-Routine Description
- allocate an addrinfo structure and populate fields.
- IPv4 specific internal function, not exported.
-
-Arguments
- iSocketType SOCK_*. can be wildcarded (zero).
- iProtocol IPPROTO_*. can be wildcarded (zero).
- wPort port number of service (in network order).
- dwAddress IPv4 address (in network order).
-
-Return Value
- returns an addrinfo struct, or NULL if out of memory.
-
---*/
-{
- struct addrinfo *ptNew;
- struct sockaddr_in *ptAddress;
-
- // allocate a new addrinfo structure.
- ptNew =
- (struct addrinfo *) WspiapiMalloc(sizeof(struct addrinfo));
- if (!ptNew)
- return NULL;
-
- ptAddress =
- (struct sockaddr_in *) WspiapiMalloc(sizeof(struct sockaddr_in));
- if (!ptAddress)
- {
- WspiapiFree(ptNew);
- return NULL;
- }
- ptAddress->sin_family = AF_INET;
- ptAddress->sin_port = wPort;
- ptAddress->sin_addr.s_addr = dwAddress;
-
- // fill in the fields...
- ptNew->ai_family = PF_INET;
- ptNew->ai_socktype = iSocketType;
- ptNew->ai_protocol = iProtocol;
- ptNew->ai_addrlen = sizeof(struct sockaddr_in);
- ptNew->ai_addr = (struct sockaddr *) ptAddress;
-
- return ptNew;
-}
-
-
-
-__inline
-int
-WINAPI
-WspiapiQueryDNS(
- IN const char *pszNodeName,
- IN int iSocketType,
- IN int iProtocol,
- IN WORD wPort,
- OUT char *pszAlias,
- OUT struct addrinfo **pptResult)
-/*++
-
-Routine Description
- helper routine for WspiapiLookupNode.
- performs name resolution by querying the DNS for A records.
- *pptResult would need to be freed if an error is returned.
-
-Arguments
- pszNodeName name of node to resolve.
- iSocketType SOCK_*. can be wildcarded (zero).
- iProtocol IPPROTO_*. can be wildcarded (zero).
- wPort port number of service (in network order).
- pszAlias where to return the alias.
- pptResult where to return the result.
-
-Return Value
- Returns 0 on success, an EAI_* style error value otherwise.
-
---*/
-{
- struct addrinfo **pptNext = pptResult;
- struct hostent *ptHost = NULL;
- char **ppAddresses;
-
- *pptNext = NULL;
- pszAlias[0] = '\0';
-
- ptHost = gethostbyname(pszNodeName);
- if (ptHost)
- {
- if ((ptHost->h_addrtype == AF_INET) &&
- (ptHost->h_length == sizeof(struct in_addr)))
- {
- for (ppAddresses = ptHost->h_addr_list;
- *ppAddresses != NULL;
- ppAddresses++)
- {
- // create an addrinfo structure...
- *pptNext = WspiapiNewAddrInfo(
- iSocketType,
- iProtocol,
- wPort,
- ((struct in_addr *) *ppAddresses)->s_addr);
- if (!*pptNext)
- return EAI_MEMORY;
-
- pptNext = &((*pptNext)->ai_next);
- }
- }
-
- // pick up the canonical name.
- strcpy(pszAlias, ptHost->h_name);
- return 0;
- }
-
- switch (WSAGetLastError())
- {
- case WSAHOST_NOT_FOUND: return EAI_NONAME;
- case WSATRY_AGAIN: return EAI_AGAIN;
- case WSANO_RECOVERY: return EAI_FAIL;
- case WSANO_DATA: return EAI_NODATA;
- default: return EAI_NONAME;
- }
-}
-
-
-
-__inline
-int
-WINAPI
-WspiapiLookupNode(
- IN const char *pszNodeName,
- IN int iSocketType,
- IN int iProtocol,
- IN WORD wPort,
- IN BOOL bAI_CANONNAME,
- OUT struct addrinfo **pptResult)
-/*++
-
-Routine Description
- resolve a nodename and return a list of addrinfo structures.
- IPv4 specific internal function, not exported.
- *pptResult would need to be freed if an error is returned.
-
- NOTE: if bAI_CANONNAME is true, the canonical name should be
- returned in the first addrinfo structure.
-
-Arguments
- pszNodeName name of node to resolve.
- iSocketType SOCK_*. can be wildcarded (zero).
- iProtocol IPPROTO_*. can be wildcarded (zero).
- wPort port number of service (in network order).
- bAI_CANONNAME whether the AI_CANONNAME flag is set.
- pptResult where to return result.
-
-Return Value
- Returns 0 on success, an EAI_* style error value otherwise.
-
---*/
-{
- int iError = 0;
- int iAliasCount = 0;
-
- char szFQDN1[NI_MAXHOST] = "";
- char szFQDN2[NI_MAXHOST] = "";
- char *pszName = szFQDN1;
- char *pszAlias = szFQDN2;
- char *pszScratch = NULL;
- strcpy(pszName, pszNodeName);
-
- for (;;)
- {
- iError = WspiapiQueryDNS(pszNodeName,
- iSocketType,
- iProtocol,
- wPort,
- pszAlias,
- pptResult);
- if (iError)
- break;
-
- // if we found addresses, then we are done.
- if (*pptResult)
- break;
-
- // stop infinite loops due to DNS misconfiguration. there appears
- // to be no particular recommended limit in RFCs 1034 and 1035.
- if ((!strlen(pszAlias)) ||
- (!strcmp(pszName, pszAlias)) ||
- (++iAliasCount == 16))
- {
- iError = EAI_FAIL;
- break;
- }
-
- // there was a new CNAME, look again.
- WspiapiSwap(pszName, pszAlias, pszScratch);
- }
-
- if (!iError && bAI_CANONNAME)
- {
- (*pptResult)->ai_canonname = WspiapiStrdup(pszAlias);
- if (!(*pptResult)->ai_canonname)
- iError = EAI_MEMORY;
- }
-
- return iError;
-}
-
-
-
-__inline
-int
-WINAPI
-WspiapiClone (
- IN WORD wPort,
- IN struct addrinfo *ptResult)
-/*++
-
-Routine Description
- clone every addrinfo structure in ptResult for the UDP service.
- ptResult would need to be freed if an error is returned.
-
-Arguments
- wPort port number of UDP service.
- ptResult list of addrinfo structures, each
- of whose node needs to be cloned.
-
-Return Value
- Returns 0 on success, an EAI_MEMORY on allocation failure.
-
---*/
-{
- struct addrinfo *ptNext = NULL;
- struct addrinfo *ptNew = NULL;
-
- for (ptNext = ptResult; ptNext != NULL; )
- {
- // create an addrinfo structure...
- ptNew = WspiapiNewAddrInfo(
- SOCK_DGRAM,
- ptNext->ai_protocol,
- wPort,
- ((struct sockaddr_in *) ptNext->ai_addr)->sin_addr.s_addr);
- if (!ptNew)
- break;
-
- // link the cloned addrinfo
- ptNew->ai_next = ptNext->ai_next;
- ptNext->ai_next = ptNew;
- ptNext = ptNew->ai_next;
- }
-
- if (ptNext != NULL)
- return EAI_MEMORY;
-
- return 0;
-}
-
-
-
-__inline
-void
-WINAPI
-WspiapiLegacyFreeAddrInfo (
- IN struct addrinfo *ptHead)
-/*++
-
-Routine Description
- Free an addrinfo structure (or chain of structures).
- As specified in RFC 2553, Section 6.4.
-
-Arguments
- ptHead structure (chain) to free
-
---*/
-{
- struct addrinfo *ptNext; // next strcture to free
-
- for (ptNext = ptHead; ptNext != NULL; ptNext = ptHead)
- {
- if (ptNext->ai_canonname)
- WspiapiFree(ptNext->ai_canonname);
-
- if (ptNext->ai_addr)
- WspiapiFree(ptNext->ai_addr);
-
- ptHead = ptNext->ai_next;
- WspiapiFree(ptNext);
- }
-}
-
-
-
-__inline
-int
-WINAPI
-WspiapiLegacyGetAddrInfo(
- IN const char *pszNodeName,
- IN const char *pszServiceName,
- IN const struct addrinfo *ptHints,
- OUT struct addrinfo **pptResult)
-/*++
-
-Routine Description
- Protocol-independent name-to-address translation.
- As specified in RFC 2553, Section 6.4.
- This is the hacked version that only supports IPv4.
-
-Arguments
- pszNodeName node name to lookup.
- pszServiceName service name to lookup.
- ptHints hints about how to process request.
- pptResult where to return result.
-
-Return Value
- returns zero if successful, an EAI_* error code if not.
-
---*/
-{
- int iError = 0;
- int iFlags = 0;
- int iFamily = PF_UNSPEC;
- int iSocketType = 0;
- int iProtocol = 0;
- WORD wPort = 0;
- DWORD dwAddress = 0;
-
- struct servent *ptService = NULL;
- char *pc = NULL;
- BOOL bClone = FALSE;
- WORD wTcpPort = 0;
- WORD wUdpPort = 0;
-
-
- // initialize pptResult with default return value.
- *pptResult = NULL;
-
-
- ////////////////////////////////////////
- // validate arguments...
- //
-
- // both the node name and the service name can't be NULL.
- if ((!pszNodeName) && (!pszServiceName))
- return EAI_NONAME;
-
- // validate hints.
- if (ptHints)
- {
- // all members other than ai_flags, ai_family, ai_socktype
- // and ai_protocol must be zero or a null pointer.
- if ((ptHints->ai_addrlen != 0) ||
- (ptHints->ai_canonname != NULL) ||
- (ptHints->ai_addr != NULL) ||
- (ptHints->ai_next != NULL))
- {
- return EAI_FAIL;
- }
-
- // the spec has the "bad flags" error code, so presumably we
- // should check something here. insisting that there aren't
- // any unspecified flags set would break forward compatibility,
- // however. so we just check for non-sensical combinations.
- //
- // we cannot come up with a canonical name given a null node name.
- iFlags = ptHints->ai_flags;
- if ((iFlags & AI_CANONNAME) && !pszNodeName)
- return EAI_BADFLAGS;
-
- // we only support a limited number of protocol families.
- iFamily = ptHints->ai_family;
- if ((iFamily != PF_UNSPEC) && (iFamily != PF_INET))
- return EAI_FAMILY;
-
- // we only support only these socket types.
- iSocketType = ptHints->ai_socktype;
- if ((iSocketType != 0) &&
- (iSocketType != SOCK_STREAM) &&
- (iSocketType != SOCK_DGRAM) &&
- (iSocketType != SOCK_RAW))
- return EAI_SOCKTYPE;
-
- // REVIEW: What if ai_socktype and ai_protocol are at odds?
- iProtocol = ptHints->ai_protocol;
- }
-
-
- ////////////////////////////////////////
- // do service lookup...
-
- if (pszServiceName)
- {
- wPort = (WORD) strtoul(pszServiceName, &pc, 10);
- if (*pc == '\0') // numeric port string
- {
- wPort = wTcpPort = wUdpPort = htons(wPort);
- if (iSocketType == 0)
- {
- bClone = TRUE;
- iSocketType = SOCK_STREAM;
- }
- }
- else // non numeric port string
- {
- if ((iSocketType == 0) || (iSocketType == SOCK_DGRAM))
- {
- ptService = getservbyname(pszServiceName, "udp");
- if (ptService)
- wPort = wUdpPort = ptService->s_port;
- }
-
- if ((iSocketType == 0) || (iSocketType == SOCK_STREAM))
- {
- ptService = getservbyname(pszServiceName, "tcp");
- if (ptService)
- wPort = wTcpPort = ptService->s_port;
- }
-
- // assumes 0 is an invalid service port...
- if (wPort == 0) // no service exists
- return (iSocketType ? EAI_SERVICE : EAI_NONAME);
-
- if (iSocketType == 0)
- {
- // if both tcp and udp, process tcp now & clone udp later.
- iSocketType = (wTcpPort) ? SOCK_STREAM : SOCK_DGRAM;
- bClone = (wTcpPort && wUdpPort);
- }
- }
- }
-
-
-
- ////////////////////////////////////////
- // do node name lookup...
-
- // if we weren't given a node name,
- // return the wildcard or loopback address (depending on AI_PASSIVE).
- //
- // if we have a numeric host address string,
- // return the binary address.
- //
- if ((!pszNodeName) || (WspiapiParseV4Address(pszNodeName, &dwAddress)))
- {
- if (!pszNodeName)
- {
- dwAddress = htonl((iFlags & AI_PASSIVE)
- ? INADDR_ANY
- : INADDR_LOOPBACK);
- }
-
- // create an addrinfo structure...
- *pptResult =
- WspiapiNewAddrInfo(iSocketType, iProtocol, wPort, dwAddress);
- if (!(*pptResult))
- iError = EAI_MEMORY;
-
- if (!iError && pszNodeName)
- {
- // implementation specific behavior: set AI_NUMERICHOST
- // to indicate that we got a numeric host address string.
- (*pptResult)->ai_flags |= AI_NUMERICHOST;
-
- // return the numeric address string as the canonical name
- if (iFlags & AI_CANONNAME)
- {
- (*pptResult)->ai_canonname =
- WspiapiStrdup(inet_ntoa(*((struct in_addr *) &dwAddress)));
- if (!(*pptResult)->ai_canonname)
- iError = EAI_MEMORY;
- }
- }
- }
-
-
- // if we do not have a numeric host address string and
- // AI_NUMERICHOST flag is set, return an error!
- else if (iFlags & AI_NUMERICHOST)
- {
- iError = EAI_NONAME;
- }
-
-
- // since we have a non-numeric node name,
- // we have to do a regular node name lookup.
- else
- {
- iError = WspiapiLookupNode(pszNodeName,
- iSocketType,
- iProtocol,
- wPort,
- (iFlags & AI_CANONNAME),
- pptResult);
- }
-
- if (!iError && bClone)
- {
- iError = WspiapiClone(wUdpPort, *pptResult);
- }
-
- if (iError)
- {
- WspiapiLegacyFreeAddrInfo(*pptResult);
- *pptResult = NULL;
- }
-
- return (iError);
-}
-
-
-
-__inline
-int
-WINAPI
-WspiapiLegacyGetNameInfo(
- IN const struct sockaddr *ptSocketAddress,
- IN socklen_t tSocketLength,
- OUT char *pszNodeName,
- IN size_t tNodeLength,
- OUT char *pszServiceName,
- IN size_t tServiceLength,
- IN int iFlags)
-/*++
-
-Routine Description
- protocol-independent address-to-name translation.
- as specified in RFC 2553, Section 6.5.
- this is the hacked version that only supports IPv4.
-
-Arguments
- ptSocketAddress socket address to translate.
- tSocketLength length of above socket address.
- pszNodeName where to return the node name.
- tNodeLength size of above buffer.
- pszServiceName where to return the service name.
- tServiceLength size of above buffer.
- iFlags flags of type NI_*.
-
-Return Value
- returns zero if successful, an EAI_* error code if not.
-
---*/
-{
- struct servent *ptService;
- WORD wPort;
- char szBuffer[] = "65535";
- char *pszService = szBuffer;
-
- struct hostent *ptHost;
- struct in_addr tAddress;
- char *pszNode = NULL;
- char *pc = NULL;
-
-
- // sanity check ptSocketAddress and tSocketLength.
- if (!ptSocketAddress)
- return EAI_FAIL;
-
- if ((ptSocketAddress->sa_family != AF_INET) ||
- (tSocketLength != sizeof(struct sockaddr_in)))
- {
- return EAI_FAMILY;
- }
-
- if (!(pszNodeName && tNodeLength) &&
- !(pszServiceName && tServiceLength))
- {
- return EAI_NONAME;
- }
-
- // the draft has the "bad flags" error code, so presumably we
- // should check something here. insisting that there aren't
- // any unspecified flags set would break forward compatibility,
- // however. so we just check for non-sensical combinations.
- if ((iFlags & NI_NUMERICHOST) && (iFlags & NI_NAMEREQD))
- {
- return EAI_BADFLAGS;
- }
-
- // translate the port to a service name (if requested).
- if (pszServiceName && tServiceLength)
- {
- wPort = ((struct sockaddr_in *) ptSocketAddress)->sin_port;
-
- if (iFlags & NI_NUMERICSERV)
- {
- // return numeric form of the address.
- sprintf(szBuffer, "%u", ntohs(wPort));
- }
- else
- {
- // return service name corresponding to port.
- ptService = getservbyport(wPort,
- (iFlags & NI_DGRAM) ? "udp" : NULL);
- if (ptService && ptService->s_name)
- {
- // lookup successful.
- pszService = ptService->s_name;
- }
- else
- {
- // DRAFT: return numeric form of the port!
- sprintf(szBuffer, "%u", ntohs(wPort));
- }
- }
-
-
- if (tServiceLength > strlen(pszService))
- strcpy(pszServiceName, pszService);
- else
- return EAI_FAIL;
- }
-
-
- // translate the address to a node name (if requested).
- if (pszNodeName && tNodeLength)
- {
- // this is the IPv4-only version, so we have an IPv4 address.
- tAddress = ((struct sockaddr_in *) ptSocketAddress)->sin_addr;
-
- if (iFlags & NI_NUMERICHOST)
- {
- // return numeric form of the address.
- pszNode = inet_ntoa(tAddress);
- }
- else
- {
- // return node name corresponding to address.
- ptHost = gethostbyaddr((char *) &tAddress,
- sizeof(struct in_addr),
- AF_INET);
- if (ptHost && ptHost->h_name)
- {
- // DNS lookup successful.
- // stop copying at a "." if NI_NOFQDN is specified.
- pszNode = ptHost->h_name;
- if ((iFlags & NI_NOFQDN) && (pc = strchr(pszNode, '.')))
- *pc = '\0';
- }
- else
- {
- // DNS lookup failed. return numeric form of the address.
- if (iFlags & NI_NAMEREQD)
- {
- switch (WSAGetLastError())
- {
- case WSAHOST_NOT_FOUND: return EAI_NONAME;
- case WSATRY_AGAIN: return EAI_AGAIN;
- case WSANO_RECOVERY: return EAI_FAIL;
- default: return EAI_NONAME;
- }
- }
- else
- pszNode = inet_ntoa(tAddress);
- }
- }
-
- if (tNodeLength > strlen(pszNode))
- strcpy(pszNodeName, pszNode);
- else
- return EAI_FAIL;
- }
-
- return 0;
-}
-
-
-
-typedef struct
-{
- char const *pszName;
- FARPROC pfAddress;
-} WSPIAPI_FUNCTION;
-
-#define WSPIAPI_FUNCTION_ARRAY \
-{ \
- "getaddrinfo", (FARPROC) WspiapiLegacyGetAddrInfo, \
- "getnameinfo", (FARPROC) WspiapiLegacyGetNameInfo, \
- "freeaddrinfo", (FARPROC) WspiapiLegacyFreeAddrInfo, \
-}
-
-
-
-__inline
-FARPROC
-WINAPI
-WspiapiLoad(
- IN WORD wFunction)
-/*++
-
-Routine Description
- try to locate the address family independent name resolution routines
- (i.e. getaddrinfo, getnameinfo, freeaddrinfo, gai_strerror).
-
-Locks
- this function call is not synchronized. hence the library containing
- the routines might be loaded multiple times. another option is to
- synchronize through a spin lock using a static local variable and the
- InterlockedExchange operation.
-
-
-Arguments
- wFunction ordinal # of the function to get the pointer to
- 0 getaddrinfo
- 1 getnameinfo
- 2 freeaddrinfo
-
-Return Value
- address of the library/legacy routine
-
---*/
-{
- HMODULE hLibrary = NULL;
-
- // these static variables store state across calls, across threads.
- static BOOL bInitialized = FALSE;
- static WSPIAPI_FUNCTION rgtGlobal[] = WSPIAPI_FUNCTION_ARRAY;
- static const int iNumGlobal = (sizeof(rgtGlobal) /
- sizeof(WSPIAPI_FUNCTION));
-
- // we overwrite rgtGlobal only if all routines exist in library.
- WSPIAPI_FUNCTION rgtLocal[] = WSPIAPI_FUNCTION_ARRAY;
- FARPROC fScratch = NULL;
- int i = 0;
-
-
- if (bInitialized) // WspiapiLoad has already been called once
- return (rgtGlobal[wFunction].pfAddress);
-
- do // breakout loop
- {
- // in Whistler and beyond...
- // the routines are present in the WinSock 2 library (ws2_32.dll).
- // printf("Looking in ws2_32 for getaddrinfo...\n");
- hLibrary = LoadLibraryA("ws2_32");
- if (hLibrary != NULL)
- {
- fScratch = GetProcAddress(hLibrary, "getaddrinfo");
- if (fScratch == NULL)
- {
- FreeLibrary(hLibrary);
- hLibrary = NULL;
- }
- }
- if (hLibrary != NULL)
- break;
-
-
- // in the IPv6 Technology Preview...
- // the routines are present in the IPv6 WinSock library (wship6.dll).
- // printf("Looking in wship6 for getaddrinfo...\n");
- hLibrary = LoadLibraryA("wship6");
- if (hLibrary != NULL)
- {
- fScratch = GetProcAddress(hLibrary, "getaddrinfo");
- if (fScratch == NULL)
- {
- FreeLibrary(hLibrary);
- hLibrary = NULL;
- }
- }
- } while (FALSE);
-
-
- if (hLibrary != NULL)
- {
- // use routines from this library...
- // since getaddrinfo is here, we expect all routines to be here,
- // but will fall back to IPv4-only if any of them is missing.
- for (i = 0; i < iNumGlobal; i++)
- {
- rgtLocal[i].pfAddress
- = GetProcAddress(hLibrary, rgtLocal[i].pszName);
- if (rgtLocal[i].pfAddress == NULL)
- {
- FreeLibrary(hLibrary);
- hLibrary = NULL;
- break;
- }
- }
-
- if (hLibrary != NULL)
- {
- // printf("found!\n");
- for (i = 0; i < iNumGlobal; i++)
- rgtGlobal[i].pfAddress = rgtLocal[i].pfAddress;
- }
- }
-
- bInitialized = TRUE;
- return (rgtGlobal[wFunction].pfAddress);
-}
-
-
-
-__inline
-int
-WINAPI
-WspiapiGetAddrInfo(
- IN const char *nodename,
- IN const char *servname,
- IN const struct addrinfo *hints,
- OUT struct addrinfo **res)
-{
- static WSPIAPI_PGETADDRINFO pfGetAddrInfo = NULL;
-
- if (!pfGetAddrInfo)
- pfGetAddrInfo = (WSPIAPI_PGETADDRINFO) WspiapiLoad(0);
- return ((*pfGetAddrInfo)
- (nodename, servname, hints, res));
-}
-
-
-
-__inline
-int
-WINAPI
-WspiapiGetNameInfo (
- IN const struct sockaddr *sa,
- IN socklen_t salen,
- OUT char *host,
- IN size_t hostlen,
- OUT char *serv,
- IN size_t servlen,
- IN int flags)
-{
- static WSPIAPI_PGETNAMEINFO pfGetNameInfo = NULL;
-
- if (!pfGetNameInfo)
- pfGetNameInfo = (WSPIAPI_PGETNAMEINFO) WspiapiLoad(1);
- return ((*pfGetNameInfo)
- (sa, salen, host, hostlen, serv, servlen, flags));
-}
-
-
-
-__inline
-void
-WINAPI
-WspiapiFreeAddrInfo (
- IN struct addrinfo *ai)
-{
- static WSPIAPI_PFREEADDRINFO pfFreeAddrInfo = NULL;
-
- if (!pfFreeAddrInfo)
- pfFreeAddrInfo = (WSPIAPI_PFREEADDRINFO) WspiapiLoad(2);
- (*pfFreeAddrInfo)(ai);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // _WSPIAPI_H_
diff --git a/libssh/CMakeLists.txt b/libssh/CMakeLists.txt
index 2fc8adb..fc355bf 100644
--- a/libssh/CMakeLists.txt
+++ b/libssh/CMakeLists.txt
@@ -35,19 +35,19 @@ if (WIN32)
)
endif (WIN32)
-if (HAVE_LIB_GETHOSTBYNAME)
+if (HAVE_LIBNSL)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
nsl
)
-endif (HAVE_LIB_GETHOSTBYNAME)
+endif (HAVE_LIBNSL)
-if (HAVE_LIB_GETADDRINFO)
+if (HAVE_LIBSOCKET)
set(LIBSSH_LINK_LIBRARIES
${LIBSSH_LINK_LIBRARIES}
socket
)
-endif (HAVE_LIB_GETADDRINFO)
+endif (HAVE_LIBSOCKET)
if (CRYPTO_LIBRARY)
set(LIBSSH_PRIVATE_INCLUDE_DIRS
diff --git a/libssh/channels.c b/libssh/channels.c
index ac49b38..6e70285 100644
--- a/libssh/channels.c
+++ b/libssh/channels.c
@@ -1057,7 +1057,7 @@ static int channel_request(ssh_channel channel, const char *request,
}
rc = packet_wait(session, SSH2_MSG_CHANNEL_SUCCESS, 1);
- if (rc) {
+ if (rc == SSH_ERROR) {
if (session->in_packet.type == SSH2_MSG_CHANNEL_FAILURE) {
ssh_log(session, SSH_LOG_PACKET,
"%s channel request failed", request);
@@ -1335,19 +1335,14 @@ error:
return rc;
}
+static ssh_channel channel_accept(ssh_session session, int channeltype,
+ int timeout_ms) {
#ifndef _WIN32
-/**
- * @brief Accept an X11 forwarding channel.
- *
- * @param channel An x11-enabled session channel.
- *
- * @param timeout_ms Timeout in milli-seconds.
- *
- * @return Newly created channel, or NULL if no X11 request from the server
- */
-ssh_channel channel_accept_x11(ssh_channel channel, int timeout_ms) {
- static const struct timespec ts = {0, 50000000}; /* 50ms */
- SSH_SESSION *session = channel->session;
+ static const struct timespec ts = {
+ .tv_sec = 0,
+ .tv_nsec = 50000000 /* 50ms */
+ };
+#endif
SSH_MESSAGE *msg = NULL;
struct ssh_iterator *iterator;
int t;
@@ -1361,19 +1356,207 @@ ssh_channel channel_accept_x11(ssh_channel channel, int timeout_ms) {
while (iterator) {
msg = (SSH_MESSAGE*)iterator->data;
if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL_OPEN &&
- ssh_message_subtype(msg) == SSH_CHANNEL_X11) {
+ ssh_message_subtype(msg) == channeltype) {
ssh_list_remove(session->ssh_message_list, iterator);
return ssh_message_channel_request_open_reply_accept(msg);
}
iterator = iterator->next;
}
}
+#ifdef _WIN32
+ Sleep(50); /* 50ms */
+#else
nanosleep(&ts, NULL);
+#endif
}
return NULL;
}
-#endif
+
+/**
+ * @brief Accept an X11 forwarding channel.
+ *
+ * @param channel An x11-enabled session channel.
+ *
+ * @param timeout_ms Timeout in milli-seconds.
+ *
+ * @return Newly created channel, or NULL if no X11 request from the server
+ */
+ssh_channel channel_accept_x11(ssh_channel channel, int timeout_ms) {
+ return channel_accept(channel->session, SSH_CHANNEL_X11, timeout_ms);
+}
+
+static int global_request(ssh_session session, const char *request,
+ ssh_buffer buffer, int reply) {
+ ssh_string req = NULL;
+ int rc = SSH_ERROR;
+
+ enter_function();
+
+ req = string_from_char(request);
+ if (req == NULL) {
+ goto error;
+ }
+
+ if (buffer_add_u8(session->out_buffer, SSH2_MSG_GLOBAL_REQUEST) < 0 ||
+ buffer_add_ssh_string(session->out_buffer, req) < 0 ||
+ buffer_add_u8(session->out_buffer, reply == 0 ? 0 : 1) < 0) {
+ goto error;
+ }
+ string_free(req);
+
+ if (buffer != NULL) {
+ if (buffer_add_data(session->out_buffer, buffer_get(buffer),
+ buffer_get_len(buffer)) < 0) {
+ goto error;
+ }
+ }
+
+ if (packet_send(session) != SSH_OK) {
+ leave_function();
+ return rc;
+ }
+
+ ssh_log(session, SSH_LOG_RARE,
+ "Sent a SSH_MSG_GLOBAL_REQUEST %s", request);
+ if (reply == 0) {
+ leave_function();
+ return SSH_OK;
+ }
+
+ rc = packet_wait(session, SSH2_MSG_REQUEST_SUCCESS, 1);
+ if (rc == SSH_ERROR) {
+ if (session->in_packet.type == SSH2_MSG_REQUEST_FAILURE) {
+ ssh_log(session, SSH_LOG_PACKET,
+ "%s channel request failed", request);
+ ssh_set_error(session, SSH_REQUEST_DENIED,
+ "Channel request %s failed", request);
+ } else {
+ ssh_log(session, SSH_LOG_RARE,
+ "Received an unexpected %d message", session->in_packet.type);
+ }
+ } else {
+ ssh_log(session, SSH_LOG_RARE, "Received a SUCCESS");
+ }
+
+ leave_function();
+ return rc;
+error:
+ buffer_reinit(session->out_buffer);
+ string_free(req);
+
+ leave_function();
+ return rc;
+}
+
+/**
+ * @brief Sends the "tcpip-forward" global request to ask the server to begin
+ * listening for inbound connections.
+ *
+ * @param session The ssh session to send the request.
+ *
+ * @param address The address to bind to on the server. Pass NULL to bind
+ * to all available addresses on all protocol families
+ * supported by the server.
+ *
+ * @param port The port to bind to on the server. Pass 0 to ask the
+ * server to allocate the next available unprivileged port
+ * number
+ *
+ * @param bound_port The pointer to get actual bound port. Pass NULL to
+ * ignore.
+ *
+ * @return SSH_OK on success\n
+ * SSH_ERROR on error
+ */
+int channel_forward_listen(ssh_session session, const char *address, int port, int *bound_port) {
+ ssh_buffer buffer = NULL;
+ ssh_string addr = NULL;
+ int rc = SSH_ERROR;
+ uint32_t tmp;
+
+ buffer = buffer_new();
+ if (buffer == NULL) {
+ goto error;
+ }
+
+ addr = string_from_char(address ? address : "");
+ if (addr == NULL) {
+ goto error;
+ }
+
+ if (buffer_add_ssh_string(buffer, addr) < 0 ||
+ buffer_add_u32(buffer, htonl(port)) < 0) {
+ goto error;
+ }
+
+ rc = global_request(session, "tcpip-forward", buffer, 1);
+
+ if (rc == SSH_OK && port == 0 && bound_port) {
+ buffer_get_u32(session->in_buffer, &tmp);
+ *bound_port = ntohl(tmp);
+ }
+
+error:
+ buffer_free(buffer);
+ string_free(addr);
+ return rc;
+}
+
+/**
+ * @brief Accept an incoming TCP/IP forwarding channel.
+ *
+ * @param session The ssh session to use.
+ *
+ * @param timeout_ms Timeout in milli-seconds.
+ *
+ * @return Newly created channel, or NULL if no incoming channel request from
+ * the server
+ */
+ssh_channel channel_forward_accept(ssh_session session, int timeout_ms) {
+ return channel_accept(session, SSH_CHANNEL_FORWARDED_TCPIP, timeout_ms);
+}
+
+/**
+ * @brief Sends the "cancel-tcpip-forward" global request to ask the server to
+ * cancel the tcpip-forward request.
+ *
+ * @param session The ssh session to send the request.
+ *
+ * @param address The bound address on the server.
+ *
+ * @param port The bound port on the server.
+ *
+ * @return SSH_OK on success\n
+ * SSH_ERROR on error
+ */
+int channel_forward_cancel(ssh_session session, const char *address, int port) {
+ ssh_buffer buffer = NULL;
+ ssh_string addr = NULL;
+ int rc = SSH_ERROR;
+
+ buffer = buffer_new();
+ if (buffer == NULL) {
+ goto error;
+ }
+
+ addr = string_from_char(address ? address : "");
+ if (addr == NULL) {
+ goto error;
+ }
+
+ if (buffer_add_ssh_string(buffer, addr) < 0 ||
+ buffer_add_u32(buffer, htonl(port)) < 0) {
+ goto error;
+ }
+
+ rc = global_request(session, "cancel-tcpip-forward", buffer, 1);
+
+error:
+ buffer_free(buffer);
+ string_free(addr);
+ return rc;
+}
/**
* @brief Set environement variables.
diff --git a/libssh/connect.c b/libssh/connect.c
index e08cd16..d8898ef 100644
--- a/libssh/connect.c
+++ b/libssh/connect.c
@@ -28,13 +28,25 @@
#include <string.h>
#ifdef _WIN32
-/* getaddrinfo, freeaddrinfo, getnameinfo */
-#define _WIN32_WINNT 0x0501
+/*
+ * Only use Windows API functions available on Windows 2000 SP4 or later.
+ * The available constants are in <sdkddkver.h>.
+ * http://msdn.microsoft.com/en-us/library/aa383745.aspx
+ * http://blogs.msdn.com/oldnewthing/archive/2007/04/11/2079137.aspx
+ */
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500 /* _WIN32_WINNT_WIN2K */
+#undef NTDDI_VERSION
+#define NTDDI_VERSION 0x05000400 /* NTDDI_WIN2KSP4 */
#include <winsock2.h>
#include <ws2tcpip.h>
-#include "wspiapi.h" /* Workaround for w2k systems */
+/* <wspiapi.h> is necessary for getaddrinfo before Windows XP, but it isn't
+ * available on some platforms like MinGW. */
+#ifdef HAVE_WSPIAPI_H
+#include <wspiapi.h>
+#endif
#else /* _WIN32 */
diff --git a/libssh/keys.c b/libssh/keys.c
index 1382b76..626acc9 100644
--- a/libssh/keys.c
+++ b/libssh/keys.c
@@ -542,7 +542,6 @@ static int dsa_public_to_string(DSA *key, ssh_buffer buffer) {
goto error;
}
string_fill(n, (char *) tmp, size);
- gcry_sexp_release(sexp);
#elif defined HAVE_LIBCRYPTO
p = make_bignum_string(key->p);
diff --git a/libssh/misc.c b/libssh/misc.c
index 03fd3c3..5fbd28e 100644
--- a/libssh/misc.c
+++ b/libssh/misc.c
@@ -238,6 +238,114 @@ const void *_ssh_list_get_head(struct ssh_list *list){
return data;
}
+/**
+ * @brief Parse directory component.
+ *
+ * dirname breaks a null-terminated pathname string into a directory component.
+ * In the usual case, ssh_dirname() returns the string up to, but not including,
+ * the final '/'. Trailing '/' characters are not counted as part of the
+ * pathname. The caller must free the memory.
+ *
+ * @param path The path to parse.
+ *
+ * @return The dirname of path or NULL if we can't allocate memory. If path
+ * does not contain a slash, c_dirname() returns the string ".". If
+ * path is the string "/", it returns the string "/". If path is
+ * NULL or an empty string, "." is returned.
+ */
+char *ssh_dirname (const char *path) {
+ char *new = NULL;
+ unsigned int len;
+
+ if (path == NULL || *path == '\0') {
+ return strdup(".");
+ }
+
+ len = strlen(path);
+
+ /* Remove trailing slashes */
+ while(len > 0 && path[len - 1] == '/') --len;
+
+ /* We have only slashes */
+ if (len == 0) {
+ return strdup("/");
+ }
+
+ /* goto next slash */
+ while(len > 0 && path[len - 1] != '/') --len;
+
+ if (len == 0) {
+ return strdup(".");
+ } else if (len == 1) {
+ return strdup("/");
+ }
+
+ /* Remove slashes again */
+ while(len > 0 && path[len - 1] == '/') --len;
+
+ new = malloc(len + 1);
+ if (new == NULL) {
+ return NULL;
+ }
+
+ strncpy(new, path, len);
+ new[len] = '\0';
+
+ return new;
+}
+
+/**
+ * @brief basename - parse filename component.
+ *
+ * basename breaks a null-terminated pathname string into a filename component.
+ * ssh_basename() returns the component following the final '/'. Trailing '/'
+ * characters are not counted as part of the pathname.
+ *
+ * @param path The path to parse.
+ *
+ * @return The filename of path or NULL if we can't allocate memory. If path
+ * is a the string "/", basename returns the string "/". If path is
+ * NULL or an empty string, "." is returned.
+ */
+char *ssh_basename (const char *path) {
+ char *new = NULL;
+ const char *s;
+ unsigned int len;
+
+ if (path == NULL || *path == '\0') {
+ return strdup(".");
+ }
+
+ len = strlen(path);
+ /* Remove trailing slashes */
+ while(len > 0 && path[len - 1] == '/') --len;
+
+ /* We have only slashes */
+ if (len == 0) {
+ return strdup("/");
+ }
+
+ while(len > 0 && path[len - 1] != '/') --len;
+
+ if (len > 0) {
+ s = path + len;
+ len = strlen(s);
+
+ while(len > 0 && s[len - 1] == '/') --len;
+ } else {
+ return strdup(path);
+ }
+
+ new = malloc(len + 1);
+ if (new == NULL) {
+ return NULL;
+ }
+
+ strncpy(new, s, len);
+ new[len] = '\0';
+
+ return new;
+}
/** @} */
/* vim: set ts=2 sw=2 et cindent: */
diff --git a/libssh/packet.c b/libssh/packet.c
index ed3a306..a2e91e6 100644
--- a/libssh/packet.c
+++ b/libssh/packet.c
@@ -758,6 +758,7 @@ static int packet_wait2(SSH_SESSION *session, int type, int blocking) {
packet_parse(session);
break;
case SSH2_MSG_IGNORE:
+ case SSH2_MSG_DEBUG:
break;
default:
if (type && (type != session->in_packet.type)) {
diff --git a/libssh/scp.c b/libssh/scp.c
index c0ebac0..e4cb348 100644
--- a/libssh/scp.c
+++ b/libssh/scp.c
@@ -21,9 +21,11 @@
* MA 02111-1307, USA.
*/
-#include "libssh/priv.h"
+#include <stdio.h>
#include <string.h>
+#include "libssh/priv.h"
+
/** @brief Creates a new scp session
* @param session the SSH session to use
* @param mode one of SSH_SCP_WRITE or SSH_SCP_READ, depending if you need to drop files remotely or read them.
@@ -121,6 +123,69 @@ void ssh_scp_free(ssh_scp scp){
SAFE_FREE(scp);
}
+/** @brief creates a directory in a scp in sink mode
+ * @param dirname Name of the directory being created.
+ * @param perms Text form of the unix permissions for the new directory, e.g. "0755".
+ * @returns SSH_OK if the directory was created.
+ * @returns SSH_ERROR if an error happened.
+ * @see ssh_scp_leave_directory
+ */
+int ssh_scp_push_directory(ssh_scp scp, const char *dirname, const char *perms){
+ char buffer[1024];
+ int r;
+ uint8_t code;
+ char *dir;
+ if(scp->state != SSH_SCP_WRITE_INITED){
+ ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_push_directory called under invalid state");
+ return SSH_ERROR;
+ }
+ dir=ssh_basename(dirname);
+ snprintf(buffer, sizeof(buffer), "D%s 0 %s\n", perms, dir);
+ SAFE_FREE(dir);
+ r=channel_write(scp->channel,buffer,strlen(buffer));
+ if(r==SSH_ERROR){
+ scp->state=SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+ r=channel_read(scp->channel,&code,1,0);
+ if(code != 0){
+ ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
+ scp->state=SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+ return SSH_OK;
+}
+
+/**
+ * @brief Leaves a directory
+ * @returns SSH_OK if the directory was created.
+ * @returns SSH_ERROR if an error happened.
+ * @see ssh_scp_push_directory
+ */
+ int ssh_scp_leave_directory(ssh_scp scp){
+ char buffer[1024];
+ int r;
+ uint8_t code;
+ if(scp->state != SSH_SCP_WRITE_INITED){
+ ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_leave_directory called under invalid state");
+ return SSH_ERROR;
+ }
+ strcpy(buffer, "E\n");
+ r=channel_write(scp->channel,buffer,strlen(buffer));
+ if(r==SSH_ERROR){
+ scp->state=SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+ r=channel_read(scp->channel,&code,1,0);
+ if(code != 0){
+ ssh_set_error(scp->session,SSH_FATAL, "scp status code %ud not valid", code);
+ scp->state=SSH_SCP_ERROR;
+ return SSH_ERROR;
+ }
+ return SSH_OK;
+}
+
+
/** @brief initializes the sending of a file to a scp in sink mode
* @param filename Name of the file being sent. It should not contain any path indicator
* @param size Exact size in bytes of the file being sent.
@@ -132,11 +197,14 @@ int ssh_scp_push_file(ssh_scp scp, const char *filename, size_t size, const char
char buffer[1024];
int r;
uint8_t code;
+ char *file;
if(scp->state != SSH_SCP_WRITE_INITED){
ssh_set_error(scp->session,SSH_FATAL,"ssh_scp_push_file called under invalid state");
return SSH_ERROR;
}
- snprintf(buffer,sizeof(buffer),"C%s %ld %s\n",perms, size, filename);
+ file=ssh_basename(filename);
+ snprintf(buffer, sizeof(buffer), "C%s %" PRIdS " %s\n", perms, size, file);
+ SAFE_FREE(file);
r=channel_write(scp->channel,buffer,strlen(buffer));
if(r==SSH_ERROR){
scp->state=SSH_SCP_ERROR;
@@ -198,3 +266,12 @@ int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){
}
return SSH_OK;
}
+
+ssh_scp_request ssh_scp_request_new(void){
+ ssh_scp_request r=malloc(sizeof(struct ssh_scp_request_struct));
+ if(r==NULL)
+ return NULL;
+ ZERO_STRUCTP(r);
+ return r;
+}
+
diff --git a/libssh/sftp.c b/libssh/sftp.c
index 250b753..40510ed 100644
--- a/libssh/sftp.c
+++ b/libssh/sftp.c
@@ -578,28 +578,28 @@ unsigned int sftp_extensions_get_count(SFTP_SESSION *sftp) {
return sftp->ext->count;
}
-const char *sftp_extensions_get_name(SFTP_SESSION *sftp, unsigned int index) {
+const char *sftp_extensions_get_name(SFTP_SESSION *sftp, unsigned int idx) {
if (sftp == NULL || sftp->ext == NULL || sftp->ext->name == NULL) {
return NULL;
}
- if (index > sftp->ext->count) {
+ if (idx > sftp->ext->count) {
return NULL;
}
- return sftp->ext->name[index];
+ return sftp->ext->name[idx];
}
-const char *sftp_extensions_get_data(SFTP_SESSION *sftp, unsigned int index) {
+const char *sftp_extensions_get_data(SFTP_SESSION *sftp, unsigned int idx) {
if (sftp == NULL || sftp->ext == NULL || sftp->ext->data == NULL) {
return NULL;
}
- if (index > sftp->ext->count) {
+ if (idx > sftp->ext->count) {
return NULL;
}
- return sftp->ext->data[index];
+ return sftp->ext->data[idx];
}
int sftp_extension_supported(SFTP_SESSION *sftp, const char *name,
@@ -2453,7 +2453,7 @@ char *sftp_readlink(SFTP_SESSION *sftp, const char *path) {
ssh_string path_s = NULL;
ssh_string link_s = NULL;
ssh_buffer buffer;
- char *link;
+ char *lnk;
uint32_t ignored;
uint32_t id;
@@ -2499,10 +2499,10 @@ char *sftp_readlink(SFTP_SESSION *sftp, const char *path) {
if (link_s == NULL) {
return NULL;
}
- link = string_to_char(link_s);
+ lnk = string_to_char(link_s);
string_free(link_s);
- return link;
+ return lnk;
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
status = parse_status_msg(msg);
sftp_message_free(msg);
@@ -2616,7 +2616,7 @@ SFTP_STATVFS *sftp_statvfs(SFTP_SESSION *sftp, const char *path) {
STATUS_MESSAGE *status = NULL;
SFTP_MESSAGE *msg = NULL;
ssh_string pathstr;
- ssh_string statvfs;
+ ssh_string ext;
ssh_buffer buffer;
uint32_t id;
@@ -2629,8 +2629,8 @@ SFTP_STATVFS *sftp_statvfs(SFTP_SESSION *sftp, const char *path) {
return NULL;
}
- statvfs = string_from_char("statvfs@openssh.com");
- if (statvfs == NULL) {
+ ext = string_from_char("statvfs@openssh.com");
+ if (ext == NULL) {
buffer_free(buffer);
return NULL;
}
@@ -2638,22 +2638,22 @@ SFTP_STATVFS *sftp_statvfs(SFTP_SESSION *sftp, const char *path) {
pathstr = string_from_char(path);
if (pathstr == NULL) {
buffer_free(buffer);
- string_free(statvfs);
+ string_free(ext);
return NULL;
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, statvfs) < 0 ||
+ buffer_add_ssh_string(buffer, ext) < 0 ||
buffer_add_ssh_string(buffer, pathstr) < 0 ||
sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer) < 0) {
buffer_free(buffer);
- string_free(statvfs);
+ string_free(ext);
string_free(pathstr);
return NULL;
}
buffer_free(buffer);
- string_free(statvfs);
+ string_free(ext);
string_free(pathstr);
while (msg == NULL) {
@@ -2664,13 +2664,13 @@ SFTP_STATVFS *sftp_statvfs(SFTP_SESSION *sftp, const char *path) {
}
if (msg->packet_type == SSH_FXP_EXTENDED_REPLY) {
- SFTP_STATVFS *statvfs = sftp_parse_statvfs(sftp, msg->payload);
+ SFTP_STATVFS *buf = sftp_parse_statvfs(sftp, msg->payload);
sftp_message_free(msg);
- if (statvfs == NULL) {
+ if (buf == NULL) {
return NULL;
}
- return statvfs;
+ return buf;
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
status = parse_status_msg(msg);
sftp_message_free(msg);
@@ -2693,7 +2693,7 @@ SFTP_STATVFS *sftp_fstatvfs(SFTP_FILE *file) {
STATUS_MESSAGE *status = NULL;
SFTP_MESSAGE *msg = NULL;
SFTP_SESSION *sftp;
- ssh_string fstatvfs;
+ ssh_string ext;
ssh_buffer buffer;
uint32_t id;
@@ -2707,23 +2707,23 @@ SFTP_STATVFS *sftp_fstatvfs(SFTP_FILE *file) {
return NULL;
}
- fstatvfs = string_from_char("fstatvfs@openssh.com");
- if (fstatvfs == NULL) {
+ ext = string_from_char("fstatvfs@openssh.com");
+ if (ext == NULL) {
buffer_free(buffer);
return NULL;
}
id = sftp_get_new_id(sftp);
if (buffer_add_u32(buffer, id) < 0 ||
- buffer_add_ssh_string(buffer, fstatvfs) < 0 ||
+ buffer_add_ssh_string(buffer, ext) < 0 ||
buffer_add_ssh_string(buffer, file->handle) < 0 ||
sftp_packet_write(sftp, SSH_FXP_EXTENDED, buffer) < 0) {
buffer_free(buffer);
- string_free(fstatvfs);
+ string_free(ext);
return NULL;
}
buffer_free(buffer);
- string_free(fstatvfs);
+ string_free(ext);
while (msg == NULL) {
if (sftp_read_and_dispatch(sftp) < 0) {
@@ -2733,13 +2733,13 @@ SFTP_STATVFS *sftp_fstatvfs(SFTP_FILE *file) {
}
if (msg->packet_type == SSH_FXP_EXTENDED_REPLY) {
- SFTP_STATVFS *statvfs = sftp_parse_statvfs(sftp, msg->payload);
+ SFTP_STATVFS *buf = sftp_parse_statvfs(sftp, msg->payload);
sftp_message_free(msg);
- if (statvfs == NULL) {
+ if (buf == NULL) {
return NULL;
}
- return statvfs;
+ return buf;
} else if (msg->packet_type == SSH_FXP_STATUS) { /* bad response (error) */
status = parse_status_msg(msg);
sftp_message_free(msg);
diff --git a/sample.c b/sample.c
index c38f9c7..c40dee9 100644
--- a/sample.c
+++ b/sample.c
@@ -346,17 +346,17 @@ void do_sftp(SSH_SESSION *session){
"\tfile system id: %llu\n"
"\tbit mask of f_flag values: %llu\n"
"\tmaximum filename length: %llu\n",
- sftpstatvfs->f_bsize,
- sftpstatvfs->f_frsize,
- sftpstatvfs->f_blocks,
- sftpstatvfs->f_bfree,
- sftpstatvfs->f_bavail,
- sftpstatvfs->f_files,
- sftpstatvfs->f_ffree,
- sftpstatvfs->f_favail,
- sftpstatvfs->f_fsid,
- sftpstatvfs->f_flag,
- sftpstatvfs->f_namemax);
+ (unsigned long long) sftpstatvfs->f_bsize,
+ (unsigned long long) sftpstatvfs->f_frsize,
+ (unsigned long long) sftpstatvfs->f_blocks,
+ (unsigned long long) sftpstatvfs->f_bfree,
+ (unsigned long long) sftpstatvfs->f_bavail,
+ (unsigned long long) sftpstatvfs->f_files,
+ (unsigned long long) sftpstatvfs->f_ffree,
+ (unsigned long long) sftpstatvfs->f_favail,
+ (unsigned long long) sftpstatvfs->f_fsid,
+ (unsigned long long) sftpstatvfs->f_flag,
+ (unsigned long long) sftpstatvfs->f_namemax);
sftp_statvfs_free(sftpstatvfs);
@@ -377,17 +377,17 @@ void do_sftp(SSH_SESSION *session){
"\tfile system id: %llu\n"
"\tbit mask of f_flag values: %llu\n"
"\tmaximum filename length: %llu\n",
- sysstatvfs.f_bsize,
- sysstatvfs.f_frsize,
- sysstatvfs.f_blocks,
- sysstatvfs.f_bfree,
- sysstatvfs.f_bavail,
- sysstatvfs.f_files,
- sysstatvfs.f_ffree,
- sysstatvfs.f_favail,
- sysstatvfs.f_fsid,
- sysstatvfs.f_flag,
- sysstatvfs.f_namemax);
+ (unsigned long long) sysstatvfs.f_bsize,
+ (unsigned long long) sysstatvfs.f_frsize,
+ (unsigned long long) sysstatvfs.f_blocks,
+ (unsigned long long) sysstatvfs.f_bfree,
+ (unsigned long long) sysstatvfs.f_bavail,
+ (unsigned long long) sysstatvfs.f_files,
+ (unsigned long long) sysstatvfs.f_ffree,
+ (unsigned long long) sysstatvfs.f_favail,
+ (unsigned long long) sysstatvfs.f_fsid,
+ (unsigned long long) sysstatvfs.f_flag,
+ (unsigned long long) sysstatvfs.f_namemax);
}
/* the connection is made */