/* Will try to login */ int ftp_login(ftp_t *ftp) { char *line = NULL; fprintf(ftp->FD, "USER %s\r\n", ftp->user); line = ftp_getline(ftp); ftp->code = atoi(line); /* case it will login anonymous user without PASS */ if ( ftp->code == 220 || ftp->code == 230 ) { ftp->logged = 1; #ifdef DEBUG print(2, "Login success!\n"); #endif return ftp->code; } fprintf(ftp->FD, "PASS %s\r\n", ftp->password); line = ftp_getline(ftp); ftp->code = atoi(line); if ( ftp->code == 220 || ftp->code == 230 ) { ftp->logged = 1; #ifdef DEBUG print(2, "Login success!\n"); #endif } else ftp->logged = 0; return ftp->code; }
/* download files/folders */ void ftp_download(ftp_t *ftp, char *path) { char *line = NULL; char buffer[MAX_STR]; FILE *data; int co = 0; ftp->alarm_sec = 3; fprintf(ftp->FD, "SIZE %s\r\n", path); line = ftp_getline(ftp); ftp->code = atoi(line); if ( ftp->code == 213 ) { ftp_mkcon(ftp); ftp_download_single(ftp, path, 1); } else { /* TODO: add download time */ print(3, ">>> %sStart downloading from%s %s\'%s\'%s ...\n",YEL,END,GREEN,path,END); ftp->dataport = ftp_getdataport(ftp); fprintf(ftp->FD, "NLST %s\r\n", path); data = tcp_connect(ip, ftp->dataport, "r"); ftp_getline(ftp); while ( fgets(buffer, sizeof(buffer), data)) { buffer[strlen(buffer)-2] = '\0'; ftp_mkcon(ftp); ftp_download_single(ftp, buffer, 0); co++; } fclose(data); close(dfd); print(0, ">>> %sFinished! we have %s%s%d files (:%s", GREEN,END, YEL,co,END, path); } }
/* Get list of files * opt: * 1 - NLST * 2 - LIST */ void ftp_list(ftp_t *ftp, char *path, int opt) { FILE *data; char buffer[MAX_STR]; ftp->dataport = ftp_getdataport(ftp); switch(opt) { case 1: fprintf(ftp->FD, "LIST %s\r\n", path); case 2: fprintf(ftp->FD, "NLST %s\r\n", path); } /* SIGALRM */ ftp_getline(ftp); data = tcp_connect2(ip, ftp->dataport, "r"); while ( fgets(buffer, sizeof(buffer), data) != NULL ) { /* dir*/ if ( buffer[0] == 0x64 ) print(3, "%s%s%s", BLUE,buffer, END); /* symlink*/ if ( buffer[0] == 0x6c ) print(3, "%s%s%s", CYN,buffer,END); /* File */ else if ( buffer[0] == 0x2d ) print(3, "%s%s%s", WHT,buffer, END); } fclose(data); close(dfd); /* No need to close fd the SIGALRM do it */ }
void vsf_cmdio_get_cmd_and_arg(struct vsf_session* p_sess, struct mystr* p_cmd_str, struct mystr* p_arg_str, int set_alarm) { /* Prepare an alarm to timeout the session.. */ if (set_alarm) { vsf_cmdio_set_alarm(p_sess); } /* Blocks */ ftp_getline(p_cmd_str); str_split_char(p_cmd_str, p_arg_str, ' '); str_upper(p_cmd_str); if (tunable_log_ftp_protocol) { static struct mystr s_log_str; if (str_equal_text(p_cmd_str, "PASS")) { str_alloc_text(&s_log_str, "PASS <password>"); } else { str_copy(&s_log_str, p_cmd_str); if (!str_isempty(p_arg_str)) { str_append_char(&s_log_str, ' '); str_append_str(&s_log_str, p_arg_str); } } vsf_log_line(p_sess, kVSFLogEntryFTPInput, &s_log_str); } }
static int control_getline(struct mystr* p_str, struct vsf_session* p_sess) { int ret; if (p_sess->p_control_line_buf == 0) { vsf_secbuf_alloc(&p_sess->p_control_line_buf, VSFTP_MAX_COMMAND_LINE); } ret = ftp_getline(p_sess, p_str, p_sess->p_control_line_buf); if (ret == 0) { return ret; } else if (ret < 0) { vsf_cmdio_write_exit(p_sess, FTP_BADCMD, "Input line too long.", 1); } /* As mandated by the FTP specifications.. */ str_replace_char(p_str, '\0', '\n'); /* If the last character is a \r, strip it */ { unsigned int len = str_getlen(p_str); while (len > 0 && str_get_char_at(p_str, len - 1) == '\r') { str_trunc(p_str, len - 1); --len; } } return 1; }
/* Parse OS/STAT*/ void skod_parse_stat(skod_t *skod, ftp_t *ftp) { char *line = NULL; char buffer[MAX_STR]; const char **p = NULL; if ( ftp->logged ) { fprintf(ftp->FD, "STAT\r\n"); while (( fgets(buffer, sizeof(buffer), ftp->FD)) != NULL ) { for ( p = ftp_prod; *p;p++ ) { if ( strstr(buffer, *p)) print(3, "%s", buffer); } } print(0, " "); } ftp_close(ftp); ftp_mkcon(ftp); /* Parse OS */ fprintf(ftp->FD, "SYST\r\n"); line = ftp_getline(ftp); if (( strstr(line, "UNIX"))) skod->os = SKOD_OS_NIX; if (( strstr(line, "NT"))) skod->os = SKOD_OS_NT; }
char * skod_hc_fingerprint(ftp_t *ftp) { char *line = NULL; const char **ptr = NULL; unsigned long sum = 0; char ssum[MAX_STR]; static char patr[MAX_STR]; int size = sizeof(ftp_commands) / sizeof(ftp_commands[0]); int c = 1; bzero(patr, MAX_STR); bzero(ssum, MAX_STR); ftp_close(ftp); /* It's more safe to make connection to each request * This way we will get the fingerprint 100% */ for ( ptr = ftp_commands; *ptr; ptr++ ) { ftp_mkcon(ftp); fprintf(ftp->FD, "%s\r\n", *ptr); line = ftp_getline(ftp); sum = skod_checksum(line); sprintf(ssum, "%lu", sum); strcat(patr, ssum); if ( c == size ) break; strcat(patr,":"); c++; ftp_close(ftp); } return (char *)patr; }
/* close connection */ void ftp_close(ftp_t *ftp) { fprintf(ftp->FD, "QUIT\r\n"); #ifdef DEBUG print(2, "%s", ftp_getline(ftp)); #endif fclose(ftp->FD); ftp->logged = 0; }
/* Change working directory for --dest. * Will work only with --upload */ void ftp_cwd(ftp_t *ftp, char *path) { char *line = NULL; fprintf(ftp->FD, "CWD %s\r\n", path); line = ftp_getline(ftp); ftp->code = atoi(line); if ( ftp->code == 550 ) die("Failed to change directory to %s\'%s\'%s.", RED,END); }
/* Delete file/directory */ void ftp_remove(ftp_t *ftp, char *path) { char *line = NULL; fprintf(ftp->FD, "DELE %s\r\n", path); line = ftp_getline(ftp); ftp->code = atoi(line); if ( ftp->code == 250 ) print(0, "=> \'%s\' deleted.", path); else print(1, "=> \'%s\' not removed.", path); }
/* delete file/folder from the server */ void ftp_delete(ftp_t *ftp, char *path) { char *line = NULL; fprintf(ftp->FD, "DELE %s\r\n", path); line = ftp_getline(ftp); ftp->code = atoi(line); if ( ftp->code == 250 ) print(0, "File %s\'%s\'%s deleted!", GREEN,path,END); else if ( ftp->code == 550 ) die("%s\'%s\'%s No such file or directory.", RED,path,END); }
/* print contents of single file from the FTP server */ void ftp_cat(ftp_t *ftp, char *path) { char *line = NULL; FILE *data; char buffer[MAX_STR]; ftp->dataport = ftp_getdataport(ftp); fprintf(ftp->FD, "TYPE I\r\n"); line = ftp_getline(ftp); if ( atoi(line) == 500 ) die("Failed to set TYPE."); fprintf(ftp->FD, "RETR %s\r\n", path); /* SIGALRM */ ftp_getline(ftp); data = tcp_connect2(ip, ftp->dataport, "r"); while(( fgets(buffer, sizeof(buffer), data)) != NULL ) { printf("%s", buffer); } fclose(data); close(dfd); }
/* Get file size */ int ftp_size(ftp_t *ftp, char *path) { char *line = NULL; int file_size = 0; fprintf(ftp->FD, "SIZE %s\r\n", path); line = ftp_getline(ftp); if ( atoi(line) != 213 ) die("Failed to get \'%s\' size.", path); sscanf(line, "213 %d", &file_size); return (file_size); }
char * ftp_pwd(ftp_t *ftp) { char *ppwd = NULL; char *line = NULL; static char pwd[MAX_STR]; fprintf(ftp->FD, "PWD\r\n"); line = ftp_getline(ftp); ppwd = strstr(line, "\""); sscanf(ppwd, "\"%s\" %[^\n]s", pwd, line); strtok(pwd, "\""); return pwd; }
/* Mdtm - return the modification time of a file*/ void ftp_mdtm(ftp_t *ftp, char *path) { char *line = NULL; char act[MAX_STR]; fprintf(ftp->FD, "MDTM %s\r\n", path); line = ftp_getline(ftp); ftp->code = atoi(line); if ( ftp->code == 550 ) die("Failed to run MTDM on \'%s\'.", path); sprintf(act, "%s", strrchr(line, 0x20)+1); print(0, "%s%s%s %c%c:%c%c:%c%c %c%c/%c%c/%c%c%c%c", GREEN,path,END, act[8], act[9], act[10], act[11], act[12], act[13], act[6], act[7], act[4], act[5], act[0], act[1],act[2], act[3]); }
/* Change working directory for --dest */ void ftp_cwd(ftp_t *ftp, char *path) { char *line = NULL; /* if download */ if ( flag == 3 ) { if ( chdir(path) == -1 ) die("Cannot change direcotry to \'%s\' ...", path); } /* if upload */ if ( flag == 4 ) { fprintf(ftp->FD, "CWD %s\r\n", path); line = ftp_getline(ftp); ftp->code = atoi(line); if ( ftp->code == 550 ) die("Failed to change directory to %s\'%s\'%s.", RED,END); } }
/* get data port using PASV*/ int ftp_getdataport(ftp_t *ftp) { char *line = NULL; int p1 = 0; int p2 = 0; int p3_secure = 0; char *act = NULL; fprintf(ftp->FD, "PASV\r\n"); line = ftp_getline(ftp); act = strrchr(line, ',') -5; /* p3_secure is for secureing the data port, * in case it will be 3 digits */ sscanf(act, "%d,%d,%d)", &p3_secure, &p1, &p2); #ifdef DEBUG print(2, "Dataport: %d\n", (p1*256+p2)); #endif return (p1*256+p2); }
static void control_getline(struct mystr* p_str, struct vsf_session* p_sess) { if (p_sess->p_control_line_buf == 0) { vsf_secbuf_alloc(&p_sess->p_control_line_buf, VSFTP_MAX_COMMAND_LINE); } ftp_getline(p_sess, p_str, p_sess->p_control_line_buf); /* As mandated by the FTP specifications.. */ str_replace_char(p_str, '\0', '\n'); /* If the last character is a \r, strip it */ { unsigned int len = str_getlen(p_str); while (len > 0 && str_get_char_at(p_str, len - 1) == '\r') { str_trunc(p_str, len - 1); --len; } } }
static void process_ssl_slave_req(struct vsf_session* p_sess) { while (1) { char cmd = priv_sock_get_cmd(p_sess->ssl_slave_fd); int retval; if (cmd == PRIV_SOCK_GET_USER_CMD) { ftp_getline(p_sess, &p_sess->ftp_cmd_str, p_sess->p_control_line_buf); priv_sock_send_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str); } else if (cmd == PRIV_SOCK_WRITE_USER_RESP) { priv_sock_get_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str); retval = ftp_write_str(p_sess, &p_sess->ftp_cmd_str, kVSFRWControl); priv_sock_send_int(p_sess->ssl_slave_fd, retval); } else { die("bad request in process_ssl_slave_req"); } } }
void ssl_slave(struct vsf_session* p_sess) { struct mystr data_str = INIT_MYSTR; str_reserve(&data_str, VSFTP_DATA_BUFSIZE); /* Before becoming the slave, clear the alarm for the FTP protocol. */ vsf_sysutil_clear_alarm(); /* No need for any further communications with the privileged parent. */ priv_sock_set_parent_context(p_sess); if (tunable_setproctitle_enable) { vsf_sysutil_setproctitle("SSL handler"); } while (1) { char cmd = priv_sock_get_cmd(p_sess->ssl_slave_fd); int ret; if (cmd == PRIV_SOCK_GET_USER_CMD) { ret = ftp_getline(p_sess, &p_sess->ftp_cmd_str, p_sess->p_control_line_buf); priv_sock_send_int(p_sess->ssl_slave_fd, ret); if (ret >= 0) { priv_sock_send_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str); } } else if (cmd == PRIV_SOCK_WRITE_USER_RESP) { priv_sock_get_str(p_sess->ssl_slave_fd, &p_sess->ftp_cmd_str); ret = ftp_write_str(p_sess, &p_sess->ftp_cmd_str, kVSFRWControl); priv_sock_send_int(p_sess->ssl_slave_fd, ret); } else if (cmd == PRIV_SOCK_DO_SSL_HANDSHAKE) { char result = PRIV_SOCK_RESULT_BAD; if (p_sess->data_fd != -1 || p_sess->p_data_ssl != 0) { bug("state not clean"); } p_sess->data_fd = priv_sock_recv_fd(p_sess->ssl_slave_fd); ret = ssl_accept(p_sess, p_sess->data_fd); if (ret == 1) { result = PRIV_SOCK_RESULT_OK; } else { vsf_sysutil_close(p_sess->data_fd); p_sess->data_fd = -1; } priv_sock_send_result(p_sess->ssl_slave_fd, result); } else if (cmd == PRIV_SOCK_DO_SSL_READ) { str_trunc(&data_str, VSFTP_DATA_BUFSIZE); ret = ssl_read_into_str(p_sess, p_sess->p_data_ssl, &data_str); priv_sock_send_int(p_sess->ssl_slave_fd, ret); priv_sock_send_str(p_sess->ssl_slave_fd, &data_str); } else if (cmd == PRIV_SOCK_DO_SSL_WRITE) { priv_sock_get_str(p_sess->ssl_slave_fd, &data_str); ret = ssl_write(p_sess->p_data_ssl, str_getbuf(&data_str), str_getlen(&data_str)); priv_sock_send_int(p_sess->ssl_slave_fd, ret); } else if (cmd == PRIV_SOCK_DO_SSL_CLOSE) { char result = PRIV_SOCK_RESULT_BAD; if (p_sess->data_fd == -1 && p_sess->p_data_ssl == 0) { result = PRIV_SOCK_RESULT_OK; } else { ret = ssl_data_close(p_sess); if (ret == 1) { result = PRIV_SOCK_RESULT_OK; } vsf_sysutil_close(p_sess->data_fd); p_sess->data_fd = -1; } priv_sock_send_result(p_sess->ssl_slave_fd, result); } else { die("bad request in process_ssl_slave_req"); } } }
/* download single file from the FTP server */ void ftp_download_single(ftp_t *ftp, char *path) { char *line = NULL; FILE *data; FILE *fp; char buffer[MAX_STR]; char *filename = NULL; long int dsize = 0; int rsize = 0; long int fsize = 0; long int lsize = 0; data_t d1; data_t d2; /* In case the URL have more then one / */ if ( path[strlen(path)-1] == 0x2f ) path[strlen(path)-1] = 0x00; /* strrchr return the last string */ filename = strrchr(path, '/') + 1; /* Check if file exists before downloading */ if (util_file_exists(filename) == 1 ) { print(1, "%s\'%s\' already exists.%s", WHT,filename,END); exit(0); } fsize = (int)ftp_size(ftp, path); ftp->dataport = ftp_getdataport(ftp); fprintf(ftp->FD, "TYPE I\r\n"); line = ftp_getline(ftp); if ( atoi(line) == 500 ) die("Failed to set TYPE."); fprintf(ftp->FD, "RETR %s\r\n", path); /* SIGALRM */ line = ftp_getline(ftp); data = tcp_connect2(ip, ftp->dataport, "r"); if (( fp = fopen(filename, "w")) == NULL ) die("Cannot create %s.", filename); calc_bytes(&d1, fsize); while(( rsize = fread(buffer, 1, sizeof(buffer), data) ) > 0 ) { if ( buffer[rsize +1] == '\r' ) buffer[rsize +1] = '\0'; dsize += fwrite(buffer, 1, rsize, fp); calc_bytes(&d2, dsize); print(3, "%s Downloading %s\'%s\'%s (%.2f%c) %.2f %c\b\b\b\b\b\r", WHT,GREEN, filename,END, d1.bytes, d1.bytes_postfix, d2.bytes, d2.bytes_postfix); fflush(stdout); } putchar(0x0a); fseek(fp, 0L, SEEK_END); lsize = ftell(fp); fseek(fp, 0L, SEEK_SET); /* All good */ if ( lsize == fsize ) print(0, "File %s\'%s\'%s saved.", GREEN,filename,END); else { /* inetutils <=1.9.4, * This bug discoverd by me in 05-10-2015, * SIZE command return file_size+23 bytes*/ if ( lsize+23 == fsize ) { print(0, "File \'%s\' saved.", GREEN,filename,END); print(0, "%sYou have unpatched version of inetutils 1.x.x please upgrade.%s", YEL,END); } /* Bad */ else print(1, "File %s\'%s\'%s is corrupted, try downloading it again?", RED,filename,END); } fclose(fp); fclose(data); close(dfd); }
/* Will grab the banner */ int ftp_banner(ftp_t *ftp) { char *line = NULL; line = ftp_getline(ftp); ftp->code = atoi(line); return (ftp->code = 0); }
/* upload single file to the FTP server */ void ftp_upload_single(ftp_t *ftp, char *path) { char *line = NULL; char *filename = NULL; FILE *data; FILE *fp; char buffer[MAX_STR]; long int dsize = 0; long int rsize = 0; long int fsize = 0; data_t d1; data_t d2; if ( path[0] == 0x2f || path[strlen(path)-1] == 0x2f ) filename = strrchr(path, '/') + 1; else filename = path; if (( fp = fopen(path, "r")) == NULL ) die("Cannot read %s.", path); fseek(fp, 0L, SEEK_END); fsize = ftell(fp); fseek(fp, 0L, SEEK_SET); ftp->dataport = ftp_getdataport(ftp); fprintf(ftp->FD, "TYPE I\r\n"); line = ftp_getline(ftp); if ( atoi(line) == 500 ) die("Failed to set TYPE."); fprintf(ftp->FD, "STOR %s\r\n", path); /* SIGALRM */ line = ftp_getline(ftp); data = tcp_connect2(ip, ftp->dataport, "w"); calc_bytes(&d1, fsize); while(( rsize = fread(buffer, 1, sizeof(buffer), fp) ) > 0 ) { if ( buffer[rsize +1] == '\r' ) buffer[rsize +1] = '\0'; dsize += fwrite(buffer, 1, rsize, data); calc_bytes(&d2, dsize); fprintf(stdout, "%s:: Uploading %s\'%s\'%s %s(%.2f%c) %.2f%c%s\r", WHT,GREEN, filename,END, YEL, d1.bytes, d1.bytes_postfix, d2.bytes, d2.bytes_postfix, END); fflush(stdout); } putchar(0x0a); if ( fsize == dsize ) print(0, "File %s\'%s\'%s saved on the server.", GREEN,filename,END); else print(1, "File %s\'%s\'%s is corrupted, try uploading it again?", RED,filename,END); fclose(fp); fclose(data); close(dfd); }