mirror of
https://git.libssh.org/projects/libssh.git
synced 2026-02-11 02:38:09 +09:00
Compare commits
16 Commits
release-0-
...
release-0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9f65b5740 | ||
|
|
99a58eb325 | ||
|
|
ed1cba705c | ||
|
|
0b13a6d265 | ||
|
|
74c0201219 | ||
|
|
83c51d1c13 | ||
|
|
c712d30311 | ||
|
|
2144049c7d | ||
|
|
9dd86859e8 | ||
|
|
810fbfb620 | ||
|
|
370d072eba | ||
|
|
56dfa69fc9 | ||
|
|
672f8412f0 | ||
|
|
83ff1ffcc3 | ||
|
|
fb35153b49 | ||
|
|
7539200773 |
@@ -6,15 +6,13 @@ cmake_minimum_required(VERSION 2.6.0)
|
|||||||
# global needed variables
|
# global needed variables
|
||||||
set(APPLICATION_NAME ${PROJECT_NAME})
|
set(APPLICATION_NAME ${PROJECT_NAME})
|
||||||
|
|
||||||
set(APPLICATION_VERSION "0.4.0")
|
|
||||||
|
|
||||||
set(APPLICATION_VERSION_MAJOR "0")
|
set(APPLICATION_VERSION_MAJOR "0")
|
||||||
set(APPLICATION_VERSION_MINOR "4")
|
set(APPLICATION_VERSION_MINOR "4")
|
||||||
set(APPLICATION_VERSION_PATCH "1")
|
set(APPLICATION_VERSION_PATCH "2")
|
||||||
|
|
||||||
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}${APPLICATION_VERSION_MINOR}${APPLICATION_VERSION_PATCH}")
|
set(APPLICATION_VERSION "${APPLICATION_VERSION_MAJOR}${APPLICATION_VERSION_MINOR}${APPLICATION_VERSION_PATCH}")
|
||||||
|
|
||||||
set(LIBRARY_VERSION "4.0.1")
|
set(LIBRARY_VERSION "4.0.2")
|
||||||
set(LIBRARY_SOVERSION "4")
|
set(LIBRARY_SOVERSION "4")
|
||||||
|
|
||||||
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
|
|||||||
### versions
|
### versions
|
||||||
set(CPACK_PACKAGE_VERSION_MAJOR "0")
|
set(CPACK_PACKAGE_VERSION_MAJOR "0")
|
||||||
set(CPACK_PACKAGE_VERSION_MINOR "4")
|
set(CPACK_PACKAGE_VERSION_MINOR "4")
|
||||||
set(CPACK_PACKAGE_VERSION_PATCH "1")
|
set(CPACK_PACKAGE_VERSION_PATCH "2")
|
||||||
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
|
set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
15
ChangeLog
15
ChangeLog
@@ -1,6 +1,21 @@
|
|||||||
ChangeLog
|
ChangeLog
|
||||||
==========
|
==========
|
||||||
|
|
||||||
|
version 0.4.2 (released 2010-03-15)
|
||||||
|
* Added owner and group information in sftp attributes.
|
||||||
|
* Added missing SSH_OPTIONS_FD option.
|
||||||
|
* Added printout of owner and group in the sftp example.
|
||||||
|
* Added a prepend function for ssh_list.
|
||||||
|
* Added send back replies to openssh's keepalives.
|
||||||
|
* Fixed documentation in scp code
|
||||||
|
* Fixed longname parsing, this only workings with readdir.
|
||||||
|
* Fixed and added support for several identity files.
|
||||||
|
* Fixed sftp_parse_longname() on Windows.
|
||||||
|
* Fixed a race condition bug in ssh_scp_close()
|
||||||
|
* Remove config support for SSHv1 Cipher variable.
|
||||||
|
* Rename ssh_list_add to ssh_list_append.
|
||||||
|
* Rename ssh_list_get_head to ssh_list_pop_head
|
||||||
|
|
||||||
version 0.4.1 (released 2010-02-13)
|
version 0.4.1 (released 2010-02-13)
|
||||||
* Added support for aes128-ctr, aes192-ctr and aes256-ctr encryption.
|
* Added support for aes128-ctr, aes192-ctr and aes256-ctr encryption.
|
||||||
* Added an example for exec.
|
* Added an example for exec.
|
||||||
|
|||||||
@@ -152,10 +152,12 @@ static void do_sftp(ssh_session session){
|
|||||||
}
|
}
|
||||||
/* reading the whole directory, file by file */
|
/* reading the whole directory, file by file */
|
||||||
while((file=sftp_readdir(sftp,dir))){
|
while((file=sftp_readdir(sftp,dir))){
|
||||||
fprintf(stderr, "%30s(%.8o) : %.5d.%.5d : %.10llu bytes\n",
|
fprintf(stderr, "%30s(%.8o) : %s(%.5d) %s(%.5d) : %.10llu bytes\n",
|
||||||
file->name,
|
file->name,
|
||||||
file->permissions,
|
file->permissions,
|
||||||
|
file->owner,
|
||||||
file->uid,
|
file->uid,
|
||||||
|
file->group,
|
||||||
file->gid,
|
file->gid,
|
||||||
(long long unsigned int) file->size);
|
(long long unsigned int) file->size);
|
||||||
sftp_attributes_free(file);
|
sftp_attributes_free(file);
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
/* libssh version */
|
/* libssh version */
|
||||||
#define LIBSSH_VERSION_MAJOR 0
|
#define LIBSSH_VERSION_MAJOR 0
|
||||||
#define LIBSSH_VERSION_MINOR 4
|
#define LIBSSH_VERSION_MINOR 4
|
||||||
#define LIBSSH_VERSION_MICRO 1
|
#define LIBSSH_VERSION_MICRO 2
|
||||||
|
|
||||||
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
#define LIBSSH_VERSION_INT SSH_VERSION_INT(LIBSSH_VERSION_MAJOR, \
|
||||||
LIBSSH_VERSION_MINOR, \
|
LIBSSH_VERSION_MINOR, \
|
||||||
@@ -252,6 +252,7 @@ enum ssh_options_e {
|
|||||||
SSH_OPTIONS_USER,
|
SSH_OPTIONS_USER,
|
||||||
SSH_OPTIONS_SSH_DIR,
|
SSH_OPTIONS_SSH_DIR,
|
||||||
SSH_OPTIONS_IDENTITY,
|
SSH_OPTIONS_IDENTITY,
|
||||||
|
SSH_OPTIONS_ADD_IDENTITY,
|
||||||
SSH_OPTIONS_KNOWNHOSTS,
|
SSH_OPTIONS_KNOWNHOSTS,
|
||||||
SSH_OPTIONS_TIMEOUT,
|
SSH_OPTIONS_TIMEOUT,
|
||||||
SSH_OPTIONS_TIMEOUT_USEC,
|
SSH_OPTIONS_TIMEOUT_USEC,
|
||||||
@@ -335,10 +336,14 @@ LIBSSH_API void privatekey_free(ssh_private_key prv);
|
|||||||
LIBSSH_API ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
|
LIBSSH_API ssh_private_key privatekey_from_file(ssh_session session, const char *filename,
|
||||||
int type, const char *passphrase);
|
int type, const char *passphrase);
|
||||||
LIBSSH_API void publickey_free(ssh_public_key key);
|
LIBSSH_API void publickey_free(ssh_public_key key);
|
||||||
|
LIBSSH_API int ssh_publickey_to_file(ssh_session session, const char *file,
|
||||||
|
ssh_string pubkey, int type);
|
||||||
LIBSSH_API ssh_string publickey_from_file(ssh_session session, const char *filename,
|
LIBSSH_API ssh_string publickey_from_file(ssh_session session, const char *filename,
|
||||||
int *type);
|
int *type);
|
||||||
LIBSSH_API ssh_public_key publickey_from_privatekey(ssh_private_key prv);
|
LIBSSH_API ssh_public_key publickey_from_privatekey(ssh_private_key prv);
|
||||||
LIBSSH_API ssh_string publickey_to_string(ssh_public_key key);
|
LIBSSH_API ssh_string publickey_to_string(ssh_public_key key);
|
||||||
|
LIBSSH_API int ssh_try_publickey_from_file(ssh_session session, const char *keyfile,
|
||||||
|
ssh_string *publickey, int *type);
|
||||||
|
|
||||||
LIBSSH_API int ssh_auth_list(ssh_session session);
|
LIBSSH_API int ssh_auth_list(ssh_session session);
|
||||||
LIBSSH_API char *ssh_basename (const char *path);
|
LIBSSH_API char *ssh_basename (const char *path);
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
/* in misc.c */
|
/* in misc.c */
|
||||||
/* gets the user home dir. */
|
/* gets the user home dir. */
|
||||||
char *ssh_get_user_home_dir(void);
|
char *ssh_get_user_home_dir(void);
|
||||||
|
char *ssh_get_local_username(ssh_session session);
|
||||||
int ssh_file_readaccess_ok(const char *file);
|
int ssh_file_readaccess_ok(const char *file);
|
||||||
|
|
||||||
/* macro for byte ordering */
|
/* macro for byte ordering */
|
||||||
@@ -46,14 +47,11 @@ struct ssh_iterator {
|
|||||||
struct ssh_list *ssh_list_new(void);
|
struct ssh_list *ssh_list_new(void);
|
||||||
void ssh_list_free(struct ssh_list *list);
|
void ssh_list_free(struct ssh_list *list);
|
||||||
struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list);
|
struct ssh_iterator *ssh_list_get_iterator(const struct ssh_list *list);
|
||||||
int ssh_list_add(struct ssh_list *list, const void *data);
|
int ssh_list_append(struct ssh_list *list, const void *data);
|
||||||
|
int ssh_list_prepend(struct ssh_list *list, const void *data);
|
||||||
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator);
|
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator);
|
||||||
|
|
||||||
/** @brief fetch the head element of a list and remove it from list
|
const void *_ssh_list_pop_head(struct ssh_list *list);
|
||||||
* @param list the ssh_list to use
|
|
||||||
* @return the first element of the list
|
|
||||||
*/
|
|
||||||
const void *_ssh_list_get_head(struct ssh_list *list);
|
|
||||||
|
|
||||||
#define ssh_iterator_value(type, iterator)\
|
#define ssh_iterator_value(type, iterator)\
|
||||||
((type)((iterator)->data))
|
((type)((iterator)->data))
|
||||||
@@ -61,9 +59,9 @@ const void *_ssh_list_get_head(struct ssh_list *list);
|
|||||||
/** @brief fetch the head element of a list and remove it from list
|
/** @brief fetch the head element of a list and remove it from list
|
||||||
* @param type type of the element to return
|
* @param type type of the element to return
|
||||||
* @param list the ssh_list to use
|
* @param list the ssh_list to use
|
||||||
* @return the first element of the list
|
* @return the first element of the list, or NULL if the list is empty
|
||||||
*/
|
*/
|
||||||
#define ssh_list_get_head(type, ssh_list)\
|
#define ssh_list_pop_head(type, ssh_list)\
|
||||||
((type)_ssh_list_get_head(ssh_list))
|
((type)_ssh_list_pop_head(ssh_list))
|
||||||
|
|
||||||
#endif /* MISC_H_ */
|
#endif /* MISC_H_ */
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ struct ssh_session_struct {
|
|||||||
char *host;
|
char *host;
|
||||||
char *bindaddr; /* TODO: check if needed */
|
char *bindaddr; /* TODO: check if needed */
|
||||||
char *xbanner; /* TODO: looks like it is not needed */
|
char *xbanner; /* TODO: looks like it is not needed */
|
||||||
char *identity;
|
struct ssh_list *identity;
|
||||||
char *sshdir;
|
char *sshdir;
|
||||||
char *knownhosts;
|
char *knownhosts;
|
||||||
char *wanted_methods[10];
|
char *wanted_methods[10];
|
||||||
|
|||||||
@@ -149,17 +149,16 @@ struct sftp_status_message_struct {
|
|||||||
char *langmsg;
|
char *langmsg;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* don't worry much of these aren't really used */
|
|
||||||
struct sftp_attributes_struct {
|
struct sftp_attributes_struct {
|
||||||
char *name;
|
char *name;
|
||||||
char *longname; /* some weird stuff */
|
char *longname; /* ls -l output on openssh, not reliable else */
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
uint64_t size;
|
uint64_t size;
|
||||||
uint32_t uid;
|
uint32_t uid;
|
||||||
uint32_t gid;
|
uint32_t gid;
|
||||||
char *owner;
|
char *owner; /* set if openssh and version 4 */
|
||||||
char *group;
|
char *group; /* set if openssh and version 4 */
|
||||||
uint32_t permissions;
|
uint32_t permissions;
|
||||||
uint64_t atime64;
|
uint64_t atime64;
|
||||||
uint32_t atime;
|
uint32_t atime;
|
||||||
|
|||||||
265
libssh/auth.c
265
libssh/auth.c
@@ -35,6 +35,7 @@
|
|||||||
#include "libssh/buffer.h"
|
#include "libssh/buffer.h"
|
||||||
#include "libssh/agent.h"
|
#include "libssh/agent.h"
|
||||||
#include "libssh/keyfiles.h"
|
#include "libssh/keyfiles.h"
|
||||||
|
#include "libssh/misc.h"
|
||||||
#include "libssh/packet.h"
|
#include "libssh/packet.h"
|
||||||
#include "libssh/session.h"
|
#include "libssh/session.h"
|
||||||
#include "libssh/keys.h"
|
#include "libssh/keys.h"
|
||||||
@@ -756,42 +757,6 @@ error:
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
static const char privKey_1[] = "SSH_DIR/identity";
|
|
||||||
static const char pubKey_1[] = "SSH_DIR/identity.pub";
|
|
||||||
static const char privKey_2[] = "SSH_DIR/id_dsa";
|
|
||||||
static const char pubKey_2[] = "SSH_DIR/id_dsa.pub";
|
|
||||||
static const char privKey_3[] = "SSH_DIR/id_rsa";
|
|
||||||
static const char pubKey_3[] = "SSH_DIR/id_rsa.pub";
|
|
||||||
/** Used different var to allow const char[] declaration */
|
|
||||||
static struct ssh_keys_struct keytab[] = {
|
|
||||||
{ privKey_1, pubKey_1},
|
|
||||||
{ privKey_2, pubKey_2},
|
|
||||||
{ privKey_3, pubKey_3},
|
|
||||||
{0}
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
/* This requires GCC extensions */
|
|
||||||
static struct ssh_keys_struct keytab[] = {
|
|
||||||
{
|
|
||||||
.privatekey = "SSH_DIR/identity",
|
|
||||||
.publickey = "SSH_DIR/identity.pub"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.privatekey = "SSH_DIR/id_dsa",
|
|
||||||
.publickey = "SSH_DIR/id_dsa.pub",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.privatekey = "SSH_DIR/id_rsa",
|
|
||||||
.publickey = "SSH_DIR/id_rsa.pub",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
.privatekey = NULL,
|
|
||||||
.publickey = NULL
|
|
||||||
}
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Tries to automaticaly authenticate with public key and "none"
|
* @brief Tries to automaticaly authenticate with public key and "none"
|
||||||
*
|
*
|
||||||
@@ -815,13 +780,10 @@ static struct ssh_keys_struct keytab[] = {
|
|||||||
* @see ssh_options_set()
|
* @see ssh_options_set()
|
||||||
*/
|
*/
|
||||||
int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
|
int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
|
||||||
struct ssh_public_key_struct *publickey;
|
struct ssh_iterator *it;
|
||||||
ssh_string pubkey;
|
|
||||||
ssh_private_key privkey;
|
ssh_private_key privkey;
|
||||||
char *privkeyfile = NULL;
|
ssh_public_key pubkey;
|
||||||
char *id = NULL;
|
ssh_string pubkey_string;
|
||||||
size_t size;
|
|
||||||
unsigned int i = 0;
|
|
||||||
int type = 0;
|
int type = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
@@ -837,142 +799,170 @@ int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
|
|||||||
/* Try authentication with ssh-agent first */
|
/* Try authentication with ssh-agent first */
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
if (agent_is_running(session)) {
|
if (agent_is_running(session)) {
|
||||||
|
char *privkey_file = NULL;
|
||||||
|
|
||||||
ssh_log(session, SSH_LOG_RARE,
|
ssh_log(session, SSH_LOG_RARE,
|
||||||
"Trying to authenticate with SSH agent keys as user: %s",
|
"Trying to authenticate with SSH agent keys as user: %s",
|
||||||
session->username);
|
session->username);
|
||||||
|
|
||||||
for (publickey = agent_get_first_ident(session, &privkeyfile);
|
for (pubkey = agent_get_first_ident(session, &privkey_file);
|
||||||
publickey != NULL;
|
pubkey != NULL;
|
||||||
publickey = agent_get_next_ident(session, &privkeyfile)) {
|
pubkey = agent_get_next_ident(session, &privkey_file)) {
|
||||||
|
|
||||||
ssh_log(session, SSH_LOG_RARE, "Trying identity %s", privkeyfile);
|
ssh_log(session, SSH_LOG_RARE, "Trying identity %s", privkey_file);
|
||||||
|
|
||||||
pubkey = publickey_to_string(publickey);
|
pubkey_string = publickey_to_string(pubkey);
|
||||||
if (pubkey) {
|
if (pubkey_string) {
|
||||||
rc = ssh_userauth_offer_pubkey(session, NULL, publickey->type, pubkey);
|
rc = ssh_userauth_offer_pubkey(session, NULL, pubkey->type, pubkey_string);
|
||||||
string_free(pubkey);
|
string_free(pubkey_string);
|
||||||
if (rc == SSH_AUTH_ERROR) {
|
if (rc == SSH_AUTH_ERROR) {
|
||||||
SAFE_FREE(id);
|
SAFE_FREE(privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
publickey_free(pubkey);
|
||||||
publickey_free(publickey);
|
|
||||||
leave_function();
|
leave_function();
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
} else if (rc != SSH_AUTH_SUCCESS) {
|
} else if (rc != SSH_AUTH_SUCCESS) {
|
||||||
ssh_log(session, SSH_LOG_PACKET, "Public key refused by server\n");
|
ssh_log(session, SSH_LOG_PROTOCOL, "Public key refused by server");
|
||||||
SAFE_FREE(id);
|
SAFE_FREE(privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
publickey_free(pubkey);
|
||||||
publickey_free(publickey);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ssh_log(session, SSH_LOG_RARE, "Public key accepted");
|
ssh_log(session, SSH_LOG_RARE, "Public key accepted");
|
||||||
/* pubkey accepted by server ! */
|
/* pubkey accepted by server ! */
|
||||||
rc = ssh_userauth_agent_pubkey(session, NULL, publickey);
|
rc = ssh_userauth_agent_pubkey(session, NULL, pubkey);
|
||||||
if (rc == SSH_AUTH_ERROR) {
|
if (rc == SSH_AUTH_ERROR) {
|
||||||
SAFE_FREE(id);
|
SAFE_FREE(privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
publickey_free(pubkey);
|
||||||
publickey_free(publickey);
|
|
||||||
leave_function();
|
leave_function();
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
} else if (rc != SSH_AUTH_SUCCESS) {
|
} else if (rc != SSH_AUTH_SUCCESS) {
|
||||||
ssh_log(session, SSH_LOG_RARE,
|
ssh_log(session, SSH_LOG_RARE,
|
||||||
"Server accepted public key but refused the signature\n"
|
"Server accepted public key but refused the signature ;"
|
||||||
"It might be a bug of libssh\n");
|
" It might be a bug of libssh");
|
||||||
SAFE_FREE(id);
|
SAFE_FREE(privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
publickey_free(pubkey);
|
||||||
publickey_free(publickey);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* auth success */
|
/* auth success */
|
||||||
ssh_log(session, SSH_LOG_RARE, "Authentication using %s success\n",
|
ssh_log(session, SSH_LOG_PROTOCOL, "Authentication using %s success",
|
||||||
privkeyfile);
|
privkey_file);
|
||||||
SAFE_FREE(id);
|
SAFE_FREE(privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
publickey_free(pubkey);
|
||||||
publickey_free(publickey);
|
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
|
|
||||||
return SSH_AUTH_SUCCESS;
|
return SSH_AUTH_SUCCESS;
|
||||||
} /* if pubkey */
|
} /* if pubkey */
|
||||||
SAFE_FREE(id);
|
SAFE_FREE(privkey_file);
|
||||||
SAFE_FREE(privkeyfile);
|
publickey_free(pubkey);
|
||||||
publickey_free(publickey);
|
|
||||||
} /* for each privkey */
|
} /* for each privkey */
|
||||||
} /* if agent is running */
|
} /* if agent is running */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
size = ARRAY_SIZE(keytab);
|
for (it = ssh_list_get_iterator(session->identity);
|
||||||
if (session->identity) {
|
it != NULL;
|
||||||
ssh_log(session, SSH_LOG_RARE,
|
it = it->next) {
|
||||||
"Trying identity file %s\n", session->identity);
|
char *privkey_file = NULL;
|
||||||
|
int privkey_open = 0;
|
||||||
|
|
||||||
id = malloc(strlen(session->identity) + 1 + 4);
|
privkey_file = dir_expand_dup(session, it->data, 1);
|
||||||
if (id == NULL) {
|
if (privkey_file == NULL) {
|
||||||
leave_function();
|
|
||||||
return SSH_AUTH_ERROR;
|
|
||||||
}
|
|
||||||
sprintf(id, "%s.pub", session->identity);
|
|
||||||
|
|
||||||
keytab[size - 1].privatekey = session->identity;
|
|
||||||
keytab[size - 1].publickey = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0, pubkey = try_publickey_from_file(session, keytab[i],
|
|
||||||
&privkeyfile, &type);
|
|
||||||
i < size;
|
|
||||||
pubkey = try_publickey_from_file(session, keytab[i++],
|
|
||||||
&privkeyfile, &type)) {
|
|
||||||
if (pubkey == NULL) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ssh_userauth_offer_pubkey(session, NULL, type, pubkey);
|
ssh_log(session, SSH_LOG_PROTOCOL, "Trying to read privatekey %s", privkey_file);
|
||||||
if (rc == SSH_AUTH_ERROR){
|
|
||||||
if (id != NULL) {
|
rc = ssh_try_publickey_from_file(session, privkey_file, &pubkey_string, &type);
|
||||||
keytab[size - 1].privatekey = NULL;
|
if (rc == 1) {
|
||||||
keytab[size - 1].publickey = NULL;
|
char *publickey_file;
|
||||||
SAFE_FREE(id);
|
size_t len;
|
||||||
|
|
||||||
|
privkey = privatekey_from_file(session, privkey_file, type, passphrase);
|
||||||
|
if (privkey == NULL) {
|
||||||
|
ssh_log(session, SSH_LOG_RARE,
|
||||||
|
"Reading private key %s failed (bad passphrase ?)",
|
||||||
|
privkey_file);
|
||||||
|
SAFE_FREE(privkey_file);
|
||||||
|
leave_function();
|
||||||
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
string_free(pubkey);
|
privkey_open = 1;
|
||||||
SAFE_FREE(privkeyfile);
|
|
||||||
|
pubkey = publickey_from_privatekey(privkey);
|
||||||
|
if (pubkey == NULL) {
|
||||||
|
SAFE_FREE(privkey_file);
|
||||||
|
privatekey_free(privkey);
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
leave_function();
|
||||||
|
return SSH_AUTH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkey_string = publickey_to_string(pubkey);
|
||||||
|
type = pubkey->type;
|
||||||
|
publickey_free(pubkey);
|
||||||
|
if (pubkey_string == NULL) {
|
||||||
|
SAFE_FREE(privkey_file);
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
leave_function();
|
||||||
|
return SSH_AUTH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(privkey_file) + 5;
|
||||||
|
publickey_file = malloc(len);
|
||||||
|
if (publickey_file == NULL) {
|
||||||
|
SAFE_FREE(privkey_file);
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
leave_function();
|
||||||
|
return SSH_AUTH_ERROR;
|
||||||
|
}
|
||||||
|
snprintf(publickey_file, len, "%s.pub", privkey_file);
|
||||||
|
rc = ssh_publickey_to_file(session, publickey_file, pubkey_string, type);
|
||||||
|
if (rc < 0) {
|
||||||
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
|
"Could not write public key to file: %s", publickey_file);
|
||||||
|
}
|
||||||
|
SAFE_FREE(publickey_file);
|
||||||
|
} else if (rc < 0) {
|
||||||
|
SAFE_FREE(privkey_file);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_userauth_offer_pubkey(session, NULL, type, pubkey_string);
|
||||||
|
if (rc == SSH_AUTH_ERROR){
|
||||||
|
SAFE_FREE(privkey_file);
|
||||||
|
string_free(pubkey_string);
|
||||||
ssh_log(session, SSH_LOG_RARE, "Publickey authentication error");
|
ssh_log(session, SSH_LOG_RARE, "Publickey authentication error");
|
||||||
leave_function();
|
leave_function();
|
||||||
return rc;
|
return rc;
|
||||||
} else {
|
} else {
|
||||||
if (rc != SSH_AUTH_SUCCESS){
|
if (rc != SSH_AUTH_SUCCESS){
|
||||||
ssh_log(session, SSH_LOG_RARE, "Publickey refused by server");
|
ssh_log(session, SSH_LOG_PROTOCOL, "Publickey refused by server");
|
||||||
string_free(pubkey);
|
SAFE_FREE(privkey_file);
|
||||||
pubkey = NULL;
|
string_free(pubkey_string);
|
||||||
SAFE_FREE(privkeyfile);
|
|
||||||
privkeyfile = NULL;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Public key accepted by server! */
|
/* Public key accepted by server! */
|
||||||
ssh_log(session, SSH_LOG_RARE, "Trying to read privatekey %s", privkeyfile);
|
if (!privkey_open) {
|
||||||
privkey = privatekey_from_file(session, privkeyfile, type, passphrase);
|
ssh_log(session, SSH_LOG_PROTOCOL, "Trying to read privatekey %s",
|
||||||
|
privkey_file);
|
||||||
|
privkey = privatekey_from_file(session, privkey_file, type, passphrase);
|
||||||
if (privkey == NULL) {
|
if (privkey == NULL) {
|
||||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
ssh_log(session, SSH_LOG_RARE,
|
||||||
"Reading private key %s failed (bad passphrase ?)",
|
"Reading private key %s failed (bad passphrase ?)",
|
||||||
privkeyfile);
|
privkey_file);
|
||||||
string_free(pubkey);
|
SAFE_FREE(privkey_file);
|
||||||
pubkey = NULL;
|
string_free(pubkey_string);
|
||||||
SAFE_FREE(privkeyfile);
|
|
||||||
privkeyfile = NULL;
|
|
||||||
continue; /* continue the loop with other pubkey */
|
continue; /* continue the loop with other pubkey */
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = ssh_userauth_pubkey(session, NULL, pubkey, privkey);
|
|
||||||
if (rc == SSH_AUTH_ERROR) {
|
|
||||||
if (id != NULL) {
|
|
||||||
keytab[size - 1].privatekey = NULL;
|
|
||||||
keytab[size - 1].publickey = NULL;
|
|
||||||
SAFE_FREE(id);
|
|
||||||
}
|
}
|
||||||
string_free(pubkey);
|
|
||||||
SAFE_FREE(privkeyfile);
|
rc = ssh_userauth_pubkey(session, NULL, pubkey_string, privkey);
|
||||||
|
if (rc == SSH_AUTH_ERROR) {
|
||||||
|
SAFE_FREE(privkey_file);
|
||||||
|
string_free(pubkey_string);
|
||||||
privatekey_free(privkey);
|
privatekey_free(privkey);
|
||||||
leave_function();
|
leave_function();
|
||||||
return rc;
|
return rc;
|
||||||
@@ -980,39 +970,28 @@ int ssh_userauth_autopubkey(ssh_session session, const char *passphrase) {
|
|||||||
if (rc != SSH_AUTH_SUCCESS){
|
if (rc != SSH_AUTH_SUCCESS){
|
||||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
ssh_log(session, SSH_LOG_FUNCTIONS,
|
||||||
"The server accepted the public key but refused the signature");
|
"The server accepted the public key but refused the signature");
|
||||||
string_free(pubkey);
|
SAFE_FREE(privkey_file);
|
||||||
pubkey = NULL;
|
string_free(pubkey_string);
|
||||||
SAFE_FREE(privkeyfile);
|
|
||||||
privkeyfile = NULL;
|
|
||||||
privatekey_free(privkey);
|
privatekey_free(privkey);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* auth success */
|
/* auth success */
|
||||||
ssh_log(session, SSH_LOG_RARE,
|
ssh_log(session, SSH_LOG_PROTOCOL,
|
||||||
"Successfully authenticated using %s", privkeyfile);
|
"Successfully authenticated using %s", privkey_file);
|
||||||
string_free(pubkey);
|
SAFE_FREE(privkey_file);
|
||||||
|
string_free(pubkey_string);
|
||||||
privatekey_free(privkey);
|
privatekey_free(privkey);
|
||||||
SAFE_FREE(privkeyfile);
|
|
||||||
if (id != NULL) {
|
|
||||||
keytab[size - 1].privatekey = NULL;
|
|
||||||
keytab[size - 1].publickey = NULL;
|
|
||||||
SAFE_FREE(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_AUTH_SUCCESS;
|
return SSH_AUTH_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* at this point, pubkey is NULL and so is privkeyfile */
|
/* at this point, pubkey is NULL and so is privkeyfile */
|
||||||
ssh_log(session, SSH_LOG_FUNCTIONS,
|
ssh_log(session, SSH_LOG_FUNCTIONS,
|
||||||
"Tried every public key, none matched");
|
"Tried every public key, none matched");
|
||||||
ssh_set_error(session,SSH_NO_ERROR,"No public key matched");
|
ssh_set_error(session,SSH_NO_ERROR,"No public key matched");
|
||||||
if (id) {
|
|
||||||
keytab[size - 1].privatekey = NULL;
|
|
||||||
keytab[size - 1].publickey = NULL;
|
|
||||||
SAFE_FREE(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_AUTH_DENIED;
|
return SSH_AUTH_DENIED;
|
||||||
|
|||||||
@@ -552,6 +552,15 @@ static void channel_rcv_request(ssh_session session) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(strcmp(request,"keepalive@openssh.com")==0){
|
||||||
|
SAFE_FREE(request);
|
||||||
|
ssh_log(session, SSH_LOG_PROTOCOL,"Responding to Openssh's keepalive");
|
||||||
|
buffer_add_u8(session->out_buffer, SSH2_MSG_CHANNEL_SUCCESS);
|
||||||
|
buffer_add_u32(session->out_buffer, htonl(channel->remote_channel));
|
||||||
|
packet_send(session);
|
||||||
|
leave_function();
|
||||||
|
return;
|
||||||
|
}
|
||||||
/* TODO call message_handle since it handles channel requests as messages */
|
/* TODO call message_handle since it handles channel requests as messages */
|
||||||
/* *but* reset buffer before !! */
|
/* *but* reset buffer before !! */
|
||||||
|
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ enum ssh_config_opcode_e {
|
|||||||
SOC_PORT,
|
SOC_PORT,
|
||||||
SOC_USERNAME,
|
SOC_USERNAME,
|
||||||
SOC_IDENTITY,
|
SOC_IDENTITY,
|
||||||
SOC_CIPHER,
|
|
||||||
SOC_CIPHERS,
|
SOC_CIPHERS,
|
||||||
SOC_COMPRESSION,
|
SOC_COMPRESSION,
|
||||||
SOC_TIMEOUT,
|
SOC_TIMEOUT,
|
||||||
@@ -53,7 +52,6 @@ static struct ssh_config_keyword_table_s ssh_config_keyword_table[] = {
|
|||||||
{ "port", SOC_PORT },
|
{ "port", SOC_PORT },
|
||||||
{ "user", SOC_USERNAME },
|
{ "user", SOC_USERNAME },
|
||||||
{ "identityfile", SOC_IDENTITY },
|
{ "identityfile", SOC_IDENTITY },
|
||||||
{ "cipher", SOC_CIPHER },
|
|
||||||
{ "ciphers", SOC_CIPHERS },
|
{ "ciphers", SOC_CIPHERS },
|
||||||
{ "compression", SOC_COMPRESSION },
|
{ "compression", SOC_COMPRESSION },
|
||||||
{ "connecttimeout", SOC_TIMEOUT },
|
{ "connecttimeout", SOC_TIMEOUT },
|
||||||
|
|||||||
@@ -887,6 +887,79 @@ void privatekey_free(ssh_private_key prv) {
|
|||||||
SAFE_FREE(prv);
|
SAFE_FREE(prv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Write a public key to a file.
|
||||||
|
*
|
||||||
|
* @param[in] session The ssh session to use.
|
||||||
|
*
|
||||||
|
* @param[in] file The filename to write the key into.
|
||||||
|
*
|
||||||
|
* @param[in] pubkey The public key to write.
|
||||||
|
*
|
||||||
|
* @param[in] type The type of the public key.
|
||||||
|
*
|
||||||
|
* @return 0 on success, -1 on error.
|
||||||
|
*/
|
||||||
|
int ssh_publickey_to_file(ssh_session session, const char *file,
|
||||||
|
ssh_string pubkey, int type) {
|
||||||
|
FILE *fp;
|
||||||
|
char *user;
|
||||||
|
char buffer[1024];
|
||||||
|
char host[256];
|
||||||
|
unsigned char *pubkey_64;
|
||||||
|
size_t len;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
pubkey_64 = bin_to_base64(pubkey->string, string_len(pubkey));
|
||||||
|
if (pubkey_64 == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
user = ssh_get_local_username(session);
|
||||||
|
if (user == NULL) {
|
||||||
|
SAFE_FREE(pubkey_64);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = gethostname(host, sizeof(host));
|
||||||
|
if (rc < 0) {
|
||||||
|
SAFE_FREE(user);
|
||||||
|
SAFE_FREE(pubkey_64);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(buffer, sizeof(buffer), "%s %s %s@%s\n",
|
||||||
|
ssh_type_to_char(type),
|
||||||
|
pubkey_64,
|
||||||
|
user,
|
||||||
|
host);
|
||||||
|
|
||||||
|
SAFE_FREE(pubkey_64);
|
||||||
|
SAFE_FREE(user);
|
||||||
|
|
||||||
|
ssh_log(session, SSH_LOG_RARE, "Trying to write public key file: %s", file);
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "public key file content: %s", buffer);
|
||||||
|
|
||||||
|
fp = fopen(file, "w+");
|
||||||
|
if (fp == NULL) {
|
||||||
|
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||||
|
"Error opening %s: %s", file, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(buffer);
|
||||||
|
if (fwrite(buffer, len, 1, fp) != 1 || ferror(fp)) {
|
||||||
|
ssh_set_error(session, SSH_REQUEST_DENIED,
|
||||||
|
"Unable to write to %s", file);
|
||||||
|
fclose(fp);
|
||||||
|
unlink(file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/** \brief Retrieve a public key from a file
|
/** \brief Retrieve a public key from a file
|
||||||
* \param session the SSH session
|
* \param session the SSH session
|
||||||
* \param filename Filename of the key
|
* \param filename Filename of the key
|
||||||
@@ -964,6 +1037,83 @@ ssh_string publickey_from_file(ssh_session session, const char *filename,
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Try to read the public key from a given file.
|
||||||
|
*
|
||||||
|
* @param[in] session The ssh session to use.
|
||||||
|
*
|
||||||
|
* @param[in] keyfile The name of the private keyfile.
|
||||||
|
*
|
||||||
|
* @param[out] publickey A ssh_string to store the public key.
|
||||||
|
*
|
||||||
|
* @param[out] type A pointer to an integer to store the type.
|
||||||
|
*
|
||||||
|
* @return 0 on success, -1 on error or the private key doesn't
|
||||||
|
* exist, 1 if the public key doesn't exist.
|
||||||
|
*/
|
||||||
|
int ssh_try_publickey_from_file(ssh_session session, const char *keyfile,
|
||||||
|
ssh_string *publickey, int *type) {
|
||||||
|
char *pubkey_file;
|
||||||
|
size_t len;
|
||||||
|
ssh_string pubkey_string;
|
||||||
|
int pubkey_type;
|
||||||
|
|
||||||
|
if (session == NULL || keyfile == NULL || publickey == NULL || type == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->sshdir == NULL) {
|
||||||
|
if (ssh_options_set(session, SSH_OPTIONS_SSH_DIR, NULL) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Trying to open privatekey %s", keyfile);
|
||||||
|
if (!ssh_file_readaccess_ok(keyfile)) {
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Failed to open privatekey %s", keyfile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(keyfile) + 5;
|
||||||
|
pubkey_file = malloc(len);
|
||||||
|
if (pubkey_file == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
snprintf(pubkey_file, len, "%s.pub", keyfile);
|
||||||
|
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Trying to open publickey %s",
|
||||||
|
pubkey_file);
|
||||||
|
if (!ssh_file_readaccess_ok(pubkey_file)) {
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Failed to open publickey %s",
|
||||||
|
pubkey_file);
|
||||||
|
SAFE_FREE(pubkey_file);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssh_log(session, SSH_LOG_PACKET, "Success opening public and private key");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We are sure both the private and public key file is readable. We return
|
||||||
|
* the public as a string, and the private filename as an argument
|
||||||
|
*/
|
||||||
|
pubkey_string = publickey_from_file(session, pubkey_file, &pubkey_type);
|
||||||
|
if (pubkey_string == NULL) {
|
||||||
|
ssh_log(session, SSH_LOG_PACKET,
|
||||||
|
"Wasn't able to open public key file %s: %s",
|
||||||
|
pubkey_file,
|
||||||
|
ssh_get_error(session));
|
||||||
|
SAFE_FREE(pubkey_file);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SAFE_FREE(pubkey_file);
|
||||||
|
|
||||||
|
*publickey = pubkey_string;
|
||||||
|
*type = pubkey_type;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_struct keytab,
|
ssh_string try_publickey_from_file(ssh_session session, struct ssh_keys_struct keytab,
|
||||||
char **privkeyfile, int *type) {
|
char **privkeyfile, int *type) {
|
||||||
char *public;
|
char *public;
|
||||||
|
|||||||
@@ -867,7 +867,7 @@ void message_handle(ssh_session session, uint32_t type){
|
|||||||
if(!session->ssh_message_list){
|
if(!session->ssh_message_list){
|
||||||
session->ssh_message_list=ssh_list_new();
|
session->ssh_message_list=ssh_list_new();
|
||||||
}
|
}
|
||||||
ssh_list_add(session->ssh_message_list,msg);
|
ssh_list_append(session->ssh_message_list,msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,6 +158,52 @@ uint64_t ntohll(uint64_t a) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
char *ssh_get_local_username(ssh_session session) {
|
||||||
|
DWORD size = 0;
|
||||||
|
char *user;
|
||||||
|
|
||||||
|
/* get the size */
|
||||||
|
GetUserName(NULL, &size);
|
||||||
|
|
||||||
|
user = malloc(size);
|
||||||
|
if (user == NULL) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetUserName(user, &size)) {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
char *ssh_get_local_username(ssh_session session) {
|
||||||
|
struct passwd pwd;
|
||||||
|
struct passwd *pwdbuf;
|
||||||
|
char buf[NSS_BUFLEN_PASSWD];
|
||||||
|
char *name;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = getpwuid_r(getuid(), &pwd, buf, NSS_BUFLEN_PASSWD, &pwdbuf);
|
||||||
|
if (rc != 0) {
|
||||||
|
ssh_set_error(session, SSH_FATAL,
|
||||||
|
"Couldn't retrieve information for current user!");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
name = strdup(pwd.pw_name);
|
||||||
|
|
||||||
|
if (name == NULL) {
|
||||||
|
ssh_set_error_oom(session);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if libssh is the required version or get the version
|
* @brief Check if libssh is the required version or get the version
|
||||||
* string.
|
* string.
|
||||||
@@ -222,7 +268,7 @@ static struct ssh_iterator *ssh_iterator_new(const void *data){
|
|||||||
return iterator;
|
return iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ssh_list_add(struct ssh_list *list,const void *data){
|
int ssh_list_append(struct ssh_list *list,const void *data){
|
||||||
struct ssh_iterator *iterator=ssh_iterator_new(data);
|
struct ssh_iterator *iterator=ssh_iterator_new(data);
|
||||||
if(!iterator)
|
if(!iterator)
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
@@ -237,6 +283,25 @@ int ssh_list_add(struct ssh_list *list,const void *data){
|
|||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ssh_list_prepend(struct ssh_list *list, const void *data){
|
||||||
|
struct ssh_iterator *it = ssh_iterator_new(data);
|
||||||
|
|
||||||
|
if (it == NULL) {
|
||||||
|
return SSH_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list->end == NULL) {
|
||||||
|
/* list is empty */
|
||||||
|
list->root = list->end = it;
|
||||||
|
} else {
|
||||||
|
/* set as new root */
|
||||||
|
it->next = list->root;
|
||||||
|
list->root = it;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SSH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator){
|
void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator){
|
||||||
struct ssh_iterator *ptr,*prev;
|
struct ssh_iterator *ptr,*prev;
|
||||||
prev=NULL;
|
prev=NULL;
|
||||||
@@ -261,7 +326,14 @@ void ssh_list_remove(struct ssh_list *list, struct ssh_iterator *iterator){
|
|||||||
SAFE_FREE(iterator);
|
SAFE_FREE(iterator);
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *_ssh_list_get_head(struct ssh_list *list){
|
/** @internal
|
||||||
|
* @brief Removes the top element of the list and returns the data value attached
|
||||||
|
* to it
|
||||||
|
* @param list the ssh_list
|
||||||
|
* @returns pointer to the element being stored in head, or
|
||||||
|
* NULL if the list is empty.
|
||||||
|
*/
|
||||||
|
const void *_ssh_list_pop_head(struct ssh_list *list){
|
||||||
struct ssh_iterator *iterator=list->root;
|
struct ssh_iterator *iterator=list->root;
|
||||||
const void *data;
|
const void *data;
|
||||||
if(!list->root)
|
if(!list->root)
|
||||||
|
|||||||
@@ -83,10 +83,29 @@ int ssh_options_copy(ssh_session src, ssh_session *dest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (src->identity) {
|
if (src->identity) {
|
||||||
new->identity = strdup(src->identity);
|
struct ssh_iterator *it;
|
||||||
|
|
||||||
|
new->identity = ssh_list_new();
|
||||||
if (new->identity == NULL) {
|
if (new->identity == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
it = ssh_list_get_iterator(src->identity);
|
||||||
|
while (it) {
|
||||||
|
char *id;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
id = strdup((char *) it->data);
|
||||||
|
if (id == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = ssh_list_append(new->identity, id);
|
||||||
|
if (rc < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
it = it->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src->sshdir) {
|
if (src->sshdir) {
|
||||||
@@ -124,29 +143,6 @@ int ssh_options_copy(ssh_session src, ssh_session *dest) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
static char *get_username_from_uid(ssh_session session, uid_t uid){
|
|
||||||
struct passwd *pwd = NULL;
|
|
||||||
char *name;
|
|
||||||
|
|
||||||
pwd = getpwuid(uid);
|
|
||||||
|
|
||||||
if (pwd == NULL) {
|
|
||||||
ssh_set_error(session, SSH_FATAL, "uid %d doesn't exist !", uid);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
name = strdup(pwd->pw_name);
|
|
||||||
|
|
||||||
if (name == NULL) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int ssh_options_set_algo(ssh_session session, int algo,
|
int ssh_options_set_algo(ssh_session session, int algo,
|
||||||
const char *list) {
|
const char *list) {
|
||||||
if (!verify_existing_algo(algo, list)) {
|
if (!verify_existing_algo(algo, list)) {
|
||||||
@@ -376,6 +372,7 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
|||||||
const void *value) {
|
const void *value) {
|
||||||
char *p, *q;
|
char *p, *q;
|
||||||
long int i;
|
long int i;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
@@ -439,30 +436,23 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
|||||||
session->port = i & 0xffff;
|
session->port = i & 0xffff;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case SSH_OPTIONS_FD:
|
||||||
|
if (value == NULL) {
|
||||||
|
session->fd = -1;
|
||||||
|
} else {
|
||||||
|
socket_t *x = (socket_t *) value;
|
||||||
|
|
||||||
|
session->fd = *x & 0xffff;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case SSH_OPTIONS_USER:
|
case SSH_OPTIONS_USER:
|
||||||
SAFE_FREE(session->username);
|
SAFE_FREE(session->username);
|
||||||
if (value == NULL) { /* set default username */
|
if (value == NULL) { /* set default username */
|
||||||
#ifdef _WIN32
|
q = ssh_get_local_username(session);
|
||||||
DWORD size = 0;
|
|
||||||
GetUserName(NULL, &size); //Get Size
|
|
||||||
q = malloc(size);
|
|
||||||
if (q == NULL) {
|
|
||||||
ssh_set_error_oom(session);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (GetUserName(q, &size)) {
|
|
||||||
session->username = q;
|
|
||||||
} else {
|
|
||||||
SAFE_FREE(q);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#else /* _WIN32 */
|
|
||||||
q = get_username_from_uid(session, getuid());
|
|
||||||
if (q == NULL) {
|
if (q == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
session->username = q;
|
session->username = q;
|
||||||
#endif /* _WIN32 */
|
|
||||||
} else { /* username provided */
|
} else { /* username provided */
|
||||||
session->username = strdup(value);
|
session->username = strdup(value);
|
||||||
if (session->username == NULL) {
|
if (session->username == NULL) {
|
||||||
@@ -489,14 +479,18 @@ int ssh_options_set(ssh_session session, enum ssh_options_e type,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case SSH_OPTIONS_IDENTITY:
|
case SSH_OPTIONS_IDENTITY:
|
||||||
|
case SSH_OPTIONS_ADD_IDENTITY:
|
||||||
if (value == NULL) {
|
if (value == NULL) {
|
||||||
ssh_set_error_invalid(session, __FUNCTION__);
|
ssh_set_error_invalid(session, __FUNCTION__);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
SAFE_FREE(session->identity);
|
q = dir_expand_dup(session, value, 1);
|
||||||
session->identity = dir_expand_dup(session, value, 1);
|
if (q == NULL) {
|
||||||
if (session->identity == NULL) {
|
return -1;
|
||||||
|
}
|
||||||
|
rc = ssh_list_prepend(session->identity, q);
|
||||||
|
if (rc < 0) {
|
||||||
|
SAFE_FREE(q);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
30
libssh/scp.c
30
libssh/scp.c
@@ -26,11 +26,18 @@
|
|||||||
|
|
||||||
#include "libssh/priv.h"
|
#include "libssh/priv.h"
|
||||||
#include "libssh/scp.h"
|
#include "libssh/scp.h"
|
||||||
|
/** @defgroup ssh_scp SSH-scp
|
||||||
|
* @brief SCP protocol over SSH functions
|
||||||
|
* @addtogroup ssh_scp
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
/** @brief Creates a new scp session
|
/** @brief Creates a new scp session
|
||||||
* @param session the SSH session to use
|
* @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.
|
* @param mode one of SSH_SCP_WRITE or SSH_SCP_READ, depending if you need to drop files remotely or read them.
|
||||||
* It is not possible to combine read and write.
|
* It is not possible to combine read and write.
|
||||||
|
* @param location The directory in which write or read will be done. Any push or pull will be relative
|
||||||
|
* to this place
|
||||||
* @returns NULL if the creation was impossible.
|
* @returns NULL if the creation was impossible.
|
||||||
* @returns a ssh_scp handle if it worked.
|
* @returns a ssh_scp handle if it worked.
|
||||||
*/
|
*/
|
||||||
@@ -110,11 +117,22 @@ int ssh_scp_init(ssh_scp scp){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int ssh_scp_close(ssh_scp scp){
|
int ssh_scp_close(ssh_scp scp){
|
||||||
|
char buffer[128];
|
||||||
|
int err;
|
||||||
if(scp->channel != NULL){
|
if(scp->channel != NULL){
|
||||||
if(channel_send_eof(scp->channel) == SSH_ERROR){
|
if(channel_send_eof(scp->channel) == SSH_ERROR){
|
||||||
scp->state=SSH_SCP_ERROR;
|
scp->state=SSH_SCP_ERROR;
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
}
|
}
|
||||||
|
/* avoid situations where data are buffered and
|
||||||
|
* not yet stored on disk. This can happen if the close is sent
|
||||||
|
* before we got the EOF back
|
||||||
|
*/
|
||||||
|
while(!channel_is_eof(scp->channel)){
|
||||||
|
err=channel_read(scp->channel,buffer,sizeof(buffer),0);
|
||||||
|
if(err==SSH_ERROR)
|
||||||
|
break;
|
||||||
|
}
|
||||||
if(channel_close(scp->channel) == SSH_ERROR){
|
if(channel_close(scp->channel) == SSH_ERROR){
|
||||||
scp->state=SSH_SCP_ERROR;
|
scp->state=SSH_SCP_ERROR;
|
||||||
return SSH_ERROR;
|
return SSH_ERROR;
|
||||||
@@ -138,6 +156,7 @@ void ssh_scp_free(ssh_scp scp){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @brief creates a directory in a scp in sink mode
|
/** @brief creates a directory in a scp in sink mode
|
||||||
|
* @param scp the scp handle.
|
||||||
* @param dirname Name of the directory being created.
|
* @param dirname Name of the directory being created.
|
||||||
* @param mode Unix permissions for the new directory, e.g. 0755.
|
* @param mode Unix permissions for the new directory, e.g. 0755.
|
||||||
* @returns SSH_OK if the directory was created.
|
* @returns SSH_OK if the directory was created.
|
||||||
@@ -203,6 +222,7 @@ int ssh_scp_push_directory(ssh_scp scp, const char *dirname, int mode){
|
|||||||
|
|
||||||
|
|
||||||
/** @brief initializes the sending of a file to a scp in sink mode
|
/** @brief initializes the sending of a file to a scp in sink mode
|
||||||
|
* @param scp the scp handle.
|
||||||
* @param filename Name of the file being sent. It should not contain any path indicator
|
* @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.
|
* @param size Exact size in bytes of the file being sent.
|
||||||
* @param mode Unix permissions for the new file, e.g. 0644
|
* @param mode Unix permissions for the new file, e.g. 0644
|
||||||
@@ -285,6 +305,7 @@ int ssh_scp_response(ssh_scp scp, char **response){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Write into a remote scp file
|
/** @brief Write into a remote scp file
|
||||||
|
* @param scp the scp handle.
|
||||||
* @param buffer the buffer to write
|
* @param buffer the buffer to write
|
||||||
* @param len the number of bytes to write
|
* @param len the number of bytes to write
|
||||||
* @returns SSH_OK the write was successful
|
* @returns SSH_OK the write was successful
|
||||||
@@ -331,6 +352,7 @@ int ssh_scp_write(ssh_scp scp, const void *buffer, size_t len){
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief reads a string on a channel, terminated by '\n'
|
* @brief reads a string on a channel, terminated by '\n'
|
||||||
|
* @param scp the scp handle.
|
||||||
* @param buffer pointer to a buffer to place the string
|
* @param buffer pointer to a buffer to place the string
|
||||||
* @param len size of the buffer in bytes. If the string is bigger
|
* @param len size of the buffer in bytes. If the string is bigger
|
||||||
* than len-1, only len-1 bytes are read and the string
|
* than len-1, only len-1 bytes are read and the string
|
||||||
@@ -455,6 +477,7 @@ int ssh_scp_pull_request(ssh_scp scp){
|
|||||||
/**
|
/**
|
||||||
* @brief denies the transfer of a file or creation of a directory
|
* @brief denies the transfer of a file or creation of a directory
|
||||||
* coming from the remote party
|
* coming from the remote party
|
||||||
|
* @param scp the scp handle.
|
||||||
* @param reason nul-terminated string with a human-readable explanation
|
* @param reason nul-terminated string with a human-readable explanation
|
||||||
* of the deny
|
* of the deny
|
||||||
* @returns SSH_OK the message was sent
|
* @returns SSH_OK the message was sent
|
||||||
@@ -481,6 +504,7 @@ int ssh_scp_deny_request(ssh_scp scp, const char *reason){
|
|||||||
/**
|
/**
|
||||||
* @brief accepts transfer of a file or creation of a directory
|
* @brief accepts transfer of a file or creation of a directory
|
||||||
* coming from the remote party
|
* coming from the remote party
|
||||||
|
* @param scp the scp handle.
|
||||||
* @returns SSH_OK the message was sent
|
* @returns SSH_OK the message was sent
|
||||||
* @returns SSH_ERROR Error sending the message, or sending it in a bad state
|
* @returns SSH_ERROR Error sending the message, or sending it in a bad state
|
||||||
*/
|
*/
|
||||||
@@ -503,6 +527,7 @@ int ssh_scp_accept_request(ssh_scp scp){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Read from a remote scp file
|
/** @brief Read from a remote scp file
|
||||||
|
* @param scp the scp handle.
|
||||||
* @param buffer Destination buffer
|
* @param buffer Destination buffer
|
||||||
* @param size Size of the buffer
|
* @param size Size of the buffer
|
||||||
* @returns Number of bytes read
|
* @returns Number of bytes read
|
||||||
@@ -585,7 +610,7 @@ int ssh_scp_integer_mode(const char *mode){
|
|||||||
|
|
||||||
/** @brief Converts a unix mode into a scp string one.
|
/** @brief Converts a unix mode into a scp string one.
|
||||||
* @param mode mode to convert, e.g. 420 or 0644
|
* @param mode mode to convert, e.g. 420 or 0644
|
||||||
* @retuns pointer to a malloc'ed string containing the scp mode,
|
* @returns pointer to a malloc'ed string containing the scp mode,
|
||||||
* e.g. "0644".
|
* e.g. "0644".
|
||||||
*/
|
*/
|
||||||
char *ssh_scp_string_mode(int mode){
|
char *ssh_scp_string_mode(int mode){
|
||||||
@@ -601,3 +626,6 @@ char *ssh_scp_string_mode(int mode){
|
|||||||
const char *ssh_scp_request_get_warning(ssh_scp scp){
|
const char *ssh_scp_request_get_warning(ssh_scp scp){
|
||||||
return scp->warning;
|
return scp->warning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
|||||||
@@ -871,7 +871,7 @@ int ssh_execute_message_callbacks(ssh_session session){
|
|||||||
if(!session->ssh_message_list)
|
if(!session->ssh_message_list)
|
||||||
return SSH_OK;
|
return SSH_OK;
|
||||||
if(session->ssh_message_callback){
|
if(session->ssh_message_callback){
|
||||||
while((msg=ssh_list_get_head(ssh_message , session->ssh_message_list)) != NULL){
|
while((msg=ssh_list_pop_head(ssh_message , session->ssh_message_list)) != NULL){
|
||||||
ret=session->ssh_message_callback(session,msg);
|
ret=session->ssh_message_callback(session,msg);
|
||||||
if(ret==1){
|
if(ret==1){
|
||||||
ret = ssh_message_reply_default(msg);
|
ret = ssh_message_reply_default(msg);
|
||||||
@@ -880,7 +880,7 @@ int ssh_execute_message_callbacks(ssh_session session){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
while((msg=ssh_list_get_head(ssh_message , session->ssh_message_list)) != NULL){
|
while((msg=ssh_list_pop_head(ssh_message , session->ssh_message_list)) != NULL){
|
||||||
ret = ssh_message_reply_default(msg);
|
ret = ssh_message_reply_default(msg);
|
||||||
if(ret != SSH_OK)
|
if(ret != SSH_OK)
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -46,6 +46,8 @@
|
|||||||
*/
|
*/
|
||||||
ssh_session ssh_new(void) {
|
ssh_session ssh_new(void) {
|
||||||
ssh_session session;
|
ssh_session session;
|
||||||
|
char *id;
|
||||||
|
int rc;
|
||||||
|
|
||||||
session = malloc(sizeof (struct ssh_session_struct));
|
session = malloc(sizeof (struct ssh_session_struct));
|
||||||
if (session == NULL) {
|
if (session == NULL) {
|
||||||
@@ -95,6 +97,39 @@ ssh_session ssh_new(void) {
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
#endif /* _WIN32 */
|
#endif /* _WIN32 */
|
||||||
|
|
||||||
|
session->identity = ssh_list_new();
|
||||||
|
if (session->identity == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = strdup("SSH_DIR/id_rsa");
|
||||||
|
if (id == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rc = ssh_list_append(session->identity, id);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = strdup("SSH_DIR/id_dsa");
|
||||||
|
if (id == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rc = ssh_list_append(session->identity, id);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
id = strdup("SSH_DIR/identity");
|
||||||
|
if (id == NULL) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
rc = ssh_list_append(session->identity, id);
|
||||||
|
if (rc == SSH_ERROR) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
@@ -155,17 +190,27 @@ void ssh_free(ssh_session session) {
|
|||||||
privatekey_free(session->rsa_key);
|
privatekey_free(session->rsa_key);
|
||||||
if(session->ssh_message_list){
|
if(session->ssh_message_list){
|
||||||
ssh_message msg;
|
ssh_message msg;
|
||||||
while((msg=ssh_list_get_head(ssh_message ,session->ssh_message_list))
|
while((msg=ssh_list_pop_head(ssh_message ,session->ssh_message_list))
|
||||||
!= NULL){
|
!= NULL){
|
||||||
ssh_message_free(msg);
|
ssh_message_free(msg);
|
||||||
}
|
}
|
||||||
ssh_list_free(session->ssh_message_list);
|
ssh_list_free(session->ssh_message_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (session->identity) {
|
||||||
|
char *id;
|
||||||
|
|
||||||
|
for (id = ssh_list_pop_head(char *, session->identity);
|
||||||
|
id != NULL;
|
||||||
|
id = ssh_list_pop_head(char *, session->identity)) {
|
||||||
|
SAFE_FREE(id);
|
||||||
|
}
|
||||||
|
ssh_list_free(session->identity);
|
||||||
|
}
|
||||||
|
|
||||||
/* options */
|
/* options */
|
||||||
SAFE_FREE(session->username);
|
SAFE_FREE(session->username);
|
||||||
SAFE_FREE(session->host);
|
SAFE_FREE(session->host);
|
||||||
SAFE_FREE(session->identity);
|
|
||||||
SAFE_FREE(session->sshdir);
|
SAFE_FREE(session->sshdir);
|
||||||
SAFE_FREE(session->knownhosts);
|
SAFE_FREE(session->knownhosts);
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
/* This file contains code written by Nick Zitzmann */
|
/* This file contains code written by Nick Zitzmann */
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <ctype.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -1111,6 +1112,54 @@ static sftp_attributes sftp_parse_attr_4(sftp_session sftp, ssh_buffer buf,
|
|||||||
return attr;
|
return attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum sftp_longname_field_e {
|
||||||
|
SFTP_LONGNAME_PERM = 0,
|
||||||
|
SFTP_LONGNAME_FIXME,
|
||||||
|
SFTP_LONGNAME_OWNER,
|
||||||
|
SFTP_LONGNAME_GROUP,
|
||||||
|
SFTP_LONGNAME_SIZE,
|
||||||
|
SFTP_LONGNAME_DATE,
|
||||||
|
SFTP_LONGNAME_TIME,
|
||||||
|
SFTP_LONGNAME_NAME,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *sftp_parse_longname(const char *longname,
|
||||||
|
enum sftp_longname_field_e longname_field) {
|
||||||
|
const char *p, *q;
|
||||||
|
size_t len, field = 0;
|
||||||
|
char *x;
|
||||||
|
|
||||||
|
p = longname;
|
||||||
|
/* Find the beginning of the field which is specified by sftp_longanme_field_e. */
|
||||||
|
while(field != longname_field) {
|
||||||
|
if(isspace(*p)) {
|
||||||
|
field++;
|
||||||
|
p++;
|
||||||
|
while(*p && isspace(*p)) {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
q = p;
|
||||||
|
while (! isspace(*q)) {
|
||||||
|
q++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* There is no strndup on windows */
|
||||||
|
len = q - p + 1;
|
||||||
|
x = malloc(len);
|
||||||
|
if (x == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(x, len, "%s", p);
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
/* sftp version 0-3 code. It is different from the v4 */
|
/* sftp version 0-3 code. It is different from the v4 */
|
||||||
/* maybe a paste of the draft is better than the code */
|
/* maybe a paste of the draft is better than the code */
|
||||||
/*
|
/*
|
||||||
@@ -1157,6 +1206,19 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
string_free(longname);
|
string_free(longname);
|
||||||
|
|
||||||
|
/* Set owner and group if we talk to openssh and have the longname */
|
||||||
|
if (ssh_get_openssh_version(sftp->session)) {
|
||||||
|
attr->owner = sftp_parse_longname(attr->longname, SFTP_LONGNAME_OWNER);
|
||||||
|
if (attr->owner == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
attr->group = sftp_parse_longname(attr->longname, SFTP_LONGNAME_GROUP);
|
||||||
|
if (attr->group == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buffer_get_u32(buf, &flags) != sizeof(uint32_t)) {
|
if (buffer_get_u32(buf, &flags) != sizeof(uint32_t)) {
|
||||||
@@ -1254,6 +1316,8 @@ static sftp_attributes sftp_parse_attr_3(sftp_session sftp, ssh_buffer buf,
|
|||||||
string_free(attr->extended_data);
|
string_free(attr->extended_data);
|
||||||
SAFE_FREE(attr->name);
|
SAFE_FREE(attr->name);
|
||||||
SAFE_FREE(attr->longname);
|
SAFE_FREE(attr->longname);
|
||||||
|
SAFE_FREE(attr->owner);
|
||||||
|
SAFE_FREE(attr->group);
|
||||||
SAFE_FREE(attr);
|
SAFE_FREE(attr);
|
||||||
|
|
||||||
ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
|
ssh_set_error(sftp->session, SSH_FATAL, "Invalid ATTR structure");
|
||||||
|
|||||||
Reference in New Issue
Block a user