int init_download(client_ftp_t *client_ftp, char *cmd) { char buff[1024]; int i; bzero(buff, 1024); xsend(client_ftp->s, "TYPE I\n", 7, 0); i = xrecv(client_ftp->s, buff, 1024, 0); clean_buff(buff, i); printf("%s\n", buff); bzero(buff, 1024); open_new_data_connection(client_ftp); open_data_connection(client_ftp); bzero(buff, 1024); for (i = 4; cmd[i] == ' ' && cmd[i] != '\0'; i++) ; sprintf(buff, "RETR %s\n", cmd + i); xsend(client_ftp->s, buff, strlen(buff), 0); i = xrecv(client_ftp->s, buff, 1024, 0); clean_buff(buff, i); printf("%s\n", buff); if (strncmp(buff, "550", 3) == 0) { close(client_ftp->s_data); return (1); } return (0); }
int process_RETR(struct session* ses, const char* data) { if (strlen(data) > 0) { char file[MAX_PATH]; if (relative_to_absolute_path(ses->current_dir, data, file)) { struct stat st; if (lstat(file, &st) != -1) if (open_data_connection(ses) != -1) { char buf[BUF_LEN]; snprintf (buf, BUF_LEN, "Opening BINARY mode data connection for %s.", data); respond (ses, 150, buf); if (send_file(ses, file) != -1) respond (ses, 226, "Transfer complete."); else respond (ses, 550, "Transfer failed."); close_data_connection (ses); return 0; } } } respond (ses, 550, "Failed to open file."); return 0; }
// perform FTP RETR command, sends a file to the client void command_retr(CLIENT_INFO * client_info) { char line[BUFFER_SIZE] = { 0 }; client_read_line(client_info->fd, client_info->buf, &client_info->buffer_pos); extract_line(line, client_info->buf, &client_info->buffer_pos); int len = strlen(line); if (len < 6) { send_code(client_info->fd, 500); return; } char * filename = line + 5; char filenamebuf[PATH_MAX + 1] = { 0 }; if (filename[0] == '/') { snprintf(filenamebuf, PATH_MAX, "%s%s", basedir, filename); } else { snprintf(filenamebuf, PATH_MAX, "%s%s%s", basedir, client_info->dir, filename); } int fd = open(filenamebuf, O_RDONLY); if (fd == -1) { // cannot open file send_code(client_info->fd, 550); return; } send_code(client_info->fd, 150); open_data_connection(client_info); while (1) { char buf[FILE_READ_BUFFER_SIZE]; int bytes_read = read(fd, buf, FILE_READ_BUFFER_SIZE); if (bytes_read == 0) break; if (bytes_read == -1) epicfail("read"); int res = data_connection_write_buffer(client_info, buf, bytes_read); if (res == -1) break; } close(fd); close_data_connection(client_info); send_code(client_info->fd, 226); }
int process_LIST(struct session* ses, const char* data) { if (open_data_connection(ses) != -1) { // listing directory via `ls` command piped to temporary file char cmd[2*MAX_PATH]; snprintf (cmd, 2*MAX_PATH, "ls %s \"%s\" | tail -n+2 >%s", LIST_LS_PARAMS, ses->current_dir, LIST_LS_OUTFILE); if (system(cmd) != -1) { respond (ses, 150, "Here comes the directory listing."); if (send_file(ses, LIST_LS_OUTFILE) != -1) { respond (ses, 226, "Directory send OK."); close_data_connection (ses); unlink (LIST_LS_OUTFILE); return 0; } } } respond (ses, 550, "Directory listing failed."); return 0; }
// perform FTP LIST command, sends a directory listing to the client void command_list(CLIENT_INFO * client_info) { char line[BUFFER_SIZE] = { 0 }; client_read_line(client_info->fd, client_info->buf, &client_info->buffer_pos); extract_line(line, client_info->buf, &client_info->buffer_pos); int len = strlen(line); char * path = NULL; if (len != 4) { char * p = line + 5; if (*p == '-') { while (*p && (*p != ' ')) p++; } while (*p && (*p == ' ')) p++; path = p; } char dirbuf[PATH_MAX + 1] = { 0 }; snprintf(dirbuf, PATH_MAX, "%s%s", basedir, client_info->dir); if (path) { if (path[0] == '/') { snprintf(dirbuf, PATH_MAX, "%s%s", basedir, path); } else { strcat(dirbuf, "/"); strcat(dirbuf, path); } } char realpathbuf[PATH_MAX + 1] = { 0 }; if (! realpath(dirbuf, realpathbuf)) { send_code(client_info->fd, 550); return; } strcpy(dirbuf, realpathbuf); if (dirbuf[strlen(dirbuf) - 1] != '/') strncat(dirbuf, "/", PATH_MAX); DIR * dirp = opendir(dirbuf); if (! dirp) { send_code(client_info->fd, 550); return; } send_code(client_info->fd, 150); open_data_connection(client_info); while (1) { struct dirent * entry = readdir(dirp); if (! entry) break; char filenamebuf[PATH_MAX + 1] = { 0 }; snprintf(filenamebuf, PATH_MAX, "%s%s", dirbuf, entry->d_name); struct stat s; if (stat(filenamebuf, &s) == -1) { // cannot stat continue; } char buf[PATH_MAX + 128 + 1] = { 0 }; strmode(s.st_mode, buf); unsigned int size = (unsigned int)s.st_size; char date[64]; struct tm * ts = localtime(&s.st_mtime); strftime(date, 64, "%b %e %Y", ts); sprintf(buf + 11, "%3d %-8d %-8d %8u %s %s\r\n", s.st_nlink, (int)s.st_uid, (int)s.st_gid, size, date, entry->d_name); data_connection_write_string(client_info, buf); } close_data_connection(client_info); send_code(client_info->fd, 226); }