diff options
-rw-r--r-- | ConfigureChecks.cmake | 43 | ||||
-rw-r--r-- | cmake/Modules/FindOpenSSL.cmake | 1 | ||||
-rw-r--r-- | config.h.cmake | 3 | ||||
-rw-r--r-- | include/libssh/libssh.h | 18 | ||||
-rw-r--r-- | include/libssh/priv.h | 24 | ||||
-rwxr-xr-x | include/wspiapi.h | 999 | ||||
-rw-r--r-- | libssh/CMakeLists.txt | 8 | ||||
-rw-r--r-- | libssh/channels.c | 213 | ||||
-rw-r--r-- | libssh/connect.c | 18 | ||||
-rw-r--r-- | libssh/keys.c | 1 | ||||
-rw-r--r-- | libssh/misc.c | 108 | ||||
-rw-r--r-- | libssh/packet.c | 1 | ||||
-rw-r--r-- | libssh/scp.c | 81 | ||||
-rw-r--r-- | libssh/sftp.c | 56 | ||||
-rw-r--r-- | sample.c | 44 |
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); @@ -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 */ |