Merge branch 'master' of git://git.libssh.org/projects/libssh/libssh
Conflicts: include/libssh/priv.h
Этот коммит содержится в:
Коммит
d4bc6fa954
@ -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)
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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__
|
||||
|
@ -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_
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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);
|
||||
|
108
libssh/misc.c
108
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: */
|
||||
|
@ -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)) {
|
||||
|
81
libssh/scp.c
81
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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
44
sample.c
44
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 */
|
||||
|
Загрузка…
x
Ссылка в новой задаче
Block a user