X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=cmds.c;h=a2e047bc51eef0a54ffc3d8d46ea4f74c74108ba;hb=f0c7394d9bdae7e980847003f2da6dcc3d2ad96c;hp=131df3403bf9bf32e6050da978da4e55dab1baf2;hpb=4b83f8e50792b459dfd8a6ffe470c2fccb524e7b;p=betaftpd diff --git a/cmds.c b/cmds.c index 131df34..a2e047b 100644 --- a/cmds.c +++ b/cmds.c @@ -141,6 +141,10 @@ #include #include +#if WANT_DCACHE +#include +#endif + #define lstat stat extern struct conn *first_conn; @@ -341,6 +345,10 @@ int cmd_pass(struct conn * const c) } #endif /* !WANT_NONROOT */ + /* root should not be allowed to FTP */ + if (c->uid == 0) { + c->auth = 0; + } if (c->auth == 0) { numeric(c, 530, "Login incorrect."); } else { @@ -802,7 +810,7 @@ int cmd_rnfr(struct conn * const c) snprintf(c->rename_from, 256, "%s/%s", cwd, fname); /* Just check that the file exists. */ - TRAP_ERROR(lstat(c->rename_from, &buf) == -1, 550, return 1); + 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; @@ -821,9 +829,10 @@ int cmd_rnto(struct conn * const c) return 1; } - TRAP_ERROR(rename(c->rename_from, fname) == -1, 550, return 1); + 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 successfulyy."); + numeric(c, 250, "File renamed successfully."); return 1; } @@ -932,11 +941,19 @@ int cmd_stat(struct conn * const c) " BetaFTPD version " VERSION " (http://members.xoom.com/sneeze/betaftpd.html)\r\n" " Connected to %s\r\n" " Control connection state: %s\r\n" +#if WANT_ASCII + " TYPE: %s; STRUcture: File; transfer MODE: Stream\r\n" +#else " TYPE: Image; STRUcture: File; transfer MODE: Stream\r\n" +#endif " Data connection state: %s\r\n" "211 End of status\r\n", inet_ntoa(((struct sockaddr_in *)(&(c->addr)))->sin_addr), - conn_state[c->auth], (f) ? ftran_state[f->state] : ftran_state[0]); + conn_state[c->auth], +#if WANT_ASCII + (c->ascii_mode == 1) ? "ASCII, FORM: Nonprint" : "Image", +#endif + (f) ? ftran_state[f->state] : ftran_state[0]); i = strlen(buf); @@ -972,9 +989,14 @@ int _mwrite(const char * const buf, const struct ftran * const f, /* * mwrite: This is a short_hand define, making calls to _mwrite() very - * similiar to calls to write(). + * similiar to calls to write(). It works both with and without + * mmap(). */ +#if HAVE_MMAP #define mwrite(buf, count) pos = _mwrite((buf), (f), (pos), (count), (size)); +#else +#define mwrite(buf, count) write(f->local_file, buf, count); +#endif /* * long_listing(): @@ -1040,14 +1062,14 @@ int long_listing(char * const retbuf, const char * const pathname, const int do_ #if WANT_NONROOT char rights[16]; - if (nr_check_permission(0, pathname, 0, (buf.st_mode & S_IFDIR), rights) == -1) { + if (nr_check_permission(0, pathname, 0, (S_ISDIR(buf.st_mode)), rights) == -1) { /* no permission to even see this file */ return 0; } - i = snprintf(temp, 1024, "%c%s %3u %-8s %-8s %8lu %12s %s\r\n", + snprintf(temp, 1024, "%c%s %3u %-8s %-8s %8lu %12s %s\r\n", #else - i = snprintf(temp, 1024, "%c%c%c%c%c%c%c%c%c%c %3u %-8s %-8s %8lu %12s %s", + snprintf(temp, 1024, "%c%c%c%c%c%c%c%c%c%c %3u %-8s %-8s %8lu %12s %s", #endif decode_mode(buf.st_mode), #if WANT_NONROOT @@ -1065,7 +1087,8 @@ int long_listing(char * const retbuf, const char * const pathname, const int do_ #endif buf.st_nlink, username, groupname, (unsigned long)(buf.st_size), newd, pathname); - + i = strlen(temp); + #if 0 /* * vim needs this extra character for some reason... It's too @@ -1096,7 +1119,7 @@ int cmd_list(struct conn * const c) { struct list_options lo; -/* lo.recursive = 0; */ + lo.recursive = 0; lo.long_listing = 1; lo.classify = 0; @@ -1115,7 +1138,7 @@ int cmd_nlst(struct conn * const c) { struct list_options lo; -/* lo.recursive = 0; */ + lo.recursive = 0; lo.long_listing = 0; lo.classify = 0; @@ -1200,30 +1223,14 @@ void do_listing(struct conn * const c, struct list_options * const lo) size = num_files * 160; f->file_data = malloc(size + 1); TRAP_ERROR(f->file_data == NULL, 550, return); - list_core(c, ptr, lo, size); + list_core(c, ptr, "", lo, size, 0); } #else - list_core(c, ptr, lo); + list_core(c, ptr, "", lo); #endif #if WANT_DCACHE - /* populate the directory listing cache */ - { - struct stat buf; - struct dcache *d = alloc_new_dcache(); - if (d != NULL && stat(cwd, &buf) > -1) { - d->use_count++; - f->dir_cache = d; - d->dir_data = f->file_data; - d->dir_size = f->size; - d->generated = buf.st_mtime; - - strcpy(d->dir_name, cwd); - strncpy(d->pattern, ptr, 255); - d->pattern[255] = 0; - d->lo = *lo; - } - } + populate_dcache(f, cwd, ptr, lo); #endif #if HAVE_MMAP @@ -1260,8 +1267,8 @@ int get_num_files(struct conn * const c, const char * const pathname, return -1; } -#if 0 /* the rest of the code doesn't support recursion yet */ if (lo->recursive) { + int i; for (i = 0; i < pglob.gl_pathc; i++) { char *temp = pglob.gl_pathv[i]; struct stat buf; @@ -1274,7 +1281,8 @@ int get_num_files(struct conn * const c, const char * const pathname, } } } -#endif + + globfree(&pglob); return num_files; } @@ -1289,20 +1297,20 @@ int get_num_files(struct conn * const c, const char * const pathname, * under 80 for long listings, and a little under 160 for * short listings), the list will be truncated. Fix... * + * The return value only makes sense if mmap()'ing, since it + * returns the number of bytes written into the buffer. + * * This function is rather long. */ -void list_core(struct conn * const c, const char * const pathname, - struct list_options * const lo +int list_core(struct conn * const c, const char * const pathname, + char * const disp_pathname, struct list_options * const lo #if HAVE_MMAP - , const int size + , const int size, int pos #endif ) { int i; glob_t pglob; -#if HAVE_MMAP - int pos = 0; -#endif struct ftran * const f = c->transfer; /* @@ -1314,12 +1322,28 @@ void list_core(struct conn * const c, const char * const pathname, #ifdef GLOB_NOMATCH case GLOB_NOMATCH: #endif - break; + break; /* note: break, not return */ default: numeric(c, 550, strerror(EACCES)); - return; +#if HAVE_MMAP + return pos; +#else + return 0; +#endif } + if (lo->recursive) { + if (disp_pathname[0] == '\0') { + mwrite(".:\r\n", 4); + } else { + char temp[1024]; + int i; + + snprintf(temp, 1024, "%s:\r\n", disp_pathname); + i = strlen(temp); + mwrite(temp, i); + } + } if (lo->long_listing) { /* FIX: we may get too high total number if we are running nonroot! */ struct stat buf; @@ -1331,12 +1355,9 @@ void list_core(struct conn * const c, const char * const pathname, total += buf.st_blocks; } } - i = snprintf(temp, 1024, "total %lu\r\n", total >> 1); -#if HAVE_MMAP + snprintf(temp, 1024, "total %lu\r\n", total >> 1); + i = strlen(temp); mwrite(temp, i); -#else - write(f->local_file, temp, i); -#endif } for (i = 0; i < pglob.gl_pathc; i++) { @@ -1367,15 +1388,43 @@ void list_core(struct conn * const c, const char * const pathname, } } - /* support recursion here some day... */ - -#if HAVE_MMAP mwrite(buf, strlen(buf)); mwrite("\r\n", 2); -#else - write(f->local_file, buf, strlen(buf)); - write(f->local_file, "\r\n", 2); + } + + /* + * If recursion is on, dive into any subdirectories now -- note + * that each entry is stat()'ed twice, hopefully the OS will manage, + * and we've got our own dcache anyways -- this could be fixed at + * the expense of some memory, consider for later inclusion. + */ + if (lo->recursive) { + for (i = 0; i < pglob.gl_pathc; i++) { + struct stat buf; + const char * const temp = pglob.gl_pathv[i]; + + /* don't dive into `.' or `..' */ + if (lstat(temp, &buf) != -1 && S_ISDIR(buf.st_mode) && + (temp[0] != '.' || (temp[1] != '.' && temp[1] != '\0'))) { + char tmp2[1024]; + + mwrite("\r\n", 2); + + /* attach the pathname to the end of the displayed path */ + if (disp_pathname[0] == '\0') { + snprintf(tmp2, 1024, "%s", temp); + } else { + snprintf(tmp2, 1024, "%s/%s", disp_pathname, temp); + } + + chdir(temp); + pos = list_core(c, "*", tmp2, lo, +#if HAVE_MMAP + size, pos); #endif + chdir(".."); + } + } } #if HAVE_MMAP @@ -1385,6 +1434,11 @@ void list_core(struct conn * const c, const char * const pathname, #endif globfree(&pglob); +#if HAVE_MMAP + return pos; +#else + return 0; +#endif } /* @@ -1429,22 +1483,30 @@ int cmd_type(struct conn * const c) } /* - * cmd_mode(): Handles the MODE command. We always use stream mode, - * so the argument is ignored. + * cmd_mode(): Handles the MODE command. Only stream mode is supported. */ int cmd_mode(struct conn * const c) { - numeric(c, 200, "MODE ignored (always S)"); + c->recv_buf[0] &= (255-32); /* convert to upper case */ + if (c->recv_buf[0] == 'S') { + numeric(c, 200, "Mode is STREAM."); + } else { + numeric(c, 504, "Unknown mode."); + } return 1; } /* - * cmd_stru(): Handles the STRU command. We always use file mode, - * so the argument is ignored. + * cmd_stru(): Handles the STRU command. Only file mode is supported. */ int cmd_stru(struct conn * const c) { - numeric(c, 200, "STRU ignored (always F)"); + c->recv_buf[0] &= (255-32); /* convert to upper case */ + if (c->recv_buf[0] == 'F') { + numeric(c, 200, "Structure is FILE."); + } else { + numeric(c, 504, "Unknown structure."); + } return 1; } @@ -1652,13 +1714,13 @@ void prepare_for_transfer(struct ftran *f) * The most common cases are put first, for speed :-) */ char decode_mode(mode_t mode) { - if (mode & S_IFREG) return '-'; - if (mode & S_IFDIR) return 'd'; - if (mode & S_IFLNK) return 'l'; - if (mode & S_IFBLK) return 'b'; - if (mode & S_IFCHR) return 'c'; - if (mode & S_IFSOCK) return 's'; - if (mode & S_IFIFO) return 'f'; + if (S_ISREG(mode)) return '-'; + if (S_ISDIR(mode)) return 'd'; + if (S_ISLNK(mode)) return 'l'; + if (S_ISBLK(mode)) return 'b'; + if (S_ISCHR(mode)) return 'c'; + if (S_ISSOCK(mode)) return 's'; + if (S_ISFIFO(mode)) return 'f'; return '-'; } @@ -1733,9 +1795,9 @@ int do_openfile(struct conn * const c, char * const path, #if WANT_UPLOAD if ((flags & O_CREAT) == 0) { #endif - stat(ptr, &buf); + TRAP_ERROR(stat(ptr, &buf) == -1, 550, return -2); if (!S_ISREG(buf.st_mode)) { - numeric(c, 550, "%s: Not a plain file.", ptr); + numeric(c, 550, "Not a plain file.", ptr); return -2; } #if WANT_UPLOAD @@ -1790,11 +1852,9 @@ int prepare_for_listing(struct conn * const c, char ** const ptr, if (optr != NULL) { while (*++optr) { switch (*optr & (255-32)) { /* uppercase */ -#if 0 case 'R': /* actually case sensitive... */ lo->recursive = 1; break; -#endif case 'L': lo->long_listing = 1; break;