diff --git a/examples/sample_sftpserver.c b/examples/sample_sftpserver.c index d60ced1f..54b7cab7 100644 --- a/examples/sample_sftpserver.c +++ b/examples/sample_sftpserver.c @@ -43,13 +43,8 @@ The goal is to show the API in action. #include /* below are for sftp */ -#include #include -#include -#include #include - -#include #include #include #include @@ -146,9 +141,9 @@ const struct message_handler extended_handlers[] = { struct sftp_handle s_handle_table[MAX_HANDLE_NUM]; -static void init_handle_table(int handle_num) { +static void init_handle_table(void) { int obj_size = sizeof(struct sftp_handle); - memset(s_handle_table, 0, obj_size*handle_num); + memset(s_handle_table, 0, obj_size * MAX_HANDLE_NUM); } static void reinit_single_handle(struct sftp_handle* handle) { @@ -159,11 +154,11 @@ static void reinit_single_handle(struct sftp_handle* handle) { handle->fd = -1; } -static int handle_is_ok(int i, int type) { - return i >= 0 && (u_int)i < MAX_HANDLE_NUM && s_handle_table[i].type == type; +static int handle_is_ok(uint8_t i, int type) { + return i < MAX_HANDLE_NUM && s_handle_table[i].type == type; } -static int handle_close(int handle_ind) { +static int handle_close(uint8_t handle_ind) { int ret = SSH_ERROR; if (handle_is_ok(handle_ind, FILE_HANDLE)) { @@ -202,9 +197,9 @@ static int handle_close_by_pointer(struct sftp_handle* handle) { return 0; } -static void free_handles(int handle_num) { - int i; - for(i = 0; i < handle_num; i++) { +static void free_handles(void) { + uint8_t i; + for(i = 0; i < MAX_HANDLE_NUM; i++) { handle_close(i); /* reinit this handle */ reinit_single_handle(&s_handle_table[i]); @@ -213,8 +208,8 @@ static void free_handles(int handle_num) { } static int add_handle(int type, void *dirp, int fd, const char *name, void *session_id) { - int ret = SSH_ERROR; - int i; + int ret = -1; + uint8_t i; if (dirp == NULL && fd < 0) { return ret; } @@ -240,12 +235,10 @@ static int add_handle(int type, void *dirp, int fd, const char *name, void *sess } static char* get_handle_name(struct sftp_handle* handle) { - char *ret = NULL; - if (handle != NULL && handle->name != NULL) - ret = handle->name; - - return ret; + return handle->name; + + return NULL; } static const char* ssh_str_error(int u_errno) { @@ -255,7 +248,7 @@ static const char* ssh_str_error(int u_errno) { return "No such file"; case SSH_FX_PERMISSION_DENIED: return "Permission denied"; - case SSH_FX_BAD_MESSAGE: + case SSH_FX_BAD_MESSAGE: return "Bad message"; case SSH_FX_OP_UNSUPPORTED: return "Operation not supported"; @@ -299,8 +292,7 @@ static int unix_errno_to_ssh_stat(int u_errno) { static void stat_to_filexfer_attrib(const struct stat* z_st, struct sftp_attributes_struct* z_attr) { - z_attr->flags = 0; - z_attr->flags |= (uint32_t)SSH_FILEXFER_ATTR_SIZE; + z_attr->flags = 0 | (uint32_t)SSH_FILEXFER_ATTR_SIZE; z_attr->size = z_st->st_size; z_attr->flags |= (uint32_t)SSH_FILEXFER_ATTR_UIDGID; @@ -395,7 +387,7 @@ static int readdir_long_name(char* z_file_name, struct stat* z_st, char* z_long_ *ptr++ = 'x'; else *ptr++ = '-'; - + *ptr++ = ' '; *ptr = '\0'; @@ -415,7 +407,6 @@ static int readdir_long_name(char* z_file_name, struct stat* z_st, char* z_long_ } static int process_open(sftp_client_message client_msg) { - int ret = SSH_OK; const char *filename = sftp_client_message_get_filename(client_msg); uint32_t msg_flag = sftp_client_message_get_flags(client_msg); int file_flag; @@ -423,7 +414,7 @@ static int process_open(sftp_client_message client_msg) { int handle_ind = -1; int status; - if (((msg_flag&(uint32_t)SSH_FXF_READ) == SSH_FXF_READ) && + if (((msg_flag&(uint32_t)SSH_FXF_READ) == SSH_FXF_READ) && ((msg_flag&(uint32_t)SSH_FXF_WRITE) == SSH_FXF_WRITE)) { file_flag = O_RDWR; //file must exist if ((msg_flag & (uint32_t)SSH_FXF_CREAT) == SSH_FXF_CREAT) @@ -439,17 +430,15 @@ static int process_open(sftp_client_message client_msg) { } else { printf("undefined message flag\n"); sftp_reply_status(client_msg, SSH_FX_FAILURE, "Flag error"); - ret = SSH_ERROR; - return ret; + return SSH_ERROR; } fd = open(filename, file_flag, 0600); if(fd == -1){ status = unix_errno_to_ssh_stat(errno); - printf("error open file with error: %d\n", errno); + printf("error opening file with error: %d\n", errno); sftp_reply_status(client_msg, status, "Write error"); - ret = SSH_ERROR; - return ret; + return SSH_ERROR; } handle_ind = add_handle(FILE_HANDLE, NULL, fd, filename, client_msg->sftp); @@ -458,18 +447,16 @@ static int process_open(sftp_client_message client_msg) { ssh_string handle_s = sftp_handle_alloc(client_msg->sftp, handle_ptr); sftp_reply_handle(client_msg, handle_s); ssh_string_free(handle_s); - ret = SSH_OK; }else { close(fd); printf("opening file failed"); sftp_reply_status(client_msg, SSH_FX_FAILURE, "No handle available"); } - - return ret; + + return SSH_OK; } static int process_read(sftp_client_message client_msg) { - int ret = SSH_OK; struct sftp_handle *client_handle = (struct sftp_handle*)sftp_handle(client_msg->sftp, client_msg->handle); uint32_t readn; int fd; @@ -477,7 +464,7 @@ static int process_read(sftp_client_message client_msg) { int rv; if (client_handle == NULL || client_handle->session_id != client_msg->sftp) { - printf("get wrong handle from msg\n"); + printf("got wrong handle from msg\n"); sftp_reply_status(client_msg, SSH_FX_FAILURE, NULL); return SSH_ERROR; } @@ -487,18 +474,16 @@ static int process_read(sftp_client_message client_msg) { if (fd < 0) { sftp_reply_status(client_msg, SSH_FX_INVALID_HANDLE, NULL); printf("error reading file fd: %d\n", fd); - ret = SSH_ERROR; - return ret; + return SSH_ERROR; } rv = lseek(fd, client_msg->offset, SEEK_SET); if (rv == -1) { sftp_reply_status(client_msg, SSH_FX_FAILURE, NULL); printf("error seeking file fd: %d at offset: %" PRIu64 "\n", fd, client_msg->offset); - ret = SSH_ERROR; - return ret; + return SSH_ERROR; } - buffer = malloc((client_msg->len)*sizeof(char)); + buffer = malloc(client_msg->len); readn = read(fd, buffer, client_msg->len); if(readn > 0){ @@ -508,14 +493,16 @@ static int process_read(sftp_client_message client_msg) { }else { sftp_reply_status(client_msg, SSH_FX_FAILURE, NULL); printf("read file error!\n"); + return SSH_ERROR; } - return ret; + + free(buffer); + return SSH_OK; } static int process_write(sftp_client_message client_msg) { - int ret = SSH_OK; struct sftp_handle *client_handle = (struct sftp_handle*)sftp_handle(client_msg->sftp, client_msg->handle); - uint32_t writen; + int written; int fd; const char *msg_data; uint32_t len; @@ -532,8 +519,7 @@ static int process_write(sftp_client_message client_msg) { if (fd < 0) { sftp_reply_status(client_msg, SSH_FX_INVALID_HANDLE, NULL); printf("write file fd error!\n"); - ret = SSH_ERROR; - return ret; + return SSH_ERROR; } msg_data = ssh_string_get_char(client_msg->data); @@ -544,19 +530,21 @@ static int process_write(sftp_client_message client_msg) { sftp_reply_status(client_msg, SSH_FX_FAILURE, NULL); printf("error seeking file at offset: %" PRIu64 "\n", client_msg->offset); } - writen = write(fd, msg_data, len); - if(writen == len) { + written = write(fd, msg_data, len); + if (written == (int)len) { sftp_reply_status(client_msg, SSH_FX_OK, NULL); - }else { + } else if (written == -1) { sftp_reply_status(client_msg, SSH_FX_FAILURE, "Write error"); + } else { + sftp_reply_status(client_msg, SSH_FX_FAILURE, "Partial write"); } - return ret; + return SSH_OK; } static int process_close(sftp_client_message client_msg) { - int ret = SSH_OK; struct sftp_handle *client_handle = (struct sftp_handle*)sftp_handle(client_msg->sftp, client_msg->handle); + int ret; if (client_handle == NULL) { printf("get wrong handle from msg\n"); @@ -564,19 +552,18 @@ static int process_close(sftp_client_message client_msg) { } ret = handle_close_by_pointer(client_handle); + reinit_single_handle(client_handle); if (ret == SSH_OK) { - reinit_single_handle(client_handle); sftp_reply_status(client_msg, SSH_FX_OK, NULL); } else { printf("closing file failed\n"); sftp_reply_status(client_msg, SSH_FX_BAD_MESSAGE, "Invalid handle"); } - return ret; + return SSH_OK; } static int process_opendir(sftp_client_message client_msg) { - int ret = SSH_OK; DIR *dir = NULL; const char *dir_name = sftp_client_message_get_filename(client_msg); int handle_ind = -1; @@ -592,13 +579,12 @@ static int process_opendir(sftp_client_message client_msg) { ssh_string handle_s = sftp_handle_alloc(client_msg->sftp, &s_handle_table[handle_ind]); sftp_reply_handle(client_msg, handle_s); ssh_string_free(handle_s); - ret = SSH_OK; } else { closedir(dir); sftp_reply_status(client_msg, SSH_FX_FAILURE, "No handle available"); } - - return ret; + + return SSH_OK; } static int process_readdir(sftp_client_message client_msg) { @@ -610,6 +596,7 @@ static int process_readdir(sftp_client_message client_msg) { char long_path[PATH_MAX]; int path_length; + int srclen; char *handle_name; if (client_handle == NULL || client_handle->session_id != client_msg->sftp) { @@ -622,18 +609,23 @@ static int process_readdir(sftp_client_message client_msg) { if (dir == NULL) { sftp_reply_status(client_msg, SSH_FX_INVALID_HANDLE, NULL); printf("read dir handle error!\n"); - ret = SSH_ERROR; - return ret; + return SSH_ERROR; } - ret = SSH_OK; handle_name = get_handle_name(client_handle); if (handle_name == NULL) { sftp_reply_status(client_msg, SSH_FX_INVALID_HANDLE, NULL); return SSH_ERROR; } - strcpy(long_path, handle_name); - strcat(long_path, "/"); + + srclen = strlen(handle_name); + if (srclen + 2 >= PATH_MAX) { + printf("handle string length exceed max length!\n"); + sftp_reply_status(client_msg, SSH_FX_INVALID_HANDLE, NULL); + return SSH_ERROR; + } + strncpy(long_path, handle_name, PATH_MAX-strlen(long_path)-1); + strncat(long_path, "/", PATH_MAX-strlen(long_path)-1); path_length = (int)strlen(long_path); for(int i=0; i < MAX_ENTRIES_NUM_IN_PACKET; i++) { @@ -644,7 +636,12 @@ static int process_readdir(sftp_client_message client_msg) { struct stat st; char long_name[MAX_LONG_NAME_LEN]; - strcpy(&long_path[path_length], dentry->d_name); + if (strlen(dentry->d_name)+path_length+1 >= PATH_MAX) { + printf("handle string length exceed max length!\n"); + sftp_reply_status(client_msg, SSH_FX_INVALID_HANDLE, NULL); + return SSH_ERROR; + } + strncpy(&long_path[path_length], dentry->d_name, strlen(dentry->d_name)+1); if(lstat(long_path, &st) == 0) { stat_to_filexfer_attrib(&st, &attr); @@ -658,7 +655,7 @@ static int process_readdir(sftp_client_message client_msg) { } else { printf("readdir long name error\n"); } - + entries++; } else { break; @@ -695,7 +692,7 @@ static int process_mkdir(sftp_client_message client_msg) { } sftp_reply_status(client_msg, status, NULL); - + return ret; } @@ -717,7 +714,7 @@ static int process_rmdir(sftp_client_message client_msg) { } sftp_reply_status(client_msg, status, NULL); - + return ret; } @@ -743,7 +740,7 @@ static int process_lstat(sftp_client_message client_msg) { stat_to_filexfer_attrib(&st, &attr); sftp_reply_attr(client_msg, &attr); } - + return ret; } @@ -782,7 +779,7 @@ static int process_symlink(sftp_client_message client_msg) { int status = SSH_FX_OK; int rv; // printf("try to create link with src: %s and dest: %s \n", srcpath, destpath); - + if (srcpath == NULL || destpath == NULL) { sftp_reply_status(client_msg, SSH_FX_NO_SUCH_FILE, "File name error"); return SSH_ERROR; @@ -815,19 +812,17 @@ static int process_remove(sftp_client_message client_msg) { } sftp_reply_status(client_msg, status, NULL); - + return ret; } static int process_unsupposed(sftp_client_message client_msg) { - int ret = SSH_OK; sftp_reply_status(client_msg, SSH_FX_OP_UNSUPPORTED, "Operation not supported"); printf("Message type %d not implemented\n", sftp_client_message_get_type(client_msg)); - return ret; + return SSH_OK; } static int process_extended_statvfs(sftp_client_message client_msg) { - int ret = SSH_OK; const char *path = sftp_client_message_get_filename(client_msg); struct statvfs st; int status; @@ -839,36 +834,35 @@ static int process_extended_statvfs(sftp_client_message client_msg) { u_int64_t flag; sftp_statvfs = calloc(1, sizeof(struct sftp_statvfs_struct)); - if (sftp_statvfs == NULL) { - goto error; - } - - flag = (st.f_flag & ST_RDONLY) ? SSH_FXE_STATVFS_ST_RDONLY : 0; - flag |= (st.f_flag & ST_NOSUID) ? SSH_FXE_STATVFS_ST_NOSUID : 0; + if (sftp_statvfs != NULL) { + flag = (st.f_flag & ST_RDONLY) ? SSH_FXE_STATVFS_ST_RDONLY : 0; + flag |= (st.f_flag & ST_NOSUID) ? SSH_FXE_STATVFS_ST_NOSUID : 0; - sftp_statvfs->f_bsize = st.f_bsize; - sftp_statvfs->f_frsize = st.f_frsize; - sftp_statvfs->f_blocks = st.f_blocks; - sftp_statvfs->f_bfree = st.f_bfree; - sftp_statvfs->f_bavail = st.f_bavail; - sftp_statvfs->f_files = st.f_files; - sftp_statvfs->f_ffree = st.f_ffree; - sftp_statvfs->f_favail = st.f_favail; - sftp_statvfs->f_fsid = st.f_fsid; - sftp_statvfs->f_flag = flag; - sftp_statvfs->f_namemax = st.f_namemax; - - if(sftp_reply_statvfs(client_msg, sftp_statvfs) == 0) - return ret; + sftp_statvfs->f_bsize = st.f_bsize; + sftp_statvfs->f_frsize = st.f_frsize; + sftp_statvfs->f_blocks = st.f_blocks; + sftp_statvfs->f_bfree = st.f_bfree; + sftp_statvfs->f_bavail = st.f_bavail; + sftp_statvfs->f_files = st.f_files; + sftp_statvfs->f_ffree = st.f_ffree; + sftp_statvfs->f_favail = st.f_favail; + sftp_statvfs->f_fsid = st.f_fsid; + sftp_statvfs->f_flag = flag; + sftp_statvfs->f_namemax = st.f_namemax; + + rv = sftp_reply_statvfs(client_msg, sftp_statvfs); + free(sftp_statvfs); + if (rv == 0) { + return SSH_OK; + } + } } -error: status = unix_errno_to_ssh_stat(errno); - ret = SSH_ERROR; sftp_reply_status(client_msg, status, NULL); printf("statvfs send failed!\n"); - return ret; + return SSH_ERROR; } static int process_extended(sftp_client_message sftp_msg) { @@ -890,8 +884,6 @@ static int process_extended(sftp_client_message sftp_msg) { sftp_reply_status(sftp_msg, SSH_FX_OP_UNSUPPORTED, "Extended Operation not supported"); printf("Extended Message type %s not implemented\n", subtype); return SSH_OK; - - return status; } static int dispatch_sftp_request(sftp_client_message sftp_msg) { @@ -905,17 +897,16 @@ static int dispatch_sftp_request(sftp_client_message sftp_msg) { break; } } - if (handler!=NULL) - status = handler(sftp_msg); - else - goto not_implemented; - - return status; -not_implemented: - sftp_reply_status(sftp_msg, SSH_FX_OP_UNSUPPORTED, "Operation not supported"); - printf("Message type %d not implemented\n", sft_msg_type); - return SSH_OK; + if (handler!=NULL) { + status = handler(sftp_msg); + } else { + sftp_reply_status(sftp_msg, SSH_FX_OP_UNSUPPORTED, "Operation not supported"); + printf("Message type %d not implemented\n", sft_msg_type); + return SSH_OK; + } + + return status; } static int process_client_message(sftp_client_message client_msg) { @@ -932,7 +923,6 @@ static int process_client_message(sftp_client_message client_msg) { status = dispatch_sftp_request(client_msg); } - // status = dispatch_sftp_request(client_msg); if (status!=SSH_OK) printf("error occur in process client message!\n"); @@ -1152,12 +1142,12 @@ static int data_function(ssh_session session, ssh_channel channel, void *data, if(decode_len == -1) return -1; - msg = sftp_get_client_message_from_packet(cdata->sftp); + msg = sftp_get_client_message_from_packet(sftp); rc = process_client_message(msg); sftp_client_message_free(msg); if(rc != SSH_OK) printf("process sftp failed!\n"); - + return decode_len; } @@ -1169,7 +1159,7 @@ static int subsystem_request(ssh_session session, ssh_channel channel, /* initialize sftp session and file handler */ cdata->sftp = sftp_server_new(session, channel); - init_handle_table(MAX_HANDLE_NUM); + init_handle_table(); return SSH_OK; } @@ -1180,8 +1170,6 @@ static int auth_password(ssh_session session, const char *user, const char *pass, void *userdata) { struct session_data_struct *sdata = (struct session_data_struct *) userdata; - (void) session; - if (strcmp(user, USER) == 0 && strcmp(pass, PASS) == 0) { sdata->authenticated = 1; return SSH_AUTH_SUCCESS; @@ -1199,9 +1187,6 @@ static int auth_publickey(ssh_session session, { struct session_data_struct *sdata = (struct session_data_struct *) userdata; - (void) user; - (void) session; - if (signature_state == SSH_PUBLICKEY_STATE_NONE) { return SSH_AUTH_SUCCESS; } @@ -1339,8 +1324,8 @@ static void handle_session(ssh_event event, ssh_session session) { } while(ssh_channel_is_open(sdata.channel) && (cdata.pid == 0 || waitpid(cdata.pid, &rc, WNOHANG) == 0)); - - free_handles(MAX_HANDLE_NUM); + + free_handles(); ssh_channel_send_eof(sdata.channel); ssh_channel_close(sdata.channel); @@ -1353,7 +1338,6 @@ static void handle_session(ssh_event event, ssh_session session) { /* SIGCHLD handler for cleaning up dead children. */ static void sigchld_handler(int signo) { - (void) signo; while (waitpid(-1, NULL, WNOHANG) > 0); } @@ -1376,13 +1360,13 @@ int main(int argc, char **argv) { rc = ssh_init(); if (rc < 0) { fprintf(stderr, "ssh_init failed\n"); - return 1; + goto exit; } sshbind = ssh_bind_new(); if (sshbind == NULL) { fprintf(stderr, "ssh_bind_new failed\n"); - return 1; + goto exit; } #ifdef HAVE_ARGP_H @@ -1396,7 +1380,7 @@ int main(int argc, char **argv) { if(ssh_bind_listen(sshbind) < 0) { fprintf(stderr, "%s\n", ssh_get_error(sshbind)); - return 1; + goto exit; } while (1) { @@ -1442,6 +1426,7 @@ int main(int argc, char **argv) { ssh_free(session); } +exit: ssh_bind_free(sshbind); ssh_finalize(); return 0; diff --git a/src/sftp.c b/src/sftp.c index 5ee0c5d6..398d662c 100644 --- a/src/sftp.c +++ b/src/sftp.c @@ -356,7 +356,6 @@ void sftp_server_free(sftp_session sftp) int sftp_process_init_packet(sftp_client_message client_msg) { - int ret = SSH_OK; sftp_session sftp = client_msg->sftp; ssh_session session = sftp->session; int version; @@ -384,7 +383,8 @@ int sftp_process_init_packet(sftp_client_message client_msg) return -1; } - if (sftp_packet_write(sftp, SSH_FXP_VERSION, reply) < 0) { + rc = sftp_packet_write(sftp, SSH_FXP_VERSION, reply); + if (rc < 0) { SSH_BUFFER_FREE(reply); return -1; } @@ -395,10 +395,10 @@ int sftp_process_init_packet(sftp_client_message client_msg) if (version > LIBSFTP_VERSION) { sftp->version = LIBSFTP_VERSION; } else { - sftp->version = (int)version; + sftp->version = version; } - return ret; + return SSH_OK; } #endif /* WITH_SERVER */ @@ -443,26 +443,35 @@ int sftp_decode_channel_data_to_packet(sftp_session sftp, void *data) int offset; int to_read; - if(packet->sftp == NULL) + if (packet->sftp == NULL) { packet->sftp = sftp; + } packet->type = *((uint8_t *)data + sizeof(uint32_t)); payload_len = PULL_BE_U32(data, 0); /* We should check the legality of payload length */ - if(payload_len > MAX_PACKET_LEN || payload_len < 0) + if (payload_len > MAX_PACKET_LEN || payload_len < 0) { return SSH_ERROR; - + } + offset = sizeof(int) + sizeof(uint8_t); to_read = payload_len - sizeof(uint8_t); - ssh_buffer_add_data(packet->payload, (void*)((uint8_t *)data + offset), payload_len - sizeof(uint8_t)); + ssh_buffer_add_data(packet->payload, + (void*)((uint8_t *)data + offset), + payload_len - sizeof(uint8_t)); nread = ssh_buffer_get_len(packet->payload); /* We should check if we copied the whole data */ - if(nread != to_read) + if (nread != to_read) { return SSH_ERROR; + } - return payload_len + sizeof(int); + /* + * We should return how many bytes we decoded, including packet length header + * and the payload length. + */ + return payload_len + sizeof(uint32_t); } int sftp_packet_write(sftp_session sftp, uint8_t type, ssh_buffer payload) diff --git a/src/sftpserver.c b/src/sftpserver.c index 4664dd84..f50545fe 100644 --- a/src/sftpserver.c +++ b/src/sftpserver.c @@ -266,9 +266,7 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) packet = sftp->read_packet; if (packet == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } payload = packet->payload; @@ -278,21 +276,17 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) /* take a copy of the whole packet */ msg->complete_message = ssh_buffer_new(); if (msg->complete_message == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } rc = ssh_buffer_add_data(msg->complete_message, ssh_buffer_get(payload), ssh_buffer_get_len(payload)); if (rc < 0) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } - if (msg->type!=SSH_FXP_INIT) { + if (msg->type != SSH_FXP_INIT) { ssh_buffer_get_u32(payload, &msg->id); } @@ -302,21 +296,17 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) "d", &version); if (rc != SSH_OK) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - printf("unpack init failed!\n"); - return NULL; + printf("unpack init failed!\n"); + goto error; } version = ntohl(version); - sftp->client_version = (int)version; + sftp->client_version = version; break; case SSH_FXP_CLOSE: case SSH_FXP_READDIR: msg->handle = ssh_buffer_get_ssh_string(payload); if (msg->handle == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } break; case SSH_FXP_READ: @@ -326,9 +316,7 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) &msg->offset, &msg->len); if (rc != SSH_OK) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } break; case SSH_FXP_WRITE: @@ -338,9 +326,7 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) &msg->offset, &msg->data); if (rc != SSH_OK) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } break; case SSH_FXP_REMOVE: @@ -352,9 +338,7 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) "s", &msg->filename); if (rc != SSH_OK) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } break; case SSH_FXP_RENAME: @@ -364,9 +348,7 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) &msg->filename, &msg->data); if (rc != SSH_OK) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } break; case SSH_FXP_MKDIR: @@ -375,29 +357,21 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) "s", &msg->filename); if (rc != SSH_OK) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } msg->attr = sftp_parse_attr(sftp, payload, 0); if (msg->attr == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } break; case SSH_FXP_FSETSTAT: msg->handle = ssh_buffer_get_ssh_string(payload); if (msg->handle == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } msg->attr = sftp_parse_attr(sftp, payload, 0); if (msg->attr == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } break; case SSH_FXP_LSTAT: @@ -406,9 +380,7 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) "s", &msg->filename); if (rc != SSH_OK) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } if(sftp->version > 3) { ssh_buffer_unpack(payload, "d", &msg->flags); @@ -420,15 +392,11 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) &msg->filename, &msg->flags); if (rc != SSH_OK) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } msg->attr = sftp_parse_attr(sftp, payload, 0); if (msg->attr == NULL) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } break; case SSH_FXP_FSTAT: @@ -436,9 +404,7 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) "S", &msg->handle); if (rc != SSH_OK) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } break; case SSH_FXP_EXTENDED: @@ -446,9 +412,7 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) "s", &msg->submessage); if (rc != SSH_OK) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } if (strcmp(msg->submessage, "hardlink@openssh.com") == 0 || @@ -458,18 +422,14 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) &msg->filename, &msg->data); if (rc != SSH_OK) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } } else if (strcmp(msg->submessage, "statvfs@openssh.com") == 0 ){ rc = ssh_buffer_unpack(payload, "s", &msg->filename); if (rc != SSH_OK) { - ssh_set_error_oom(session); - sftp_client_message_free(msg); - return NULL; + goto error; } } break; @@ -481,6 +441,11 @@ sftp_client_message sftp_get_client_message_from_packet(sftp_session sftp) } return msg; + +error: + ssh_set_error_oom(session); + sftp_client_message_free(msg); + return NULL; } @@ -722,8 +687,8 @@ int sftp_reply_data(sftp_client_message msg, const void *data, int len) { int sftp_reply_statvfs(sftp_client_message msg, sftp_statvfs_t st) { + int ret = 0; ssh_buffer out; - out = ssh_buffer_new(); if (out == NULL) { return -1; @@ -742,12 +707,11 @@ int sftp_reply_statvfs(sftp_client_message msg, sftp_statvfs_t st) ssh_buffer_add_u64(out, ntohll(st->f_flag)) < 0 || ssh_buffer_add_u64(out, ntohll(st->f_namemax)) < 0 || sftp_packet_write(msg->sftp, SSH_FXP_EXTENDED_REPLY, out) < 0) { - SSH_BUFFER_FREE(out); - return -1; + ret = -1; } SSH_BUFFER_FREE(out); - return 0; + return ret; } diff --git a/tests/server/torture_sftpserver.c b/tests/server/torture_sftpserver.c index 4c5dc6d8..9a9fe011 100644 --- a/tests/server/torture_sftpserver.c +++ b/tests/server/torture_sftpserver.c @@ -1,470 +1,470 @@ -/* - * This file is part of the SSH Library - * - * Copyright (c) 2018 by Red Hat, Inc. - * - * Author: Anderson Toshiyuki Sasaki - * - * The SSH Library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or (at your - * option) any later version. - * - * The SSH Library is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public - * License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with the SSH Library; see the file COPYING. If not, write to - * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, - * MA 02111-1307, USA. - */ - -#include "config.h" - -#define LIBSSH_STATIC - -#include -#include -#include -#include - -#include "torture.h" -#include "torture_key.h" -#include "libssh/libssh.h" -#include "libssh/priv.h" -#include "libssh/session.h" - -#include "test_server.h" -#include "default_cb.h" - -#define TORTURE_KNOWN_HOSTS_FILE "libssh_torture_knownhosts" - -const char template[] = "temp_dir_XXXXXX"; - -struct test_server_st { - struct torture_state *state; - struct server_state_st *ss; - char *cwd; - char *temp_dir; -}; - -void sftp_handle_session_cb(ssh_event event, - ssh_session session, - struct server_state_st *state); - -static int setup_default_server(void **state) -{ - struct torture_state *s; - struct server_state_st *ss; - struct test_server_st *tss; -#ifdef HAVE_DSA - char dsa_hostkey[1024]; -#endif /* HAVE_DSA */ - - char ed25519_hostkey[1024] = {0}; - char rsa_hostkey[1024]; - char ecdsa_hostkey[1024]; - //char trusted_ca_pubkey[1024]; - - char sshd_path[1024]; - int rc; - - char pid_str[1024]; - - pid_t pid; - - assert_non_null(state); - - tss = (struct test_server_st*)calloc(1, sizeof(struct test_server_st)); - assert_non_null(tss); - - torture_setup_socket_dir((void **)&s); - assert_non_null(s->socket_dir); - - /* Set the default interface for the server */ - setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1); - setenv("PAM_WRAPPER", "1", 1); - - snprintf(sshd_path, - sizeof(sshd_path), - "%s/sshd", - s->socket_dir); - - rc = mkdir(sshd_path, 0755); - assert_return_code(rc, errno); - - snprintf(ed25519_hostkey, - sizeof(ed25519_hostkey), - "%s/sshd/ssh_host_ed25519_key", - s->socket_dir); - torture_write_file(ed25519_hostkey, - torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0)); - -#ifdef HAVE_DSA - snprintf(dsa_hostkey, - sizeof(dsa_hostkey), - "%s/sshd/ssh_host_dsa_key", - s->socket_dir); - torture_write_file(dsa_hostkey, torture_get_testkey(SSH_KEYTYPE_DSS, 0)); -#endif /* HAVE_DSA */ - - snprintf(rsa_hostkey, - sizeof(rsa_hostkey), - "%s/sshd/ssh_host_rsa_key", - s->socket_dir); - torture_write_file(rsa_hostkey, torture_get_testkey(SSH_KEYTYPE_RSA, 0)); - - snprintf(ecdsa_hostkey, - sizeof(ecdsa_hostkey), - "%s/sshd/ssh_host_ecdsa_key", - s->socket_dir); - torture_write_file(ecdsa_hostkey, - torture_get_testkey(SSH_KEYTYPE_ECDSA_P521, 0)); - - /* Create default server state */ - ss = (struct server_state_st *)calloc(1, sizeof(struct server_state_st)); - assert_non_null(ss); - - ss->address = strdup("127.0.0.10"); - assert_non_null(ss->address); - - ss->port = 22; - - ss->ecdsa_key = strdup(ecdsa_hostkey); - assert_non_null(ss->ecdsa_key); - -#ifdef HAVE_DSA - ss->dsa_key = strdup(dsa_hostkey); - assert_non_null(ss->dsa_key); -#endif /* HAVE_DSA */ - - ss->ed25519_key = strdup(ed25519_hostkey); - assert_non_null(ed25519_hostkey); - - ss->rsa_key = strdup(rsa_hostkey); - assert_non_null(ss->rsa_key); - - ss->host_key = NULL; - - /* Use default username and password (set in default_handle_session_cb) */ - ss->expected_username = NULL; - ss->expected_password = NULL; - - ss->verbosity = torture_libssh_verbosity(); - - ss->auth_methods = SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY; - -#ifdef WITH_PCAP - ss->with_pcap = 1; - ss->pcap_file = strdup(s->pcap_file); - assert_non_null(ss->pcap_file); -#endif - - /* TODO make configurable */ - ss->max_tries = 3; - ss->error = 0; - - /* Use the default session handling function */ - ss->handle_session = sftp_handle_session_cb; - assert_non_null(ss->handle_session); - - /* Do not use global configuration */ - ss->parse_global_config = false; - - /* Start the server using the default values */ - pid = fork_run_server(ss); - if (pid < 0) { - fail(); - } - - snprintf(pid_str, sizeof(pid_str), "%d", pid); - - torture_write_file(s->srv_pidfile, (const char *)pid_str); - - setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "21", 1); - unsetenv("PAM_WRAPPER"); - - /* Wait until the sshd is ready to accept connections */ - //rc = torture_wait_for_daemon(5); - //assert_int_equal(rc, 0); - - /* TODO properly wait for the server (use ping approach) */ - /* Wait 200ms */ - usleep(200 * 1000); - - tss->state = s; - tss->ss = ss; - - *state = tss; - - return 0; -} - -static int teardown_default_server(void **state) -{ - struct torture_state *s; - struct server_state_st *ss; - struct test_server_st *tss; - - tss = *state; - assert_non_null(tss); - - s = tss->state; - assert_non_null(s); - - ss = tss->ss; - assert_non_null(ss); - - /* This function can be reused */ - torture_teardown_sshd_server((void **)&s); - - free_server_state(tss->ss); - SAFE_FREE(tss->ss); - SAFE_FREE(tss); - - return 0; -} - -static int session_setup(void **state) -{ - struct test_server_st *tss = *state; - struct torture_state *s; - int verbosity = torture_libssh_verbosity(); - char *cwd = NULL; - char *tmp_dir = NULL; - bool b = false; - int rc; - - assert_non_null(tss); - - /* Make sure we do not test the agent */ - unsetenv("SSH_AUTH_SOCK"); - - cwd = torture_get_current_working_dir(); - assert_non_null(cwd); - - tmp_dir = torture_make_temp_dir(template); - assert_non_null(tmp_dir); - - tss->cwd = cwd; - tss->temp_dir = tmp_dir; - - s = tss->state; - assert_non_null(s); - - s->ssh.session = ssh_new(); - assert_non_null(s->ssh.session); - - s->ssh.tsftp = (struct torture_sftp*)calloc(1, sizeof(struct torture_sftp)); - assert_non_null(s->ssh.tsftp); - - rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); - assert_ssh_return_code(s->ssh.session, rc); - rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER); - assert_ssh_return_code(s->ssh.session, rc); - /* Make sure no other configuration options from system will get used */ - rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG, &b); - assert_ssh_return_code(s->ssh.session, rc); - - return 0; -} - -static int session_teardown(void **state) -{ - struct test_server_st *tss = *state; - struct torture_state *s; - int rc = 0; - - assert_non_null(tss); - - s = tss->state; - assert_non_null(s); - - sftp_free(s->ssh.tsftp->sftp); - SAFE_FREE(s->ssh.tsftp); - - ssh_disconnect(s->ssh.session); - ssh_free(s->ssh.session); - - rc = torture_change_dir(tss->cwd); - assert_int_equal(rc, 0); - - rc = torture_rmdirs(tss->temp_dir); - assert_int_equal(rc, 0); - - SAFE_FREE(tss->temp_dir); - SAFE_FREE(tss->cwd); - - return 0; -} - -static void torture_server_establish_sftp(void **state) -{ - struct test_server_st *tss = *state; - struct torture_state *s; - struct torture_sftp *tsftp; - ssh_session session; - sftp_session sftp; - int rc; - - assert_non_null(tss); - - s = tss->state; - assert_non_null(s); - - session = s->ssh.session; - assert_non_null(session); - - /* TODO: implement proper pam authentication in callback */ - /* Using the default user for the server */ - rc = ssh_options_set(session, SSH_OPTIONS_USER, SSHD_DEFAULT_USER); - assert_int_equal(rc, SSH_OK); - - rc = ssh_connect(session); - assert_int_equal(rc, SSH_OK); - - rc = ssh_userauth_none(session, NULL); - /* This request should return a SSH_REQUEST_DENIED error */ - if (rc == SSH_AUTH_ERROR) { - assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED); - } - rc = ssh_userauth_list(session, NULL); - assert_true(rc & SSH_AUTH_METHOD_PASSWORD); - - /* TODO: implement proper pam authentication in callback */ - /* Using the default password for the server */ - rc = ssh_userauth_password(session, NULL, SSHD_DEFAULT_PASSWORD); - assert_int_equal(rc, SSH_AUTH_SUCCESS); - - ssh_get_issue_banner(session); - - /* init sftp session */ - tsftp = s->ssh.tsftp; - sftp = tsftp->sftp; - - printf("in establish before sftp_new\n"); - sftp = sftp_new(session); - assert_non_null(sftp); - - rc = sftp_init(sftp); - assert_int_equal(rc, SSH_OK); -} - - -static void torture_server_test_sftp_function(void **state) -{ - struct test_server_st *tss = *state; - struct torture_state *s; - struct torture_sftp *tsftp; - ssh_session session; - sftp_session sftp; - int rc; - char *rv_str; - sftp_dir dir; - - char data[65535] = {0}; - sftp_file fichier; - sftp_file to; - int read_len; - int write_len; - - assert_non_null(tss); - - s = tss->state; - assert_non_null(s); - - session = s->ssh.session; - assert_non_null(session); - - rc = ssh_options_set(session, SSH_OPTIONS_USER, SSHD_DEFAULT_USER); - assert_int_equal(rc, SSH_OK); - - rc = ssh_connect(session); - assert_int_equal(rc, SSH_OK); - - rc = ssh_userauth_none(session, NULL); - /* This request should return a SSH_REQUEST_DENIED error */ - if (rc == SSH_AUTH_ERROR) { - assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED); - } - rc = ssh_userauth_list(session, NULL); - assert_true(rc & SSH_AUTH_METHOD_PASSWORD); - - /* TODO: implement proper pam authentication in callback */ - /* Using the default password for the server */ - rc = ssh_userauth_password(session, NULL, SSHD_DEFAULT_PASSWORD); - assert_int_equal(rc, SSH_AUTH_SUCCESS); - - rv_str = ssh_get_issue_banner(session); - - /* init sftp session */ - tsftp = s->ssh.tsftp; - sftp = tsftp->sftp; - sftp = sftp_new(session); - assert_non_null(sftp); - - rc = sftp_init(sftp); - assert_int_equal(rc, SSH_OK); - - /* symbol link */ - rc = sftp_symlink(sftp, "/tmp/this_is_the_link", "/tmp/sftp_symlink_test"); - assert_int_equal(rc, SSH_OK); - - rv_str = sftp_readlink(sftp, "/tmp/sftp_symlink_test"); - assert_non_null(rv_str); - - rc = sftp_unlink(sftp, "/tmp/sftp_symlink_test"); - assert_int_equal(rc, SSH_OK); - - /* open and close dir */ - dir = sftp_opendir(sftp, "./"); - assert_non_null(dir); - - rc = sftp_closedir(dir); - assert_int_equal(rc, SSH_OK); - - /* file read and write */ - fichier = sftp_open(sftp, "/usr/bin/ssh", O_RDONLY, 0); - assert_non_null(fichier); - - to = sftp_open(sftp, "ssh-copy", O_WRONLY | O_CREAT, 0700); - assert_non_null(to); - - read_len = sftp_read(fichier, data, 4096); - write_len = sftp_write(to, data, read_len); - assert_int_equal(write_len, read_len); - - rc = sftp_close(fichier); - assert_int_equal(rc, SSH_OK); - - rc = sftp_close(to); - assert_int_equal(rc, SSH_OK); - - rc = sftp_unlink(sftp, "ssh-copy"); - assert_int_equal(rc, SSH_OK); -} - -int torture_run_tests(void) { - int rc; - struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(torture_server_establish_sftp, - session_setup, - session_teardown), - cmocka_unit_test_setup_teardown(torture_server_test_sftp_function, - session_setup, - session_teardown), - }; - - ssh_init(); - - torture_filter_tests(tests); - rc = cmocka_run_group_tests(tests, - setup_default_server, - teardown_default_server); - - ssh_finalize(); - - return rc; -} +/* + * This file is part of the SSH Library + * + * Copyright (c) 2018 by Red Hat, Inc. + * + * Author: Anderson Toshiyuki Sasaki + * + * The SSH Library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at your + * option) any later version. + * + * The SSH Library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the SSH Library; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + * MA 02111-1307, USA. + */ + +#include "config.h" + +#define LIBSSH_STATIC + +#include +#include +#include +#include + +#include "torture.h" +#include "torture_key.h" +#include "libssh/libssh.h" +#include "libssh/priv.h" +#include "libssh/session.h" + +#include "test_server.h" +#include "default_cb.h" + +#define TORTURE_KNOWN_HOSTS_FILE "libssh_torture_knownhosts" + +const char template[] = "temp_dir_XXXXXX"; + +struct test_server_st { + struct torture_state *state; + struct server_state_st *ss; + char *cwd; + char *temp_dir; +}; + +void sftp_handle_session_cb(ssh_event event, + ssh_session session, + struct server_state_st *state); + +static int setup_default_server(void **state) +{ + struct torture_state *s; + struct server_state_st *ss; + struct test_server_st *tss; +#ifdef HAVE_DSA + char dsa_hostkey[1024]; +#endif /* HAVE_DSA */ + + char ed25519_hostkey[1024] = {0}; + char rsa_hostkey[1024]; + char ecdsa_hostkey[1024]; + //char trusted_ca_pubkey[1024]; + + char sshd_path[1024]; + int rc; + + char pid_str[1024]; + + pid_t pid; + + assert_non_null(state); + + tss = (struct test_server_st*)calloc(1, sizeof(struct test_server_st)); + assert_non_null(tss); + + torture_setup_socket_dir((void **)&s); + assert_non_null(s->socket_dir); + + /* Set the default interface for the server */ + setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "10", 1); + setenv("PAM_WRAPPER", "1", 1); + + snprintf(sshd_path, + sizeof(sshd_path), + "%s/sshd", + s->socket_dir); + + rc = mkdir(sshd_path, 0755); + assert_return_code(rc, errno); + + snprintf(ed25519_hostkey, + sizeof(ed25519_hostkey), + "%s/sshd/ssh_host_ed25519_key", + s->socket_dir); + torture_write_file(ed25519_hostkey, + torture_get_openssh_testkey(SSH_KEYTYPE_ED25519, 0)); + +#ifdef HAVE_DSA + snprintf(dsa_hostkey, + sizeof(dsa_hostkey), + "%s/sshd/ssh_host_dsa_key", + s->socket_dir); + torture_write_file(dsa_hostkey, torture_get_testkey(SSH_KEYTYPE_DSS, 0)); +#endif /* HAVE_DSA */ + + snprintf(rsa_hostkey, + sizeof(rsa_hostkey), + "%s/sshd/ssh_host_rsa_key", + s->socket_dir); + torture_write_file(rsa_hostkey, torture_get_testkey(SSH_KEYTYPE_RSA, 0)); + + snprintf(ecdsa_hostkey, + sizeof(ecdsa_hostkey), + "%s/sshd/ssh_host_ecdsa_key", + s->socket_dir); + torture_write_file(ecdsa_hostkey, + torture_get_testkey(SSH_KEYTYPE_ECDSA_P521, 0)); + + /* Create default server state */ + ss = (struct server_state_st *)calloc(1, sizeof(struct server_state_st)); + assert_non_null(ss); + + ss->address = strdup("127.0.0.10"); + assert_non_null(ss->address); + + ss->port = 22; + + ss->ecdsa_key = strdup(ecdsa_hostkey); + assert_non_null(ss->ecdsa_key); + +#ifdef HAVE_DSA + ss->dsa_key = strdup(dsa_hostkey); + assert_non_null(ss->dsa_key); +#endif /* HAVE_DSA */ + + ss->ed25519_key = strdup(ed25519_hostkey); + assert_non_null(ed25519_hostkey); + + ss->rsa_key = strdup(rsa_hostkey); + assert_non_null(ss->rsa_key); + + ss->host_key = NULL; + + /* Use default username and password (set in default_handle_session_cb) */ + ss->expected_username = NULL; + ss->expected_password = NULL; + + ss->verbosity = torture_libssh_verbosity(); + + ss->auth_methods = SSH_AUTH_METHOD_PASSWORD | SSH_AUTH_METHOD_PUBLICKEY; + +#ifdef WITH_PCAP + ss->with_pcap = 1; + ss->pcap_file = strdup(s->pcap_file); + assert_non_null(ss->pcap_file); +#endif + + /* TODO make configurable */ + ss->max_tries = 3; + ss->error = 0; + + /* Use the default session handling function */ + ss->handle_session = sftp_handle_session_cb; + assert_non_null(ss->handle_session); + + /* Do not use global configuration */ + ss->parse_global_config = false; + + /* Start the server using the default values */ + pid = fork_run_server(ss); + if (pid < 0) { + fail(); + } + + snprintf(pid_str, sizeof(pid_str), "%d", pid); + + torture_write_file(s->srv_pidfile, (const char *)pid_str); + + setenv("SOCKET_WRAPPER_DEFAULT_IFACE", "21", 1); + unsetenv("PAM_WRAPPER"); + + /* Wait until the sshd is ready to accept connections */ + //rc = torture_wait_for_daemon(5); + //assert_int_equal(rc, 0); + + /* TODO properly wait for the server (use ping approach) */ + /* Wait 200ms */ + usleep(200 * 1000); + + tss->state = s; + tss->ss = ss; + + *state = tss; + + return 0; +} + +static int teardown_default_server(void **state) +{ + struct torture_state *s; + struct server_state_st *ss; + struct test_server_st *tss; + + tss = *state; + assert_non_null(tss); + + s = tss->state; + assert_non_null(s); + + ss = tss->ss; + assert_non_null(ss); + + /* This function can be reused */ + torture_teardown_sshd_server((void **)&s); + + free_server_state(tss->ss); + SAFE_FREE(tss->ss); + SAFE_FREE(tss); + + return 0; +} + +static int session_setup(void **state) +{ + struct test_server_st *tss = *state; + struct torture_state *s; + int verbosity = torture_libssh_verbosity(); + char *cwd = NULL; + char *tmp_dir = NULL; + bool b = false; + int rc; + + assert_non_null(tss); + + /* Make sure we do not test the agent */ + unsetenv("SSH_AUTH_SOCK"); + + cwd = torture_get_current_working_dir(); + assert_non_null(cwd); + + tmp_dir = torture_make_temp_dir(template); + assert_non_null(tmp_dir); + + tss->cwd = cwd; + tss->temp_dir = tmp_dir; + + s = tss->state; + assert_non_null(s); + + s->ssh.session = ssh_new(); + assert_non_null(s->ssh.session); + + s->ssh.tsftp = (struct torture_sftp*)calloc(1, sizeof(struct torture_sftp)); + assert_non_null(s->ssh.tsftp); + + rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); + assert_ssh_return_code(s->ssh.session, rc); + rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_HOST, TORTURE_SSH_SERVER); + assert_ssh_return_code(s->ssh.session, rc); + /* Make sure no other configuration options from system will get used */ + rc = ssh_options_set(s->ssh.session, SSH_OPTIONS_PROCESS_CONFIG, &b); + assert_ssh_return_code(s->ssh.session, rc); + + return 0; +} + +static int session_teardown(void **state) +{ + struct test_server_st *tss = *state; + struct torture_state *s; + int rc = 0; + + assert_non_null(tss); + + s = tss->state; + assert_non_null(s); + + sftp_free(s->ssh.tsftp->sftp); + SAFE_FREE(s->ssh.tsftp); + + ssh_disconnect(s->ssh.session); + ssh_free(s->ssh.session); + + rc = torture_change_dir(tss->cwd); + assert_int_equal(rc, 0); + + rc = torture_rmdirs(tss->temp_dir); + assert_int_equal(rc, 0); + + SAFE_FREE(tss->temp_dir); + SAFE_FREE(tss->cwd); + + return 0; +} + +static void torture_server_establish_sftp(void **state) +{ + struct test_server_st *tss = *state; + struct torture_state *s; + struct torture_sftp *tsftp; + ssh_session session; + sftp_session sftp; + int rc; + + assert_non_null(tss); + + s = tss->state; + assert_non_null(s); + + session = s->ssh.session; + assert_non_null(session); + + /* TODO: implement proper pam authentication in callback */ + /* Using the default user for the server */ + rc = ssh_options_set(session, SSH_OPTIONS_USER, SSHD_DEFAULT_USER); + assert_int_equal(rc, SSH_OK); + + rc = ssh_connect(session); + assert_int_equal(rc, SSH_OK); + + rc = ssh_userauth_none(session, NULL); + /* This request should return a SSH_REQUEST_DENIED error */ + if (rc == SSH_AUTH_ERROR) { + assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED); + } + rc = ssh_userauth_list(session, NULL); + assert_true(rc & SSH_AUTH_METHOD_PASSWORD); + + /* TODO: implement proper pam authentication in callback */ + /* Using the default password for the server */ + rc = ssh_userauth_password(session, NULL, SSHD_DEFAULT_PASSWORD); + assert_int_equal(rc, SSH_AUTH_SUCCESS); + + ssh_get_issue_banner(session); + + /* init sftp session */ + tsftp = s->ssh.tsftp; + sftp = tsftp->sftp; + + printf("in establish before sftp_new\n"); + sftp = sftp_new(session); + assert_non_null(sftp); + + rc = sftp_init(sftp); + assert_int_equal(rc, SSH_OK); +} + + +static void torture_server_test_sftp_function(void **state) +{ + struct test_server_st *tss = *state; + struct torture_state *s; + struct torture_sftp *tsftp; + ssh_session session; + sftp_session sftp; + int rc; + char *rv_str; + sftp_dir dir; + + char data[65535] = {0}; + sftp_file fichier; + sftp_file to; + int read_len; + int write_len; + + assert_non_null(tss); + + s = tss->state; + assert_non_null(s); + + session = s->ssh.session; + assert_non_null(session); + + rc = ssh_options_set(session, SSH_OPTIONS_USER, SSHD_DEFAULT_USER); + assert_int_equal(rc, SSH_OK); + + rc = ssh_connect(session); + assert_int_equal(rc, SSH_OK); + + rc = ssh_userauth_none(session, NULL); + /* This request should return a SSH_REQUEST_DENIED error */ + if (rc == SSH_AUTH_ERROR) { + assert_int_equal(ssh_get_error_code(session), SSH_REQUEST_DENIED); + } + rc = ssh_userauth_list(session, NULL); + assert_true(rc & SSH_AUTH_METHOD_PASSWORD); + + /* TODO: implement proper pam authentication in callback */ + /* Using the default password for the server */ + rc = ssh_userauth_password(session, NULL, SSHD_DEFAULT_PASSWORD); + assert_int_equal(rc, SSH_AUTH_SUCCESS); + + rv_str = ssh_get_issue_banner(session); + + /* init sftp session */ + tsftp = s->ssh.tsftp; + sftp = tsftp->sftp; + sftp = sftp_new(session); + assert_non_null(sftp); + + rc = sftp_init(sftp); + assert_int_equal(rc, SSH_OK); + + /* symbol link */ + rc = sftp_symlink(sftp, "/tmp/this_is_the_link", "/tmp/sftp_symlink_test"); + assert_int_equal(rc, SSH_OK); + + rv_str = sftp_readlink(sftp, "/tmp/sftp_symlink_test"); + assert_non_null(rv_str); + + rc = sftp_unlink(sftp, "/tmp/sftp_symlink_test"); + assert_int_equal(rc, SSH_OK); + + /* open and close dir */ + dir = sftp_opendir(sftp, "./"); + assert_non_null(dir); + + rc = sftp_closedir(dir); + assert_int_equal(rc, SSH_OK); + + /* file read and write */ + fichier = sftp_open(sftp, "/usr/bin/ssh", O_RDONLY, 0); + assert_non_null(fichier); + + to = sftp_open(sftp, "ssh-copy", O_WRONLY | O_CREAT, 0700); + assert_non_null(to); + + read_len = sftp_read(fichier, data, 4096); + write_len = sftp_write(to, data, read_len); + assert_int_equal(write_len, read_len); + + rc = sftp_close(fichier); + assert_int_equal(rc, SSH_OK); + + rc = sftp_close(to); + assert_int_equal(rc, SSH_OK); + + rc = sftp_unlink(sftp, "ssh-copy"); + assert_int_equal(rc, SSH_OK); +} + +int torture_run_tests(void) { + int rc; + struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(torture_server_establish_sftp, + session_setup, + session_teardown), + cmocka_unit_test_setup_teardown(torture_server_test_sftp_function, + session_setup, + session_teardown), + }; + + ssh_init(); + + torture_filter_tests(tests); + rc = cmocka_run_group_tests(tests, + setup_default_server, + teardown_default_server); + + ssh_finalize(); + + return rc; +}