mirror of
https://git.libssh.org/projects/libssh.git
synced 2025-08-07 08:02:55 +03:00
patches 0001-Save-the-last-error-and-provide-a-function-to-get-it.patch,
0002-Use-const-whereever-it-makes-sense.patch, 0003-Implement-function-to-retrieve-userauth-possabilitie.patch from Andreas Schneider git-svn-id: svn+ssh://svn.berlios.de/svnroot/repos/libssh/trunk@191 7dcaeef0-15fb-0310-b436-a5af3365683c
This commit is contained in:
@@ -91,6 +91,11 @@ typedef int socket_t;
|
|||||||
#define SSH_AUTH_INFO 3
|
#define SSH_AUTH_INFO 3
|
||||||
#define SSH_AUTH_ERROR -1
|
#define SSH_AUTH_ERROR -1
|
||||||
|
|
||||||
|
#define SSH_AUTH_METHOD_PASSWORD 0x0001
|
||||||
|
#define SSH_AUTH_METHOD_PUBLICKEY 0x0002
|
||||||
|
#define SSH_AUTH_METHOD_HOSTBASED 0x0004
|
||||||
|
#define SSH_AUTH_METHOD_INTERACTIVE 0x0008
|
||||||
|
|
||||||
/* status flags */
|
/* status flags */
|
||||||
|
|
||||||
#define SSH_CLOSED (1<<0)
|
#define SSH_CLOSED (1<<0)
|
||||||
@@ -120,7 +125,7 @@ typedef int socket_t;
|
|||||||
|
|
||||||
char *ssh_get_error(void *error);
|
char *ssh_get_error(void *error);
|
||||||
int ssh_get_error_code(void *error);
|
int ssh_get_error_code(void *error);
|
||||||
void ssh_say(int priority,char *format,...);
|
void ssh_say(int priority, const char *format, ...);
|
||||||
void ssh_set_verbosity(int num);
|
void ssh_set_verbosity(int num);
|
||||||
/** \addtogroup ssh_log
|
/** \addtogroup ssh_log
|
||||||
* @{
|
* @{
|
||||||
@@ -178,12 +183,12 @@ const char *ssh_copyright();
|
|||||||
|
|
||||||
/* You can use these functions, they won't change */
|
/* You can use these functions, they won't change */
|
||||||
/* makestring returns a newly allocated string from a char * ptr */
|
/* makestring returns a newly allocated string from a char * ptr */
|
||||||
STRING *string_from_char(char *what);
|
STRING *string_from_char(const char *what);
|
||||||
/* it returns the string len in host byte orders. str->size is big endian warning ! */
|
/* it returns the string len in host byte orders. str->size is big endian warning ! */
|
||||||
int string_len(STRING *str);
|
int string_len(STRING *str);
|
||||||
STRING *string_new(unsigned int size);
|
STRING *string_new(unsigned int size);
|
||||||
/* string_fill copies the data in the string. it does NOT check for boundary so allocate enough place with string_new */
|
/* string_fill copies the data in the string. it does NOT check for boundary so allocate enough place with string_new */
|
||||||
void string_fill(STRING *str,void *data,int len);
|
void string_fill(STRING *str, const void *data,int len);
|
||||||
/* returns a newly allocated char array with the str string and a final nul caracter */
|
/* returns a newly allocated char array with the str string and a final nul caracter */
|
||||||
char *string_to_char(STRING *str);
|
char *string_to_char(STRING *str);
|
||||||
STRING *string_copy(STRING *str);
|
STRING *string_copy(STRING *str);
|
||||||
@@ -196,7 +201,7 @@ void string_free(STRING *str);
|
|||||||
void ssh_crypto_init();
|
void ssh_crypto_init();
|
||||||
|
|
||||||
/* useful for debug */
|
/* useful for debug */
|
||||||
void ssh_print_hexa(char *descr,unsigned char *what, int len);
|
void ssh_print_hexa(char *descr, const unsigned char *what, int len);
|
||||||
int ssh_get_random(void *where,int len,int strong);
|
int ssh_get_random(void *where,int len,int strong);
|
||||||
|
|
||||||
/* this one can be called by the client to see the hash of the public key before accepting it */
|
/* this one can be called by the client to see the hash of the public key before accepting it */
|
||||||
@@ -250,25 +255,25 @@ int channel_select(CHANNEL **readchans, CHANNEL **writechans, CHANNEL **exceptch
|
|||||||
|
|
||||||
SSH_OPTIONS *ssh_options_new();
|
SSH_OPTIONS *ssh_options_new();
|
||||||
SSH_OPTIONS *ssh_options_copy(SSH_OPTIONS *opt);
|
SSH_OPTIONS *ssh_options_copy(SSH_OPTIONS *opt);
|
||||||
int ssh_options_set_wanted_algos(SSH_OPTIONS *opt,int algo, char *list);
|
int ssh_options_set_wanted_algos(SSH_OPTIONS *opt, int algo, const char *list);
|
||||||
void ssh_options_set_username(SSH_OPTIONS *opt,char *username);
|
void ssh_options_set_username(SSH_OPTIONS *opt, const char *username);
|
||||||
void ssh_options_set_port(SSH_OPTIONS *opt, unsigned int port);
|
void ssh_options_set_port(SSH_OPTIONS *opt, unsigned int port);
|
||||||
int ssh_options_getopt(SSH_OPTIONS *options, int *argcptr, char **argv);
|
int ssh_options_getopt(SSH_OPTIONS *options, int *argcptr, char **argv);
|
||||||
void ssh_options_set_host(SSH_OPTIONS *opt, const char *host);
|
void ssh_options_set_host(SSH_OPTIONS *opt, const char *host);
|
||||||
void ssh_options_set_fd(SSH_OPTIONS *opt, socket_t fd);
|
void ssh_options_set_fd(SSH_OPTIONS *opt, socket_t fd);
|
||||||
void ssh_options_set_bind(SSH_OPTIONS *opt, char *bindaddr,int port);
|
void ssh_options_set_bind(SSH_OPTIONS *opt, const char *bindaddr, int port);
|
||||||
void ssh_options_set_identity(SSH_OPTIONS *opt, char *identity);
|
void ssh_options_set_identity(SSH_OPTIONS *opt, const char *identity);
|
||||||
void ssh_options_set_status_callback(SSH_OPTIONS *opt, void (*callback)
|
void ssh_options_set_status_callback(SSH_OPTIONS *opt, void (*callback)
|
||||||
(void *arg, float status), void *arg);
|
(void *arg, float status), void *arg);
|
||||||
void ssh_options_set_timeout(SSH_OPTIONS *opt, long seconds, long usec);
|
void ssh_options_set_timeout(SSH_OPTIONS *opt, long seconds, long usec);
|
||||||
void ssh_options_set_ssh_dir(SSH_OPTIONS *opt, char *dir);
|
void ssh_options_set_ssh_dir(SSH_OPTIONS *opt, const char *dir);
|
||||||
void ssh_options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir);
|
void ssh_options_set_known_hosts_file(SSH_OPTIONS *opt, const char *dir);
|
||||||
void ssh_options_allow_ssh1(SSH_OPTIONS *opt, int allow);
|
void ssh_options_allow_ssh1(SSH_OPTIONS *opt, int allow);
|
||||||
void ssh_options_allow_ssh2(SSH_OPTIONS *opt, int allow);
|
void ssh_options_allow_ssh2(SSH_OPTIONS *opt, int allow);
|
||||||
void ssh_options_set_dsa_server_key(SSH_OPTIONS *opt, char *dsakey);
|
void ssh_options_set_dsa_server_key(SSH_OPTIONS *opt, const char *dsakey);
|
||||||
void ssh_options_set_rsa_server_key(SSH_OPTIONS *opt, char *rsakey);
|
void ssh_options_set_rsa_server_key(SSH_OPTIONS *opt, const char *rsakey);
|
||||||
void ssh_options_set_log_function(SSH_OPTIONS *opt,
|
void ssh_options_set_log_function(SSH_OPTIONS *opt,
|
||||||
void (*callback)(const char *message, SSH_SESSION *session, int verbosity ));
|
void (*callback)(const char *message, SSH_SESSION *session, int verbosity ));
|
||||||
void ssh_options_set_log_verbosity(SSH_OPTIONS *opt, int verbosity);
|
void ssh_options_set_log_verbosity(SSH_OPTIONS *opt, int verbosity);
|
||||||
|
|
||||||
|
|
||||||
@@ -289,17 +294,18 @@ int buffer_get_len(BUFFER *buffer);
|
|||||||
AUTH_SUCCESS if success,
|
AUTH_SUCCESS if success,
|
||||||
AUTH_PARTIAL if partial success,
|
AUTH_PARTIAL if partial success,
|
||||||
AUTH_DENIED if refused */
|
AUTH_DENIED if refused */
|
||||||
int ssh_userauth_none(SSH_SESSION *session,char *username);
|
int ssh_userauth_list(SSH_SESSION *session, const char *username);
|
||||||
int ssh_userauth_password(SSH_SESSION *session,char *username,char *password);
|
int ssh_userauth_none(SSH_SESSION *session, const char *username);
|
||||||
int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STRING *publickey);
|
int ssh_userauth_password(SSH_SESSION *session, const char *username, const char *password);
|
||||||
int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey, PRIVATE_KEY *privatekey);
|
int ssh_userauth_offer_pubkey(SSH_SESSION *session, const char *username, int type, STRING *publickey);
|
||||||
|
int ssh_userauth_pubkey(SSH_SESSION *session, const char *username, STRING *publickey, PRIVATE_KEY *privatekey);
|
||||||
int ssh_userauth_autopubkey(SSH_SESSION *session);
|
int ssh_userauth_autopubkey(SSH_SESSION *session);
|
||||||
int ssh_userauth_kbdint(SSH_SESSION *session, char *user, char *submethods);
|
int ssh_userauth_kbdint(SSH_SESSION *session, const char *user, const char *submethods);
|
||||||
int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session);
|
int ssh_userauth_kbdint_getnprompts(SSH_SESSION *session);
|
||||||
char *ssh_userauth_kbdint_getname(SSH_SESSION *session);
|
char *ssh_userauth_kbdint_getname(SSH_SESSION *session);
|
||||||
char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session);
|
char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session);
|
||||||
char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, int i, char *echo);
|
char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, int i, char *echo);
|
||||||
void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, char *answer);
|
void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, const char *answer);
|
||||||
|
|
||||||
|
|
||||||
/* init.c */
|
/* init.c */
|
||||||
|
@@ -504,10 +504,10 @@ void ssh_send_kex(SSH_SESSION *session,int server_kex);
|
|||||||
void ssh_list_kex(KEX *kex);
|
void ssh_list_kex(KEX *kex);
|
||||||
int set_kex(SSH_SESSION *session);
|
int set_kex(SSH_SESSION *session);
|
||||||
int ssh_get_kex(SSH_SESSION *session, int server_kex);
|
int ssh_get_kex(SSH_SESSION *session, int server_kex);
|
||||||
int verify_existing_algo(int algo,char *name);
|
int verify_existing_algo(int algo, const char *name);
|
||||||
char **space_tokenize(char *chain);
|
char **space_tokenize(const char *chain);
|
||||||
int ssh_get_kex1(SSH_SESSION *session);
|
int ssh_get_kex1(SSH_SESSION *session);
|
||||||
char *ssh_find_matching(char *in_d, char *what_d);
|
char *ssh_find_matching(const char *in_d, const char *what_d);
|
||||||
|
|
||||||
/* in keyfiles.c */
|
/* in keyfiles.c */
|
||||||
|
|
||||||
|
@@ -34,6 +34,7 @@ typedef struct sftp_session_struct {
|
|||||||
int version;
|
int version;
|
||||||
struct request_queue *queue;
|
struct request_queue *queue;
|
||||||
u32 id_counter;
|
u32 id_counter;
|
||||||
|
int errnum;
|
||||||
void **handles;
|
void **handles;
|
||||||
} SFTP_SESSION ;
|
} SFTP_SESSION ;
|
||||||
|
|
||||||
@@ -131,33 +132,34 @@ typedef struct sftp_attributes{
|
|||||||
SFTP_SESSION *sftp_new(SSH_SESSION *session);
|
SFTP_SESSION *sftp_new(SSH_SESSION *session);
|
||||||
void sftp_free(SFTP_SESSION *sftp);
|
void sftp_free(SFTP_SESSION *sftp);
|
||||||
int sftp_init(SFTP_SESSION *sftp);
|
int sftp_init(SFTP_SESSION *sftp);
|
||||||
SFTP_DIR *sftp_opendir(SFTP_SESSION *session, char *path);
|
int sftp_get_error(SFTP_SESSION *sftp);
|
||||||
|
SFTP_DIR *sftp_opendir(SFTP_SESSION *session, const char *path);
|
||||||
/* reads one file and attribute from opened directory. fails at end */
|
/* reads one file and attribute from opened directory. fails at end */
|
||||||
SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *session, SFTP_DIR *dir);
|
SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *session, SFTP_DIR *dir);
|
||||||
/* returns 1 if the directory was EOF */
|
/* returns 1 if the directory was EOF */
|
||||||
int sftp_dir_eof(SFTP_DIR *dir);
|
int sftp_dir_eof(SFTP_DIR *dir);
|
||||||
SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, char *path);
|
SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, const char *path);
|
||||||
SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, char *path);
|
SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, const char *path);
|
||||||
/* sftp_lstat stats a file but doesn't follow symlinks */
|
/* sftp_lstat stats a file but doesn't follow symlinks */
|
||||||
SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file);
|
SFTP_ATTRIBUTES *sftp_fstat(SFTP_FILE *file);
|
||||||
void sftp_attributes_free(SFTP_ATTRIBUTES *file);
|
void sftp_attributes_free(SFTP_ATTRIBUTES *file);
|
||||||
int sftp_dir_close(SFTP_DIR *dir);
|
int sftp_dir_close(SFTP_DIR *dir);
|
||||||
int sftp_file_close(SFTP_FILE *file);
|
int sftp_file_close(SFTP_FILE *file);
|
||||||
/* access are the sames than the ones from ansi fopen() */
|
/* access are the sames than the ones from ansi fopen() */
|
||||||
SFTP_FILE *sftp_open(SFTP_SESSION *session, char *file, int access, SFTP_ATTRIBUTES *attr);
|
SFTP_FILE *sftp_open(SFTP_SESSION *session, const char *file, int access, SFTP_ATTRIBUTES *attr);
|
||||||
int sftp_read(SFTP_FILE *file, void *dest, int len);
|
int sftp_read(SFTP_FILE *file, void *dest, int len);
|
||||||
u32 sftp_async_read_begin(SFTP_FILE *file, int len);
|
u32 sftp_async_read_begin(SFTP_FILE *file, int len);
|
||||||
int sftp_async_read(SFTP_FILE *file, void *data, int len, u32 id);
|
int sftp_async_read(SFTP_FILE *file, void *data, int len, u32 id);
|
||||||
int sftp_write(SFTP_FILE *file, void *source, int len);
|
int sftp_write(SFTP_FILE *file, const void *source, int len);
|
||||||
void sftp_seek(SFTP_FILE *file, int new_offset);
|
void sftp_seek(SFTP_FILE *file, int new_offset);
|
||||||
unsigned long sftp_tell(SFTP_FILE *file);
|
unsigned long sftp_tell(SFTP_FILE *file);
|
||||||
void sftp_rewind(SFTP_FILE *file);
|
void sftp_rewind(SFTP_FILE *file);
|
||||||
int sftp_rm(SFTP_SESSION *sftp, char *file);
|
int sftp_rm(SFTP_SESSION *sftp, char *file);
|
||||||
int sftp_rmdir(SFTP_SESSION *sftp, char *directory);
|
int sftp_rmdir(SFTP_SESSION *sftp, const char *directory);
|
||||||
int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr);
|
int sftp_mkdir(SFTP_SESSION *sftp, const char *directory, SFTP_ATTRIBUTES *attr);
|
||||||
int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname);
|
int sftp_rename(SFTP_SESSION *sftp, const char *original, const char *newname);
|
||||||
int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr);
|
int sftp_setstat(SFTP_SESSION *sftp, const char *file, SFTP_ATTRIBUTES *attr);
|
||||||
char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path);
|
char *sftp_canonicalize_path(SFTP_SESSION *sftp, const char *path);
|
||||||
|
|
||||||
#ifndef NO_SERVER
|
#ifndef NO_SERVER
|
||||||
SFTP_SESSION *sftp_server_new(SSH_SESSION *session, CHANNEL *chan);
|
SFTP_SESSION *sftp_server_new(SSH_SESSION *session, CHANNEL *chan);
|
||||||
|
@@ -52,9 +52,10 @@ static void burn(char *ptr){
|
|||||||
static int wait_auth_status(SSH_SESSION *session,int kbdint){
|
static int wait_auth_status(SSH_SESSION *session,int kbdint){
|
||||||
int err=SSH_AUTH_ERROR;
|
int err=SSH_AUTH_ERROR;
|
||||||
int cont=1;
|
int cont=1;
|
||||||
STRING *can_continue;
|
STRING *auth;
|
||||||
u8 partial=0;
|
u8 partial=0;
|
||||||
char *c_cont;
|
int todo = 0;
|
||||||
|
char *auth_methods = NULL;
|
||||||
enter_function();
|
enter_function();
|
||||||
while(cont){
|
while(cont){
|
||||||
if(packet_read(session))
|
if(packet_read(session))
|
||||||
@@ -63,24 +64,39 @@ static int wait_auth_status(SSH_SESSION *session,int kbdint){
|
|||||||
break;
|
break;
|
||||||
switch(session->in_packet.type){
|
switch(session->in_packet.type){
|
||||||
case SSH2_MSG_USERAUTH_FAILURE:
|
case SSH2_MSG_USERAUTH_FAILURE:
|
||||||
can_continue=buffer_get_ssh_string(session->in_buffer);
|
auth = buffer_get_ssh_string(session->in_buffer);
|
||||||
if(!can_continue || buffer_get_u8(session->in_buffer,&partial)!=1 ){
|
if(!auth || buffer_get_u8(session->in_buffer,&partial)!=1 ){
|
||||||
ssh_set_error(session,SSH_FATAL,
|
ssh_set_error(session,SSH_FATAL,
|
||||||
"invalid SSH_MSG_USERAUTH_FAILURE message");
|
"invalid SSH_MSG_USERAUTH_FAILURE message");
|
||||||
leave_function();
|
leave_function();
|
||||||
return SSH_AUTH_ERROR;
|
return SSH_AUTH_ERROR;
|
||||||
}
|
}
|
||||||
c_cont=string_to_char(can_continue);
|
auth_methods = string_to_char(auth);
|
||||||
if(partial){
|
if(partial) {
|
||||||
err=SSH_AUTH_PARTIAL;
|
err=SSH_AUTH_PARTIAL;
|
||||||
ssh_set_error(session,SSH_NO_ERROR,"partial success, authentications that can continue : %s",c_cont);
|
ssh_set_error(session,SSH_NO_ERROR,"partial success, authentications that can continue : %s", auth_methods);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
err=SSH_AUTH_DENIED;
|
err=SSH_AUTH_DENIED;
|
||||||
ssh_set_error(session,SSH_REQUEST_DENIED,"Access denied. authentications that can continue : %s",c_cont);
|
ssh_set_error(session,SSH_REQUEST_DENIED,"Access denied. authentications that can continue : %s", auth_methods);
|
||||||
|
|
||||||
|
session->auth_methods = 0;
|
||||||
|
if (strstr(auth_methods, "password") != NULL) {
|
||||||
|
session->auth_methods |= SSH_AUTH_METHOD_PASSWORD;
|
||||||
|
}
|
||||||
|
if (strstr(auth_methods, "keyboard-interactive") != NULL) {
|
||||||
|
session->auth_methods |= SSH_AUTH_METHOD_INTERACTIVE;
|
||||||
|
}
|
||||||
|
if (strstr(auth_methods, "publickey") != NULL) {
|
||||||
|
session->auth_methods |= SSH_AUTH_METHOD_PUBLICKEY;
|
||||||
|
}
|
||||||
|
if (strstr(auth_methods, "hostbased") != NULL) {
|
||||||
|
session->auth_methods |= SSH_AUTH_METHOD_HOSTBASED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
free(can_continue);
|
|
||||||
free(c_cont);
|
|
||||||
|
free(auth);
|
||||||
|
free(auth_methods);
|
||||||
cont=0;
|
cont=0;
|
||||||
break;
|
break;
|
||||||
case SSH2_MSG_USERAUTH_PK_OK:
|
case SSH2_MSG_USERAUTH_PK_OK:
|
||||||
@@ -120,6 +136,13 @@ static int wait_auth_status(SSH_SESSION *session,int kbdint){
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ssh_auth_list(SSH_SESSION *session) {
|
||||||
|
if (session == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return session->auth_methods;
|
||||||
|
}
|
||||||
|
|
||||||
/* use the "none" authentication question */
|
/* use the "none" authentication question */
|
||||||
|
|
||||||
/** \brief Try to authenticate through the "none" method
|
/** \brief Try to authenticate through the "none" method
|
||||||
@@ -132,7 +155,7 @@ static int wait_auth_status(SSH_SESSION *session,int kbdint){
|
|||||||
* SSH_AUTH_SUCCESS : Authentication success
|
* SSH_AUTH_SUCCESS : Authentication success
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ssh_userauth_none(SSH_SESSION *session,char *username){
|
int ssh_userauth_none(SSH_SESSION *session, const char *username){
|
||||||
STRING *user;
|
STRING *user;
|
||||||
STRING *service;
|
STRING *service;
|
||||||
STRING *method;
|
STRING *method;
|
||||||
@@ -188,7 +211,7 @@ int ssh_userauth_none(SSH_SESSION *session,char *username){
|
|||||||
* \see ssh_userauth_pubkey()
|
* \see ssh_userauth_pubkey()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STRING *publickey){
|
int ssh_userauth_offer_pubkey(SSH_SESSION *session, const char *username,int type, STRING *publickey){
|
||||||
STRING *user;
|
STRING *user;
|
||||||
STRING *service;
|
STRING *service;
|
||||||
STRING *method;
|
STRING *method;
|
||||||
@@ -253,7 +276,7 @@ int ssh_userauth_offer_pubkey(SSH_SESSION *session, char *username,int type, STR
|
|||||||
* \see ssh_userauth_offer_pubkey()
|
* \see ssh_userauth_offer_pubkey()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey, PRIVATE_KEY *privatekey){
|
int ssh_userauth_pubkey(SSH_SESSION *session, const char *username, STRING *publickey, PRIVATE_KEY *privatekey){
|
||||||
STRING *user;
|
STRING *user;
|
||||||
STRING *service;
|
STRING *service;
|
||||||
STRING *method;
|
STRING *method;
|
||||||
@@ -317,7 +340,7 @@ int ssh_userauth_pubkey(SSH_SESSION *session, char *username, STRING *publickey,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
int ssh_userauth_password(SSH_SESSION *session,char *username,char *password){
|
int ssh_userauth_password(SSH_SESSION *session, const char *username, const char *password){
|
||||||
STRING *user;
|
STRING *user;
|
||||||
STRING *service;
|
STRING *service;
|
||||||
STRING *method;
|
STRING *method;
|
||||||
@@ -556,7 +579,7 @@ static void kbdint_clean(struct ssh_kbdint *kbd){
|
|||||||
/* this function sends the first packet as explained in section 3.1
|
/* this function sends the first packet as explained in section 3.1
|
||||||
* of the draft */
|
* of the draft */
|
||||||
static int kbdauth_init(SSH_SESSION *session,
|
static int kbdauth_init(SSH_SESSION *session,
|
||||||
char *user, char *submethods){
|
const char *user, const char *submethods){
|
||||||
STRING *user_s=string_from_char(user);
|
STRING *user_s=string_from_char(user);
|
||||||
STRING *submethods_s=(submethods ? string_from_char(submethods): string_from_char(""));
|
STRING *submethods_s=(submethods ? string_from_char(submethods): string_from_char(""));
|
||||||
STRING *service=string_from_char("ssh-connection");
|
STRING *service=string_from_char("ssh-connection");
|
||||||
@@ -684,7 +707,7 @@ static int kbdauth_send(SSH_SESSION *session) {
|
|||||||
|
|
||||||
|
|
||||||
/* the heart of the whole keyboard interactive login */
|
/* the heart of the whole keyboard interactive login */
|
||||||
int ssh_userauth_kbdint(SSH_SESSION *session,char *user,char *submethods){
|
int ssh_userauth_kbdint(SSH_SESSION *session, const char *user, const char *submethods){
|
||||||
int err;
|
int err;
|
||||||
if(session->version==1)
|
if(session->version==1)
|
||||||
return SSH_AUTH_DENIED; // no keyb-interactive for ssh1
|
return SSH_AUTH_DENIED; // no keyb-interactive for ssh1
|
||||||
@@ -779,7 +802,7 @@ char *ssh_userauth_kbdint_getinstruction(SSH_SESSION *session){
|
|||||||
* \returns pointer to the prompt. Do not free it
|
* \returns pointer to the prompt. Do not free it
|
||||||
*/
|
*/
|
||||||
|
|
||||||
char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, int i,
|
char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, int i,
|
||||||
char *echo){
|
char *echo){
|
||||||
if(i > session->kbdint->nprompts || i<0)
|
if(i > session->kbdint->nprompts || i<0)
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -796,7 +819,7 @@ char *ssh_userauth_kbdint_getprompt(SSH_SESSION *session, int i,
|
|||||||
* \param answer answer to give to server
|
* \param answer answer to give to server
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, char *answer){
|
void ssh_userauth_kbdint_setanswer(SSH_SESSION *session, unsigned int i, const char *answer){
|
||||||
if (i>session->kbdint->nprompts)
|
if (i>session->kbdint->nprompts)
|
||||||
return;
|
return;
|
||||||
if(!session->kbdint->answers){
|
if(!session->kbdint->answers){
|
||||||
|
@@ -129,7 +129,7 @@ void ssh_print_bignum(char *which,bignum num){
|
|||||||
free(hex);
|
free(hex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssh_print_hexa(char *descr,unsigned char *what, int len){
|
void ssh_print_hexa(char *descr, const unsigned char *what, int len){
|
||||||
int i;
|
int i;
|
||||||
printf("%s : ",descr);
|
printf("%s : ",descr);
|
||||||
if(len>16)
|
if(len>16)
|
||||||
|
@@ -64,7 +64,7 @@ int ssh_get_error_code(void *error){
|
|||||||
return err->error_code;
|
return err->error_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ssh_say(int priority, char *format,...){
|
void ssh_say(int priority, const char *format, ...){
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va,format);
|
va_start(va,format);
|
||||||
if(priority <= verbosity)
|
if(priority <= verbosity)
|
||||||
|
18
libssh/kex.c
18
libssh/kex.c
@@ -63,11 +63,12 @@ char *ssh_kex_nums[]={
|
|||||||
"compression algo server->client","languages client->server","languages server->client",NULL};
|
"compression algo server->client","languages client->server","languages server->client",NULL};
|
||||||
|
|
||||||
/* tokenize will return a token of strings delimited by ",". the first element has to be freed */
|
/* tokenize will return a token of strings delimited by ",". the first element has to be freed */
|
||||||
static char **tokenize(char *chain){
|
static char **tokenize(const char *chain){
|
||||||
char **tokens;
|
char **tokens;
|
||||||
int n=1;
|
int n=1;
|
||||||
int i=0;
|
int i=0;
|
||||||
char *ptr=chain=strdup(chain);
|
char *tmp = strdup(chain);
|
||||||
|
char *ptr = tmp;
|
||||||
while(*ptr){
|
while(*ptr){
|
||||||
if(*ptr==','){
|
if(*ptr==','){
|
||||||
n++;
|
n++;
|
||||||
@@ -77,7 +78,7 @@ static char **tokenize(char *chain){
|
|||||||
}
|
}
|
||||||
/* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
|
/* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
|
||||||
tokens=malloc(sizeof(char *) * (n+1) ); /* +1 for the null */
|
tokens=malloc(sizeof(char *) * (n+1) ); /* +1 for the null */
|
||||||
ptr=chain;
|
ptr=tmp;
|
||||||
for(i=0;i<n;i++){
|
for(i=0;i<n;i++){
|
||||||
tokens[i]=ptr;
|
tokens[i]=ptr;
|
||||||
while(*ptr)
|
while(*ptr)
|
||||||
@@ -89,11 +90,12 @@ static char **tokenize(char *chain){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* same as tokenize(), but with spaces instead of ',' */
|
/* same as tokenize(), but with spaces instead of ',' */
|
||||||
char **space_tokenize(char *chain){
|
char **space_tokenize(const char *chain){
|
||||||
char **tokens;
|
char **tokens;
|
||||||
int n=1;
|
int n=1;
|
||||||
int i=0;
|
int i=0;
|
||||||
char *ptr=chain=strdup(chain);
|
char *tmp = strdup(chain);
|
||||||
|
char *ptr = tmp;
|
||||||
while(*ptr==' ')
|
while(*ptr==' ')
|
||||||
++ptr; /* skip initial spaces */
|
++ptr; /* skip initial spaces */
|
||||||
while(*ptr){
|
while(*ptr){
|
||||||
@@ -108,7 +110,7 @@ char **space_tokenize(char *chain){
|
|||||||
}
|
}
|
||||||
/* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
|
/* now n contains the number of tokens, the first possibly empty if the list was empty too e.g. "" */
|
||||||
tokens=malloc(sizeof(char *) * (n+1) ); /* +1 for the null */
|
tokens=malloc(sizeof(char *) * (n+1) ); /* +1 for the null */
|
||||||
ptr=chain; /* we don't pass the initial spaces because the "chain" pointer is needed by the caller */
|
ptr=tmp; /* we don't pass the initial spaces because the "tmp" pointer is needed by the caller */
|
||||||
/* function to free the tokens. */
|
/* function to free the tokens. */
|
||||||
for(i=0;i<n;i++){
|
for(i=0;i<n;i++){
|
||||||
tokens[i]=ptr;
|
tokens[i]=ptr;
|
||||||
@@ -128,7 +130,7 @@ char **space_tokenize(char *chain){
|
|||||||
/* and a list of prefered objects (what_d) */
|
/* and a list of prefered objects (what_d) */
|
||||||
/* it will return a strduped pointer on the first prefered object found in the available objects list */
|
/* it will return a strduped pointer on the first prefered object found in the available objects list */
|
||||||
|
|
||||||
char *ssh_find_matching(char *in_d, char *what_d){
|
char *ssh_find_matching(const char *in_d, const char *what_d){
|
||||||
char ** tok_in, **tok_what;
|
char ** tok_in, **tok_what;
|
||||||
int i_in, i_what;
|
int i_in, i_what;
|
||||||
char *ret;
|
char *ret;
|
||||||
@@ -272,7 +274,7 @@ void ssh_send_kex(SSH_SESSION *session, int server_kex){
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* returns 1 if at least one of the name algos is in the default algorithms table */
|
/* returns 1 if at least one of the name algos is in the default algorithms table */
|
||||||
int verify_existing_algo(int algo, char *name){
|
int verify_existing_algo(int algo, const char *name){
|
||||||
char *ptr;
|
char *ptr;
|
||||||
if(algo>9 || algo <0)
|
if(algo>9 || algo <0)
|
||||||
return -1;
|
return -1;
|
||||||
|
@@ -166,7 +166,7 @@ void ssh_options_set_host(SSH_OPTIONS *opt, const char *hostname){
|
|||||||
* \param opt options structure
|
* \param opt options structure
|
||||||
* \param username user name to authenticate
|
* \param username user name to authenticate
|
||||||
*/
|
*/
|
||||||
void ssh_options_set_username(SSH_OPTIONS *opt, char *username){
|
void ssh_options_set_username(SSH_OPTIONS *opt, const char *username){
|
||||||
if(opt->username)
|
if(opt->username)
|
||||||
free(opt->username);
|
free(opt->username);
|
||||||
opt->username=strdup(username);
|
opt->username=strdup(username);
|
||||||
@@ -193,7 +193,7 @@ void ssh_options_set_fd(SSH_OPTIONS *opt, socket_t fd){
|
|||||||
* \param bindaddr bind address in form of hostname or ip address
|
* \param bindaddr bind address in form of hostname or ip address
|
||||||
* \param port port number to bind
|
* \param port port number to bind
|
||||||
*/
|
*/
|
||||||
void ssh_options_set_bind(SSH_OPTIONS *opt, char *bindaddr,int port){
|
void ssh_options_set_bind(SSH_OPTIONS *opt, const char *bindaddr, int port){
|
||||||
opt->bindaddr=strdup(bindaddr);
|
opt->bindaddr=strdup(bindaddr);
|
||||||
opt->bindport=port;
|
opt->bindport=port;
|
||||||
}
|
}
|
||||||
@@ -206,7 +206,7 @@ void ssh_options_set_bind(SSH_OPTIONS *opt, char *bindaddr,int port){
|
|||||||
* the user home directory
|
* the user home directory
|
||||||
* \see ssh_options_set_user_home_dir()
|
* \see ssh_options_set_user_home_dir()
|
||||||
*/
|
*/
|
||||||
void ssh_options_set_ssh_dir(SSH_OPTIONS *opt, char *dir){
|
void ssh_options_set_ssh_dir(SSH_OPTIONS *opt, const char *dir){
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
snprintf(buffer,1024,dir,ssh_get_user_home_dir());
|
snprintf(buffer,1024,dir,ssh_get_user_home_dir());
|
||||||
opt->ssh_dir=strdup(buffer);
|
opt->ssh_dir=strdup(buffer);
|
||||||
@@ -219,7 +219,7 @@ void ssh_options_set_ssh_dir(SSH_OPTIONS *opt, char *dir){
|
|||||||
* with the user home directory
|
* with the user home directory
|
||||||
* \see ssh_options_set_user_home_dir()
|
* \see ssh_options_set_user_home_dir()
|
||||||
*/
|
*/
|
||||||
void ssh_options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir){
|
void ssh_options_set_known_hosts_file(SSH_OPTIONS *opt, const char *dir){
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
snprintf(buffer,1024,dir,ssh_get_user_home_dir());
|
snprintf(buffer,1024,dir,ssh_get_user_home_dir());
|
||||||
opt->known_hosts_file=strdup(buffer);
|
opt->known_hosts_file=strdup(buffer);
|
||||||
@@ -232,7 +232,7 @@ void ssh_options_set_known_hosts_file(SSH_OPTIONS *opt, char *dir){
|
|||||||
* with the user home directory
|
* with the user home directory
|
||||||
* \see ssh_options_set_user_home_dir()
|
* \see ssh_options_set_user_home_dir()
|
||||||
*/
|
*/
|
||||||
void ssh_options_set_identity(SSH_OPTIONS *opt, char *identity){
|
void ssh_options_set_identity(SSH_OPTIONS *opt, const char *identity){
|
||||||
char buffer[1024];
|
char buffer[1024];
|
||||||
snprintf(buffer,1024,identity,ssh_get_user_home_dir());
|
snprintf(buffer,1024,identity,ssh_get_user_home_dir());
|
||||||
opt->identity=strdup(buffer);
|
opt->identity=strdup(buffer);
|
||||||
@@ -241,13 +241,13 @@ void ssh_options_set_identity(SSH_OPTIONS *opt, char *identity){
|
|||||||
/** \warning I don't remember what these functions are supposed
|
/** \warning I don't remember what these functions are supposed
|
||||||
* to set
|
* to set
|
||||||
*/
|
*/
|
||||||
void ssh_options_set_dsa_server_key(SSH_OPTIONS *opt, char *dsakey){
|
void ssh_options_set_dsa_server_key(SSH_OPTIONS *opt, const char *dsakey){
|
||||||
opt->dsakey=strdup(dsakey);
|
opt->dsakey=strdup(dsakey);
|
||||||
}
|
}
|
||||||
/** \warning I don't remember what these functions are supposed
|
/** \warning I don't remember what these functions are supposed
|
||||||
* to set
|
* to set
|
||||||
*/
|
*/
|
||||||
void ssh_options_set_rsa_server_key(SSH_OPTIONS *opt, char *rsakey){
|
void ssh_options_set_rsa_server_key(SSH_OPTIONS *opt, const char *rsakey){
|
||||||
opt->rsakey=strdup(rsakey);
|
opt->rsakey=strdup(rsakey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,7 +255,7 @@ void ssh_options_set_rsa_server_key(SSH_OPTIONS *opt, char *rsakey){
|
|||||||
* \param opt options structure
|
* \param opt options structure
|
||||||
* \param banner a text banner to be shown
|
* \param banner a text banner to be shown
|
||||||
*/
|
*/
|
||||||
void ssh_options_set_banner(SSH_OPTIONS *opt, char *banner){
|
void ssh_options_set_banner(SSH_OPTIONS *opt, const char *banner){
|
||||||
if(opt->banner)
|
if(opt->banner)
|
||||||
free(opt->banner);
|
free(opt->banner);
|
||||||
opt->banner=strdup(banner);
|
opt->banner=strdup(banner);
|
||||||
@@ -277,7 +277,7 @@ void ssh_options_set_banner(SSH_OPTIONS *opt, char *banner){
|
|||||||
* \param list list of algorithms to be used, in order of preference and separated by commas
|
* \param list list of algorithms to be used, in order of preference and separated by commas
|
||||||
* \return 0 on success, -1 on error (most likely an algorithm is not available)
|
* \return 0 on success, -1 on error (most likely an algorithm is not available)
|
||||||
*/
|
*/
|
||||||
int ssh_options_set_wanted_algos(SSH_OPTIONS *opt,int algo, char *list){
|
int ssh_options_set_wanted_algos(SSH_OPTIONS *opt, int algo, const char *list){
|
||||||
if(algo > SSH_LANG_S_C || algo < 0){
|
if(algo > SSH_LANG_S_C || algo < 0){
|
||||||
ssh_set_error(opt,SSH_REQUEST_DENIED,"algo %d out of range",algo);
|
ssh_set_error(opt,SSH_REQUEST_DENIED,"algo %d out of range",algo);
|
||||||
return -1;
|
return -1;
|
||||||
|
@@ -43,6 +43,7 @@ SSH_SESSION *ssh_new() {
|
|||||||
session->maxchannel=FIRST_CHANNEL;
|
session->maxchannel=FIRST_CHANNEL;
|
||||||
session->socket=ssh_socket_new(session);
|
session->socket=ssh_socket_new(session);
|
||||||
session->alive=0;
|
session->alive=0;
|
||||||
|
session->auth_methods=0;
|
||||||
session->blocking=1;
|
session->blocking=1;
|
||||||
session->log_indent=0;
|
session->log_indent=0;
|
||||||
session->out_buffer=buffer_new();
|
session->out_buffer=buffer_new();
|
||||||
|
191
libssh/sftp.c
191
libssh/sftp.c
@@ -28,6 +28,7 @@ MA 02111-1307, USA. */
|
|||||||
/** \addtogroup ssh_sftp
|
/** \addtogroup ssh_sftp
|
||||||
* @{ */
|
* @{ */
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -49,6 +50,7 @@ MA 02111-1307, USA. */
|
|||||||
/* functions */
|
/* functions */
|
||||||
void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg);
|
void sftp_enqueue(SFTP_SESSION *session, SFTP_MESSAGE *msg);
|
||||||
static void sftp_message_free(SFTP_MESSAGE *msg);
|
static void sftp_message_free(SFTP_MESSAGE *msg);
|
||||||
|
static void sftp_set_errno(SFTP_SESSION *sftp, int errnum);
|
||||||
|
|
||||||
/** \brief start a new SFTP session
|
/** \brief start a new SFTP session
|
||||||
* \param session the SSH session
|
* \param session the SSH session
|
||||||
@@ -188,6 +190,20 @@ SFTP_PACKET *sftp_packet_read(SFTP_SESSION *sftp){
|
|||||||
return packet;
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sftp_set_errno(SFTP_SESSION *sftp, int errnum) {
|
||||||
|
if (sftp != NULL) {
|
||||||
|
sftp->errnum = errnum;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int sftp_get_error(SFTP_SESSION *sftp) {
|
||||||
|
if (sftp == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sftp->errnum;
|
||||||
|
}
|
||||||
|
|
||||||
static SFTP_MESSAGE *sftp_message_new(SFTP_SESSION *sftp){
|
static SFTP_MESSAGE *sftp_message_new(SFTP_SESSION *sftp){
|
||||||
sftp_enter_function();
|
sftp_enter_function();
|
||||||
SFTP_MESSAGE *msg=malloc(sizeof(SFTP_MESSAGE));
|
SFTP_MESSAGE *msg=malloc(sizeof(SFTP_MESSAGE));
|
||||||
@@ -419,6 +435,7 @@ SFTP_FILE *parse_handle_msg(SFTP_MESSAGE *msg){
|
|||||||
}
|
}
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief open a directory
|
/** \brief open a directory
|
||||||
* \param sftp SFTP session handle
|
* \param sftp SFTP session handle
|
||||||
* \param path path to the directory
|
* \param path path to the directory
|
||||||
@@ -426,7 +443,7 @@ SFTP_FILE *parse_handle_msg(SFTP_MESSAGE *msg){
|
|||||||
* \see sftp_readdir()
|
* \see sftp_readdir()
|
||||||
* \see sftp_dir_close()
|
* \see sftp_dir_close()
|
||||||
*/
|
*/
|
||||||
SFTP_DIR *sftp_opendir(SFTP_SESSION *sftp, char *path){
|
SFTP_DIR *sftp_opendir(SFTP_SESSION *sftp, const char *path){
|
||||||
SFTP_DIR *dir=NULL;
|
SFTP_DIR *dir=NULL;
|
||||||
SFTP_FILE *file;
|
SFTP_FILE *file;
|
||||||
STATUS_MESSAGE *status;
|
STATUS_MESSAGE *status;
|
||||||
@@ -452,6 +469,7 @@ SFTP_DIR *sftp_opendir(SFTP_SESSION *sftp, char *path){
|
|||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
if(!status)
|
if(!status)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
sftp_set_errno(sftp, status->status);
|
||||||
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
|
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -760,10 +778,14 @@ SFTP_ATTRIBUTES *sftp_readdir(SFTP_SESSION *sftp, SFTP_DIR *dir){
|
|||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
if(!status)
|
if(!status)
|
||||||
return NULL;
|
return NULL;
|
||||||
if(status->status==SSH_FX_EOF){
|
sftp_set_errno(sftp, status->status);
|
||||||
dir->eof=1;
|
switch (status->status) {
|
||||||
|
case SSH_FX_EOF:
|
||||||
|
dir->eof = 1;
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
ssh_set_error(sftp->session,SSH_FATAL,"Unknown error status : %d",status->status);
|
ssh_set_error(sftp->session,SSH_FATAL,"Unknown error status : %d",status->status);
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
@@ -849,12 +871,18 @@ static int sftp_handle_close(SFTP_SESSION *sftp, STRING *handle){
|
|||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
if(!status)
|
if(!status)
|
||||||
return -1;
|
return -1;
|
||||||
if(status->status != SSH_FX_OK){
|
sftp_set_errno(sftp, status->status);
|
||||||
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
|
switch (status->status) {
|
||||||
err=-1;
|
case SSH_FX_OK:
|
||||||
|
status_msg_free(status);
|
||||||
|
return err;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return err;
|
return -1;
|
||||||
default:
|
default:
|
||||||
ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during sftp_handle_close!",msg->packet_type);
|
ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during sftp_handle_close!",msg->packet_type);
|
||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
@@ -903,7 +931,7 @@ int sftp_dir_close(SFTP_DIR *dir){
|
|||||||
/** \brief Open a remote file
|
/** \brief Open a remote file
|
||||||
* \todo please complete doc
|
* \todo please complete doc
|
||||||
*/
|
*/
|
||||||
SFTP_FILE *sftp_open(SFTP_SESSION *sftp, char *file, int access, SFTP_ATTRIBUTES *attr){
|
SFTP_FILE *sftp_open(SFTP_SESSION *sftp, const char *file, int access, SFTP_ATTRIBUTES *attr){
|
||||||
SFTP_FILE *handle;
|
SFTP_FILE *handle;
|
||||||
SFTP_MESSAGE *msg=NULL;
|
SFTP_MESSAGE *msg=NULL;
|
||||||
STATUS_MESSAGE *status;
|
STATUS_MESSAGE *status;
|
||||||
@@ -943,6 +971,7 @@ SFTP_FILE *sftp_open(SFTP_SESSION *sftp, char *file, int access, SFTP_ATTRIBUTES
|
|||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
if(!status)
|
if(!status)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
sftp_set_errno(sftp, status->status);
|
||||||
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
|
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1000,14 +1029,18 @@ int sftp_read(SFTP_FILE *handle, void *data, int len){
|
|||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
if(!status)
|
if(!status)
|
||||||
return -1;
|
return -1;
|
||||||
if(status->status != SSH_FX_EOF){
|
sftp_set_errno(sftp, status->status);
|
||||||
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
|
switch (status->status) {
|
||||||
err=-1;
|
case SSH_FX_EOF:
|
||||||
}
|
|
||||||
else
|
|
||||||
handle->eof=1;
|
handle->eof=1;
|
||||||
|
status_msg_free(status);
|
||||||
|
return err ? err : 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return err?err:0;
|
return -1;
|
||||||
case SSH_FXP_DATA:
|
case SSH_FXP_DATA:
|
||||||
datastring=buffer_get_ssh_string(msg->payload);
|
datastring=buffer_get_ssh_string(msg->payload);
|
||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
@@ -1120,6 +1153,7 @@ int sftp_async_read(SFTP_FILE *file, void *data, int size, u32 id){
|
|||||||
sftp_leave_function();
|
sftp_leave_function();
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
sftp_set_errno(sftp, status->status);
|
||||||
if(status->status != SSH_FX_EOF){
|
if(status->status != SSH_FX_EOF){
|
||||||
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
|
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
|
||||||
sftp_leave_function();
|
sftp_leave_function();
|
||||||
@@ -1161,7 +1195,7 @@ int sftp_async_read(SFTP_FILE *file, void *data, int size, u32 id){
|
|||||||
sftp_leave_function();
|
sftp_leave_function();
|
||||||
}
|
}
|
||||||
|
|
||||||
int sftp_write(SFTP_FILE *file, void *data, int len){
|
int sftp_write(SFTP_FILE *file, const void *data, int len){
|
||||||
SFTP_MESSAGE *msg=NULL;
|
SFTP_MESSAGE *msg=NULL;
|
||||||
STATUS_MESSAGE *status;
|
STATUS_MESSAGE *status;
|
||||||
STRING *datastring;
|
STRING *datastring;
|
||||||
@@ -1194,13 +1228,19 @@ int sftp_write(SFTP_FILE *file, void *data, int len){
|
|||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
if(!status)
|
if(!status)
|
||||||
return -1;
|
return -1;
|
||||||
if(status->status != SSH_FX_OK){
|
sftp_set_errno(sftp, status->status);
|
||||||
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
|
switch (status->status) {
|
||||||
err=-1;
|
case SSH_FX_OK:
|
||||||
|
file->offset+=len;
|
||||||
|
status_msg_free(status);
|
||||||
|
return err ? err : len;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server : %s",status->errormsg);
|
||||||
file->offset+=len;
|
file->offset+=len;
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return (err?err:len);
|
return -1;
|
||||||
default:
|
default:
|
||||||
ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during write!",msg->packet_type);
|
ssh_set_error(sftp->session,SSH_FATAL,"Received message %d during write!",msg->packet_type);
|
||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
@@ -1246,14 +1286,18 @@ int sftp_rm(SFTP_SESSION *sftp, char *file) {
|
|||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
if (!status)
|
if (!status)
|
||||||
return -1;
|
return -1;
|
||||||
if (status->status != SSH_FX_OK) {
|
sftp_set_errno(sftp, status->status);
|
||||||
/* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
|
switch (status->status) {
|
||||||
ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
|
case SSH_FX_OK:
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return -1;
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
/* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
|
||||||
|
ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return 0; /* at this point, everything turned out OK */
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to remove file", msg->packet_type);
|
ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to remove file", msg->packet_type);
|
||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
@@ -1262,7 +1306,7 @@ int sftp_rm(SFTP_SESSION *sftp, char *file) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* code written by Nick */
|
/* code written by Nick */
|
||||||
int sftp_rmdir(SFTP_SESSION *sftp, char *directory) {
|
int sftp_rmdir(SFTP_SESSION *sftp, const char *directory) {
|
||||||
u32 id = sftp_get_new_id(sftp);
|
u32 id = sftp_get_new_id(sftp);
|
||||||
BUFFER *buffer = buffer_new();
|
BUFFER *buffer = buffer_new();
|
||||||
STRING *filename = string_from_char(directory);
|
STRING *filename = string_from_char(directory);
|
||||||
@@ -1285,18 +1329,21 @@ int sftp_rmdir(SFTP_SESSION *sftp, char *directory) {
|
|||||||
{
|
{
|
||||||
status = parse_status_msg(msg);
|
status = parse_status_msg(msg);
|
||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
if (!status)
|
if (!status) {
|
||||||
{
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
else if (status->status != SSH_FX_OK) /* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
|
sftp_set_errno(sftp, status->status);
|
||||||
{
|
switch (status->status) {
|
||||||
ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
|
case SSH_FX_OK:
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return -1;
|
return 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return 0; /* at this point, everything turned out OK */
|
return -1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1307,12 +1354,13 @@ int sftp_rmdir(SFTP_SESSION *sftp, char *directory) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Code written by Nick */
|
/* Code written by Nick */
|
||||||
int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr) {
|
int sftp_mkdir(SFTP_SESSION *sftp, const char *directory, SFTP_ATTRIBUTES *attr) {
|
||||||
u32 id = sftp_get_new_id(sftp);
|
u32 id = sftp_get_new_id(sftp);
|
||||||
BUFFER *buffer = buffer_new();
|
BUFFER *buffer = buffer_new();
|
||||||
STRING *path = string_from_char(directory);
|
STRING *path = string_from_char(directory);
|
||||||
SFTP_MESSAGE *msg = NULL;
|
SFTP_MESSAGE *msg = NULL;
|
||||||
STATUS_MESSAGE *status = NULL;
|
STATUS_MESSAGE *status = NULL;
|
||||||
|
SFTP_ATTRIBUTES *errno_attr = NULL;
|
||||||
|
|
||||||
buffer_add_u32(buffer, id);
|
buffer_add_u32(buffer, id);
|
||||||
buffer_add_ssh_string(buffer, path);
|
buffer_add_ssh_string(buffer, path);
|
||||||
@@ -1329,17 +1377,33 @@ int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr) {
|
|||||||
/* by specification, this command's only supposed to return SSH_FXP_STATUS */
|
/* by specification, this command's only supposed to return SSH_FXP_STATUS */
|
||||||
status = parse_status_msg(msg);
|
status = parse_status_msg(msg);
|
||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
if (!status)
|
if (status == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
else
|
|
||||||
if (status->status != SSH_FX_OK) {
|
|
||||||
/* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
|
|
||||||
ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
|
|
||||||
status_msg_free(status);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
sftp_set_errno(sftp, status->status);
|
||||||
|
switch (status->status) {
|
||||||
|
case SSH_FX_FAILURE:
|
||||||
|
/*
|
||||||
|
* mkdir always returns a failure, even if the path already exists.
|
||||||
|
* To be POSIX conform and to be able to map it to EEXIST a stat
|
||||||
|
* call should be issued here
|
||||||
|
*/
|
||||||
|
errno_attr = sftp_lstat(sftp, directory);
|
||||||
|
if (errno_attr != NULL) {
|
||||||
|
sftp_set_errno(sftp, SSH_FX_FILE_ALREADY_EXISTS);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case SSH_FX_OK:
|
||||||
|
status_msg_free(status);
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
|
||||||
|
ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return 0; /* at this point, everything turned out OK */
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to make directory", msg->packet_type);
|
ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to make directory", msg->packet_type);
|
||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
@@ -1348,7 +1412,7 @@ int sftp_mkdir(SFTP_SESSION *sftp, char *directory, SFTP_ATTRIBUTES *attr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* code written by nick */
|
/* code written by nick */
|
||||||
int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname) {
|
int sftp_rename(SFTP_SESSION *sftp, const char *original, const char *newname) {
|
||||||
u32 id = sftp_get_new_id(sftp);
|
u32 id = sftp_get_new_id(sftp);
|
||||||
BUFFER *buffer = buffer_new();
|
BUFFER *buffer = buffer_new();
|
||||||
STRING *oldpath = string_from_char(original);
|
STRING *oldpath = string_from_char(original);
|
||||||
@@ -1374,14 +1438,18 @@ int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname) {
|
|||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
if (!status)
|
if (!status)
|
||||||
return -1;
|
return -1;
|
||||||
else if (status->status != SSH_FX_OK) {
|
sftp_set_errno(sftp, status->status);
|
||||||
/* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
|
switch (status->status) {
|
||||||
ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
|
case SSH_FX_OK:
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return -1;
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
/* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
|
||||||
|
ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return 0; /* at this point, everything turned out OK */
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to rename", msg->packet_type);
|
ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to rename", msg->packet_type);
|
||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
@@ -1390,7 +1458,7 @@ int sftp_rename(SFTP_SESSION *sftp, char *original, char *newname) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Code written by Nick */
|
/* Code written by Nick */
|
||||||
int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr) {
|
int sftp_setstat(SFTP_SESSION *sftp, const char *file, SFTP_ATTRIBUTES *attr) {
|
||||||
u32 id = sftp_get_new_id(sftp);
|
u32 id = sftp_get_new_id(sftp);
|
||||||
BUFFER *buffer = buffer_new();
|
BUFFER *buffer = buffer_new();
|
||||||
STRING *path = string_from_char(file);
|
STRING *path = string_from_char(file);
|
||||||
@@ -1414,14 +1482,18 @@ int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr) {
|
|||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
if (!status)
|
if (!status)
|
||||||
return -1;
|
return -1;
|
||||||
else if (status->status != SSH_FX_OK) {
|
sftp_set_errno(sftp, status->status);
|
||||||
/* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
|
switch (status->status) {
|
||||||
ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
|
case SSH_FX_OK:
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return -1;
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
/* status should be SSH_FX_OK if the command was successful, if it didn't, then there was an error */
|
||||||
|
ssh_set_error(sftp->session,SSH_REQUEST_DENIED, "sftp server: %s", status->errormsg);
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return 0; /* at this point, everything turned out OK */
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to set stats", msg->packet_type);
|
ssh_set_error(sftp->session,SSH_FATAL, "Received message %d when attempting to set stats", msg->packet_type);
|
||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
@@ -1430,7 +1502,7 @@ int sftp_setstat(SFTP_SESSION *sftp, char *file, SFTP_ATTRIBUTES *attr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* another code written by Nick */
|
/* another code written by Nick */
|
||||||
char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path)
|
char *sftp_canonicalize_path(SFTP_SESSION *sftp, const char *path)
|
||||||
{
|
{
|
||||||
u32 id = sftp_get_new_id(sftp);
|
u32 id = sftp_get_new_id(sftp);
|
||||||
BUFFER *buffer = buffer_new();
|
BUFFER *buffer = buffer_new();
|
||||||
@@ -1477,7 +1549,7 @@ char *sftp_canonicalize_path(SFTP_SESSION *sftp, char *path)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SFTP_ATTRIBUTES *sftp_xstat(SFTP_SESSION *sftp, char *path,int param){
|
SFTP_ATTRIBUTES *sftp_xstat(SFTP_SESSION *sftp, const char *path, int param){
|
||||||
u32 id=sftp_get_new_id(sftp);
|
u32 id=sftp_get_new_id(sftp);
|
||||||
BUFFER *buffer=buffer_new();
|
BUFFER *buffer=buffer_new();
|
||||||
STRING *pathstr= string_from_char(path);
|
STRING *pathstr= string_from_char(path);
|
||||||
@@ -1504,6 +1576,7 @@ SFTP_ATTRIBUTES *sftp_xstat(SFTP_SESSION *sftp, char *path,int param){
|
|||||||
sftp_message_free(msg);
|
sftp_message_free(msg);
|
||||||
if(!status)
|
if(!status)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
sftp_set_errno(sftp, status->status);
|
||||||
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server: %s",status->errormsg);
|
ssh_set_error(sftp->session,SSH_REQUEST_DENIED,"sftp server: %s",status->errormsg);
|
||||||
status_msg_free(status);
|
status_msg_free(status);
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -1513,10 +1586,10 @@ SFTP_ATTRIBUTES *sftp_xstat(SFTP_SESSION *sftp, char *path,int param){
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, char *path){
|
SFTP_ATTRIBUTES *sftp_stat(SFTP_SESSION *session, const char *path){
|
||||||
return sftp_xstat(session,path,SSH_FXP_STAT);
|
return sftp_xstat(session,path,SSH_FXP_STAT);
|
||||||
}
|
}
|
||||||
SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, char *path){
|
SFTP_ATTRIBUTES *sftp_lstat(SFTP_SESSION *session, const char *path){
|
||||||
return sftp_xstat(session,path,SSH_FXP_LSTAT);
|
return sftp_xstat(session,path,SSH_FXP_LSTAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,7 +39,7 @@ STRING *string_new(unsigned int size){
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
void string_fill(STRING *str,void *data,int len){
|
void string_fill(STRING *str, const void *data,int len){
|
||||||
memcpy(str->string,data,len);
|
memcpy(str->string,data,len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ void string_fill(STRING *str,void *data,int len){
|
|||||||
* \return the newly allocated string.
|
* \return the newly allocated string.
|
||||||
* \warning The nul byte is not copied nor counted in the ouput string.
|
* \warning The nul byte is not copied nor counted in the ouput string.
|
||||||
*/
|
*/
|
||||||
STRING *string_from_char(char *what){
|
STRING *string_from_char(const char *what){
|
||||||
STRING *ptr;
|
STRING *ptr;
|
||||||
int len=strlen(what);
|
int len=strlen(what);
|
||||||
ptr=malloc(4 + len);
|
ptr=malloc(4 + len);
|
||||||
|
15
sample.c
15
sample.c
@@ -440,6 +440,19 @@ int main(int argc, char **argv){
|
|||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssh_userauth_none(session, NULL);
|
||||||
|
|
||||||
|
auth = ssh_auth_list(session);
|
||||||
|
printf("auth: 0x%04x\n", auth);
|
||||||
|
printf("supported auth methods: ");
|
||||||
|
if (auth & SSH_AUTH_METHOD_PUBLICKEY) {
|
||||||
|
printf("publickey");
|
||||||
|
}
|
||||||
|
if (auth & SSH_AUTH_METHOD_INTERACTIVE) {
|
||||||
|
printf(", keyboard-interactive");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
/* no ? you should :) */
|
/* no ? you should :) */
|
||||||
auth=ssh_userauth_autopubkey(session);
|
auth=ssh_userauth_autopubkey(session);
|
||||||
if(auth==SSH_AUTH_ERROR){
|
if(auth==SSH_AUTH_ERROR){
|
||||||
@@ -462,7 +475,7 @@ int main(int argc, char **argv){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(auth!=SSH_AUTH_SUCCESS){
|
if(auth!=SSH_AUTH_SUCCESS){
|
||||||
password=getpass("Password : ");
|
password=getpass("Password: ");
|
||||||
if(ssh_userauth_password(session,NULL,password) != SSH_AUTH_SUCCESS){
|
if(ssh_userauth_password(session,NULL,password) != SSH_AUTH_SUCCESS){
|
||||||
fprintf(stderr,"Authentication failed: %s\n",ssh_get_error(session));
|
fprintf(stderr,"Authentication failed: %s\n",ssh_get_error(session));
|
||||||
ssh_disconnect(session);
|
ssh_disconnect(session);
|
||||||
|
Reference in New Issue
Block a user