--- betaftpd-0.0.8pre17/ftpd.h.old Fri Jun 20 16:25:17 2003 +++ betaftpd-0.0.8pre17/ftpd.h Fri Jun 20 16:25:27 2003 @@ -203,7 +203,7 @@ void time_out_sockets(); void remove_bytes(struct conn * const c, const int i); -void numeric(struct conn * const c, const int numeric, const char * const format, ...); +int numeric(struct conn * const c, const int numeric, const char * const format, ...); void init_file_transfer(struct ftran * const f); int create_server_socket(); --- betaftpd-0.0.8pre17/ftpd.c.old Fri Jun 20 16:24:10 2003 +++ betaftpd-0.0.8pre17/ftpd.c Fri Jun 20 16:53:23 2003 @@ -359,6 +359,9 @@ if (c == NULL) return c; + c->prev_conn = NULL; + c->next_conn = NULL; + if (sock != -1) { ioctl(sock, FIONBIO, &one); if (add_fd(sock, POLLIN) != 0) { @@ -414,11 +417,9 @@ struct ftran *f = (struct ftran *)(malloc(sizeof(struct ftran))); if (f == NULL) return f; - if (c == NULL) { - /* this is the bogus head of the list */ - f->next_ftran = NULL; - f->prev_ftran = NULL; - } else { + f->next_ftran = NULL; + f->prev_ftran = NULL; + if (c != NULL) { add_to_linked_list((struct list_element *)first_ftran, (struct list_element *)f); } @@ -565,17 +566,19 @@ /* overrun = disconnect */ if (c->buf_len + bytes_avail > 254) { - numeric(c, 503, "Buffer overrun; disconnecting."); - destroy_conn(c); + if (numeric(c, 503, "Buffer overrun; disconnecting.")) + destroy_conn(c); continue; } c->buf_len += bytes_avail; parse_command(c); + /* FIXME: c could be invalid here, as parse_command can destroy it if (fds[c->sock].revents & (POLLERR|POLLHUP|POLLNVAL)) { destroy_conn(c); } + */ } return checked_through; } @@ -660,7 +663,8 @@ if (do_download(f)) continue; /* do_{upload,download} returned 0, the transfer is complete */ - numeric(f->owner, 226, "Transfer complete."); + if (!numeric(f->owner, 226, "Transfer complete.")) + continue; time(&(f->owner->last_transfer)); #if WANT_XFERLOG @@ -1090,10 +1094,12 @@ struct conn * const c = alloc_new_conn(tempsock); num_err = 0; if (c != NULL) { - numeric(c, 220, "BetaFTPD " VERSION " ready."); + if (numeric(c, 220, "BetaFTPD " VERSION " ready.")) { #if WANT_STAT - memcpy(&(c->addr), &tempaddr, sizeof(struct sockaddr)); + memcpy(&(c->addr), &tempaddr, sizeof(struct sockaddr)); #endif + ; + } } } } @@ -1136,8 +1142,8 @@ if ((c->transfer == NULL || c->transfer->state != 5) && (now - c->last_transfer > TIMEOUT_SECS)) { /* RFC violation? */ - numeric(c, 421, "Timeout (%u minutes): Closing control connection.", TIMEOUT_SECS/60); - destroy_conn(c); + if (numeric(c, 421, "Timeout (%u minutes): Closing control connection.", TIMEOUT_SECS/60)) + destroy_conn(c); } } } @@ -1165,8 +1171,11 @@ * you can use this command much the same way as you * would use a printf() (with all the normal %s, %d, * etc.), since it actually uses printf() internally. + * + * Returns 0 if connection was destroyed, 1 on success. + * This is so cmd_* callers can just do "return numeric(...)" on error. */ -void numeric(struct conn * const c, const int numeric, const char * const format, ...) +int numeric(struct conn * const c, const int numeric, const char * const format, ...) { char buf[256], fmt[256]; va_list args; @@ -1181,7 +1190,9 @@ err = send(c->sock, buf, i, 0); if (err == -1 && errno == EPIPE) { destroy_conn(c); + return 0; } + return 1; } /* @@ -1277,7 +1288,8 @@ if (f->dir_listing) { /* include size? */ - numeric(f->owner, 150, "Opening ASCII mode data connection for directory listing."); + if (!numeric(f->owner, 150, "Opening ASCII mode data connection for directory listing.")) + return; } else { /* * slightly kludged -- perhaps we should kill the second arm, @@ -1290,20 +1302,24 @@ || f->upload #endif /* WANT_UPLOAD */ ) { - numeric(f->owner, 150, "Opening %s mode data connection for '%s'", - (f->ascii_mode) ? "ASCII" : "BINARY", f->filename); + if (!numeric(f->owner, 150, "Opening %s mode data connection for '%s'", + (f->ascii_mode) ? "ASCII" : "BINARY", f->filename)) + return; } else { - numeric(f->owner, 150, "Opening %s mode data connection for '%s' (%u bytes)", + if (!numeric(f->owner, 150, "Opening %s mode data connection for '%s' (%u bytes)", (f->ascii_mode) ? "ASCII" : "BINARY", f->filename, - f->size); + f->size)) + return; } #else /* !WANT_ASCII */ #if WANT_UPLOAD if (f->upload) { - numeric(f->owner, 150, "Opening BINARY mode data connection for '%s'", f->filename); + if (!numeric(f->owner, 150, "Opening BINARY mode data connection for '%s'", f->filename)) + return; } else #endif /* WANT_UPLOAD */ - numeric(f->owner, 150, "Opening BINARY mode data connection for '%s' (%u bytes)", f->filename, f->size); + if (!numeric(f->owner, 150, "Opening BINARY mode data connection for '%s' (%u bytes)", f->filename, f->size)) + return; #endif /* !WANT_ASCII */ } --- betaftpd-0.0.8pre17/cmds.c.old Fri Jun 20 16:28:56 2003 +++ betaftpd-0.0.8pre17/cmds.c Fri Jun 20 16:51:01 2003 @@ -234,8 +234,7 @@ #if WANT_NONROOT if (nr_check_permission(c->uid, temp, 1, 1, NULL) == -1) { - numeric(c, 550, "Permission denied"); - return -1; + return numeric(c, 550, "Permission denied"); } #endif @@ -247,11 +246,10 @@ } if (strncmp(chd, c->root_dir, strlen(c->root_dir)) != 0) { - numeric(c, 550, "No such file or directory."); - return -1; + return numeric(c, 550, "No such file or directory."); } - return 0; + return 1; } /* @@ -268,12 +266,13 @@ strcpy(c->username, "ftp"); } if (strcasecmp(c->username, "ftp") == 0) { - numeric(c, 331, "Login OK, send password (your e-mail)."); c->auth = 1; + return numeric(c, 331, "Login OK, send password (your e-mail)."); } else { - numeric(c, 331, "Password required for %s.", c->username); c->auth = 2; + return numeric(c, 331, "Password required for %s.", c->username); } + /*notreached*/ return 1; } @@ -334,14 +333,15 @@ c->auth = 0; } if (c->auth == 0) { - numeric(c, 530, "Login incorrect."); + return numeric(c, 530, "Login incorrect."); } else { #if WANT_MESSAGE chdir(c->curr_dir); dump_file(c, 230, "welcome.msg"); #endif - numeric(c, 230, "User logged in."); + return numeric(c, 230, "User logged in."); } + /*notreached*/ return 1; } @@ -358,8 +358,7 @@ */ int cmd_acct(struct conn * const c) { - numeric(c, 202, "ACCT ignored OK -- not applicable on this system."); - return 1; + return numeric(c, 202, "ACCT ignored OK -- not applicable on this system."); } /* @@ -377,8 +376,7 @@ struct sockaddr_in sin; if ((c->transfer != NULL) && (c->transfer->state >= 4)) { - numeric(c, 500, "Sorry, only one transfer at a time."); - return 1; + return numeric(c, 500, "Sorry, only one transfer at a time."); } sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); @@ -389,7 +387,7 @@ i = sscanf(c->recv_buf, "%3hu,%3hu,%3hu,%3hu,%3hu,%3hu", &a0, &a1, &a2, &a3, &p0, &p1); if (i < 6) { - numeric(c, 501, "Parse error."); + return numeric(c, 501, "Parse error."); } else { const int one = 1; int tmp; @@ -400,7 +398,8 @@ TRAP_ERROR(err == -1, 500, return 1); sin.sin_port = FTP_PORT - 1; - numeric(c, 200, "PORT command OK."); + if (!numeric(c, 200, "PORT command OK.")) + return 0; /* note that bind() might well fail, so we don't error check */ #if !WANT_NONROOT @@ -442,8 +441,7 @@ struct sockaddr_in addr; if ((c->transfer != NULL) && (c->transfer->state >= 4)) { - numeric(c, 503, "Sorry, only one transfer at once."); - return 1; + return numeric(c, 503, "Sorry, only one transfer at once."); } destroy_ftran(c->transfer); @@ -473,14 +471,13 @@ TRAP_ERROR(err == -1, 500, return 1); f->state = 1; - numeric(c, 227, "Entering passive mode (%u,%u,%u,%u,%u,%u)", + return numeric(c, 227, "Entering passive mode (%u,%u,%u,%u,%u,%u)", (htonl(addr.sin_addr.s_addr) & 0xff000000) >> 24, (htonl(addr.sin_addr.s_addr) & 0x00ff0000) >> 16, (htonl(addr.sin_addr.s_addr) & 0x0000ff00) >> 8, (htonl(addr.sin_addr.s_addr) & 0x000000ff), (htons(addr.sin_port) & 0xff00) >> 8, (htons(addr.sin_port) & 0x00ff)); - return 1; } /* @@ -497,7 +494,7 @@ cdir = do_pwd(c, temp, c->curr_dir); if (cdir != NULL) { - numeric(c, 257, "\"%s\" is current working directory.", cdir); + return numeric(c, 257, "\"%s\" is current working directory.", cdir); } return 1; } @@ -535,8 +532,7 @@ */ int cmd_cwd(struct conn * const c) { - cmd_cwd_internal(c, c->recv_buf); - return 1; + return cmd_cwd_internal(c, c->recv_buf); } /* @@ -551,8 +547,7 @@ */ int cmd_cdup(struct conn * const c) { - cmd_cwd_internal(c, ".."); - return 1; + return cmd_cwd_internal(c, ".."); } /* @@ -561,11 +556,15 @@ * space and have clearer code). Mostly, it just uses do_chdir(), * and sees where that takes us. It adds a trailing slash if needed. */ -void cmd_cwd_internal(struct conn * const c, const char * const newd) +int cmd_cwd_internal(struct conn * const c, const char * const newd) { - if (do_chdir(c, newd) != -1) { - int i; - + int i; + switch (do_chdir(c, newd)) { + case 0: + return 0; + case -1: + return -1; + case 1: getcwd(c->curr_dir, 254); i = strlen(c->curr_dir); if (c->curr_dir[i - 1] != '/') { @@ -578,8 +577,10 @@ list_readmes(c); #endif - numeric(c, 250, "CWD successful."); + return numeric(c, 250, "CWD successful."); } + /*notreached*/ + return 1; } /* @@ -590,8 +591,7 @@ int cmd_rest(struct conn * const c) { c->rest_pos = abs(atoi(c->recv_buf)); - numeric(c, 350, "Setting resume at %u bytes.", c->rest_pos); - return 1; + return numeric(c, 350, "Setting resume at %u bytes.", c->rest_pos); } /* @@ -603,17 +603,16 @@ */ int cmd_retr(struct conn * const c) { + int ok=1; struct ftran *f = c->transfer; if ((f == NULL) || ((f->state != 1) && (f->state != 3))) { - numeric(c, 425, "No data connection set up; please use PASV or PORT."); - return 1; + return numeric(c, 425, "No data connection set up; please use PASV or PORT."); } #if WANT_ASCII if ((c->rest_pos > 0) && (c->ascii_mode == 1)) { - numeric(c, 500, "Cannot resume while in ASCII mode."); - return 1; + return numeric(c, 500, "Cannot resume while in ASCII mode."); } #endif @@ -625,7 +624,7 @@ f->dir_listing = 0; if (f->local_file == -1) { - numeric(f->owner, 550, strerror(errno)); + ok = numeric(f->owner, 550, strerror(errno)); destroy_ftran(f); } else if (f->local_file == -2) { f->local_file = -1; @@ -636,7 +635,7 @@ #endif prepare_for_transfer(f); } - return 1; + return ok; } #if WANT_UPLOAD @@ -646,8 +645,7 @@ */ int cmd_stor(struct conn * const c) { - do_store(c, 0); - return 1; + return do_store(c, 0); } /* @@ -656,27 +654,24 @@ */ int cmd_appe(struct conn * const c) { - do_store(c, 1); - return 1; + return do_store(c, 1); } /* * do_store(): Initiate an upload. Most of the comments to do_retr() * (above) apply to this one as well. */ -void do_store(struct conn * const c, const int append) +int do_store(struct conn * const c, const int append) { struct ftran *f = c->transfer; if ((f == NULL) || ((f->state != 1) && (f->state != 3))) { - numeric(c, 425, "No data connection set up; please use PASV or PORT."); - return; + return numeric(c, 425, "No data connection set up; please use PASV or PORT."); } #if WANT_ASCII if ((c->rest_pos > 0) && (c->ascii_mode == 1)) { - numeric(c, 500, "Cannot resume while in ASCII mode."); - return; + return numeric(c, 500, "Cannot resume while in ASCII mode."); } #endif @@ -689,7 +684,7 @@ f->dir_listing = 0; if (f->local_file == -1) { - numeric(f->owner, 550, strerror(errno)); + return numeric(f->owner, 550, strerror(errno)); } else if (f->local_file == -2) { f->local_file = -1; } else { @@ -700,6 +695,7 @@ #endif prepare_for_transfer(f); } + return 1; } #endif /* WANT_UPLOAD */ @@ -718,8 +714,7 @@ { #if WANT_ASCII if (c->ascii_mode) { - numeric(c, 550, "SIZE not available in ASCII mode."); - return 1; + return numeric(c, 550, "SIZE not available in ASCII mode."); } #endif { @@ -728,8 +723,7 @@ TRAP_ERROR(fname == NULL || lstat(fname, &buf) == -1, 550, return 1); - numeric(c, 213, "%lu", (unsigned long)(buf.st_size)); - return 1; + return numeric(c, 213, "%lu", (unsigned long)(buf.st_size)); } } @@ -747,9 +741,8 @@ TRAP_ERROR(fname == NULL || lstat(fname, &buf) == -1, 550, return 1); m = gmtime(&(buf.st_mtime)); /* at least wu-ftpd does it in GMT */ - numeric(c, 213, "%u%02u%02u%02u%02u%02u", m->tm_year + 1900, + return numeric(c, 213, "%u%02u%02u%02u%02u%02u", m->tm_year + 1900, m->tm_mon + 1, m->tm_mday, m->tm_hour, m->tm_min, m->tm_sec); - return 1; } /* @@ -759,11 +752,11 @@ int cmd_abor(struct conn * const c) { if (c->transfer != NULL) { - numeric(c, 426, "File transfer aborted."); + if (!numeric(c, 426, "File transfer aborted.")) + return 0; destroy_ftran(c->transfer); } - numeric(c, 226, "ABOR command processed OK."); - return 1; + return numeric(c, 226, "ABOR command processed OK."); } /* @@ -774,8 +767,7 @@ const char * const fname = translate_path(c, c->recv_buf); TRAP_ERROR(fname == NULL || unlink(fname) == -1, 550, return 1); - numeric(c, 250, "File deleted OK."); - return 1; + return numeric(c, 250, "File deleted OK."); } /* @@ -796,8 +788,7 @@ /* Just check that the file exists. */ TRAP_ERROR(lstat(c->rename_from, &buf) == -1, 550, c->rename_from[0] = '\0'; return 1); - numeric(c, 350, "File exists, send RNTO."); - return 1; + return numeric(c, 350, "File exists, send RNTO."); } /* @@ -809,15 +800,13 @@ if (fname == NULL) return 1; if (c->rename_from[0] == '\0') { - numeric(c, 503, "Please send RNFR first."); - return 1; + return numeric(c, 503, "Please send RNFR first."); } TRAP_ERROR(rename(c->rename_from, fname) == -1, 550, c->rename_from[0] = '\0'; return 1); c->rename_from[0] = '\0'; - numeric(c, 250, "File renamed successfully."); - return 1; + return numeric(c, 250, "File renamed successfully."); } /* @@ -853,8 +842,7 @@ temp2[++j] = '"'; } } - numeric(c, 257, "\"%s\" created.", temp2); - return 1; + return numeric(c, 257, "\"%s\" created.", temp2); } /* @@ -866,8 +854,7 @@ const char * const fname = translate_path(c, c->recv_buf); TRAP_ERROR(fname == NULL || rmdir(fname) == -1, 550, return 1); - numeric(c, 250, "Directory deleted."); - return 1; + return numeric(c, 250, "Directory deleted."); } /* @@ -883,8 +870,7 @@ */ int cmd_allo(struct conn * const c) { - numeric(c, 202, "No storage allocation necessary."); - return 1; + return numeric(c, 202, "No storage allocation necessary."); } /* @@ -947,7 +933,7 @@ return 0; } #else - numeric(c, 502, "STAT command disabled for security reasons."); + return numeric(c, 502, "STAT command disabled for security reasons."); #endif return 1; } @@ -1234,8 +1220,7 @@ num_files = pglob.gl_pathc; break; default: - numeric(c, 550, strerror(EACCES)); - return -1; + return numeric(c, 550, strerror(EACCES)); } if (lo->recursive) { @@ -1295,6 +1280,7 @@ #endif break; /* note: break, not return */ default: + /* FIXME -- this could destroy c */ numeric(c, 550, strerror(EACCES)); #if HAVE_MMAP return pos; @@ -1418,8 +1404,7 @@ */ int cmd_noop(struct conn * const c) { - numeric(c, 200, "NOOP command successful."); - return 1; + return numeric(c, 200, "NOOP command successful."); } /* @@ -1427,8 +1412,7 @@ */ int cmd_syst(struct conn * const c) { - numeric(c, 215, "UNIX Type: L%u", NBBY); - return 1; + return numeric(c, 215, "UNIX Type: L%u", NBBY); } /* @@ -1440,16 +1424,17 @@ c->recv_buf[0] &= (255-32); /* convert to upper case */ if (c->recv_buf[0] == 'A') { c->ascii_mode = 1; - numeric(c, 200, "Type is ASCII."); + return numeric(c, 200, "Type is ASCII."); } else if (c->recv_buf[0] == 'I') { c->ascii_mode = 0; - numeric(c, 200, "Type is IMAGE."); + return numeric(c, 200, "Type is IMAGE."); } else { - numeric(c, 504, "Unknown type."); + return numeric(c, 504, "Unknown type."); } #else - numeric(c, 200, "TYPE ignored (always I)"); + return numeric(c, 200, "TYPE ignored (always I)"); #endif + /*notreached*/ return 1; } @@ -1460,10 +1445,11 @@ { c->recv_buf[0] &= (255-32); /* convert to upper case */ if (c->recv_buf[0] == 'S') { - numeric(c, 200, "Mode is STREAM."); + return numeric(c, 200, "Mode is STREAM."); } else { - numeric(c, 504, "Unknown mode."); + return numeric(c, 504, "Unknown mode."); } + /*notreached*/ return 1; } @@ -1474,10 +1460,11 @@ { c->recv_buf[0] &= (255-32); /* convert to upper case */ if (c->recv_buf[0] == 'F') { - numeric(c, 200, "Structure is FILE."); + return numeric(c, 200, "Structure is FILE."); } else { - numeric(c, 504, "Unknown structure."); + return numeric(c, 504, "Unknown structure."); } + /*notreached*/ return 1; } @@ -1500,8 +1487,7 @@ */ int cmd_help(struct conn * const c) { - numeric(c, 414, "Sorry, no detailed help; use standard FTP commands."); - return 1; + return numeric(c, 414, "Sorry, no detailed help; use standard FTP commands."); } /* @@ -1510,8 +1496,8 @@ */ int cmd_quit(struct conn * const c) { - numeric(c, 221, "Have a nice day!"); - destroy_conn(c); + if (numeric(c, 221, "Have a nice day!")) + destroy_conn(c); return 0; } @@ -1535,9 +1521,7 @@ #endif time(&(c->last_transfer)); - numeric(c, 220, "BetaFTPD " VERSION " ready."); - - return 1; + return numeric(c, 220, "BetaFTPD " VERSION " ready."); } #if DOING_PROFILING @@ -1594,7 +1578,8 @@ if ((cmlen >= (strlen(h->cmd_name) + h->add_cmlen)) && (strncasecmp(c->recv_buf, h->cmd_name, strlen(h->cmd_name)) == 0)) { if (c->auth < h->min_auth) { - numeric(c, 503, "Please login with USER and PASS."); + if (!numeric(c, 503, "Please login with USER and PASS.")) + return; while (c->recv_buf[0] != '\n') remove_bytes(c, 1); } else { char schar; @@ -1630,8 +1615,8 @@ } } while ((++h)->callback != NULL); - numeric(c, 500, "Sorry, no such command."); - remove_bytes(c, cmlen); + if (numeric(c, 500, "Sorry, no such command.")) + remove_bytes(c, cmlen); } /* @@ -1768,6 +1753,7 @@ #endif TRAP_ERROR(stat(ptr, &buf) == -1, 550, return -2); if (!S_ISREG(buf.st_mode)) { + /*FIXME: could destroy c*/ numeric(c, 550, "Not a plain file.", ptr); return -2; } @@ -1804,8 +1790,7 @@ #endif if ((f == NULL) || ((f->state != 1) && (f->state != 3))) { - numeric(c, 425, "No data connection set up; please use PASV or PORT."); - return -1; + return numeric(c, 425, "No data connection set up; please use PASV or PORT."); } /* @@ -1871,8 +1856,7 @@ #if WANT_NONROOT getcwd(chd, 512); if (nr_check_permission(c->uid, chd, 4, 1, NULL) == -1) { - numeric(c, 550, "Permission denied"); - return -1; + return numeric(c, 550, "Permission denied"); } #endif