Hi, This diff removes dead code from ftpd(8). In the past ftpd executes ls(1) for directory listings. But, quite a while now It justs calls the main function of the linked in ls(1) directly. The code path to the main function of ls(1) as well as the read-only mode are hard coded in the current version of ftpd. All callers of ftpd_popen() calls it with "/bin/ls" as program path. The diff below renames ftpd_popen() to ftpd_ls() and simplifies the function. Also, the manpage section to "~ftp/bin" is removed, because ftpd is not able to exec other programs.
I don't know if its usual?! But, I used an enum to signal file transfer or listing for the retrieve function. The code seems to be more readable for for me. bye, Jan Index: extern.h =================================================================== RCS file: /cvs/src/libexec/ftpd/extern.h,v retrieving revision 1.19 diff -u -p -r1.19 extern.h --- extern.h 4 Oct 2015 11:58:09 -0000 1.19 +++ extern.h 8 May 2019 20:02:23 -0000 @@ -68,7 +68,7 @@ void delete(char *); void dologout(int); void fatal(char *); int ftpd_pclose(FILE *, pid_t); -FILE *ftpd_popen(char *, char *, pid_t *); +FILE *ftpd_ls(char *, char *, pid_t *); int get_line(char *, int, FILE *); void ftpdlogwtmp(char *, char *, char *); void lreply(int, const char *, ...); @@ -89,7 +89,8 @@ void renamecmd(char *, char *); char *renamefrom(char *); void reply(int, const char *, ...); void reply_r(int, const char *, ...); -void retrieve(char *, char *); +enum ret_cmd { RET_FILE, RET_LIST }; +void retrieve(enum ret_cmd, char *); void send_file_list(char *); void setproctitle(const char *, ...); void statcmd(void); Index: ftpcmd.y =================================================================== RCS file: /cvs/src/libexec/ftpd/ftpcmd.y,v retrieving revision 1.66 diff -u -p -r1.66 ftpcmd.y --- ftpcmd.y 27 Apr 2017 13:30:54 -0000 1.66 +++ ftpcmd.y 8 May 2019 20:03:29 -0000 @@ -342,7 +342,7 @@ cmd | RETR check_login SP pathname CRLF { if ($2 && $4 != NULL) - retrieve(NULL, $4); + retrieve(RET_FILE, $4); if ($4 != NULL) free($4); } @@ -374,12 +374,12 @@ cmd | LIST check_login CRLF { if ($2) - retrieve("/bin/ls -lgA", ""); + retrieve(RET_LIST, NULL); } | LIST check_login SP pathname CRLF { if ($2 && $4 != NULL) - retrieve("/bin/ls -lgA %s", $4); + retrieve(RET_LIST, $4); if ($4 != NULL) free($4); } Index: ftpd.8 =================================================================== RCS file: /cvs/src/libexec/ftpd/ftpd.8,v retrieving revision 1.75 diff -u -p -r1.75 ftpd.8 --- ftpd.8 25 Oct 2015 23:10:53 -0000 1.75 +++ ftpd.8 8 May 2019 20:08:15 -0000 @@ -385,15 +385,6 @@ subtree be constructed with care, follow Make the home directory owned by .Dq root and unwritable by anyone (mode 555). -.It Pa ~ftp/bin -Make this directory owned by -.Dq root -and unwritable by anyone (mode 511). -This directory is optional unless you have commands you wish -the anonymous FTP user to be able to run (the -.Xr ls 1 -command exists as a built-in). -Any programs in this directory should be mode 111 (executable only). .It Pa ~ftp/etc Make this directory owned by .Dq root Index: ftpd.c =================================================================== RCS file: /cvs/src/libexec/ftpd/ftpd.c,v retrieving revision 1.225 diff -u -p -r1.225 ftpd.c --- ftpd.c 11 Dec 2018 18:19:55 -0000 1.225 +++ ftpd.c 8 May 2019 22:45:07 -0000 @@ -1113,36 +1113,32 @@ bad: } void -retrieve(char *cmd, char *name) +retrieve(enum ret_cmd cmd, char *name) { FILE *fin, *dout; struct stat st; pid_t pid; time_t start; - if (cmd == NULL) { + if (cmd == RET_FILE) { fin = fopen(name, "r"); st.st_size = 0; } else { - char line[BUFSIZ]; - - (void) snprintf(line, sizeof(line), cmd, name); - name = line; - fin = ftpd_popen(line, "r", &pid); + fin = ftpd_ls("-lgA", name, &pid); st.st_size = -1; st.st_blksize = BUFSIZ; } if (fin == NULL) { if (errno != 0) { perror_reply(550, name); - if (cmd == NULL) { + if (cmd == RET_FILE) { LOGCMD("get", name); } } return; } byte_count = -1; - if (cmd == NULL && + if (cmd == RET_FILE && (fstat(fileno(fin), &st) < 0 || !S_ISREG(st.st_mode))) { reply(550, "%s: not a plain file.", name); goto done; @@ -1175,8 +1171,8 @@ retrieve(char *cmd, char *name) goto done; time(&start); send_data(fin, dout, st.st_blksize, st.st_size, - (restart_point == 0 && cmd == NULL && S_ISREG(st.st_mode))); - if ((cmd == NULL) && stats) + (restart_point == 0 && cmd == RET_FILE && S_ISREG(st.st_mode))); + if ((cmd == RET_FILE) && stats) logxfer(name, byte_count, start); (void) fclose(dout); data = -1; @@ -1184,7 +1180,7 @@ done: if (pdata >= 0) (void) close(pdata); pdata = -1; - if (cmd == NULL) { + if (cmd == RET_FILE) { LOGBYTES("get", name, byte_count); fclose(fin); } else { @@ -1734,10 +1730,7 @@ statfilecmd(char *filename) int c; int atstart; pid_t pid; - char line[LINE_MAX]; - - (void)snprintf(line, sizeof(line), "/bin/ls -lgA %s", filename); - fin = ftpd_popen(line, "r", &pid); + fin = ftpd_ls("-lgA", filename, &pid); if (fin == NULL) { reply(451, "Local resource failure"); return; @@ -2633,7 +2626,7 @@ send_file_list(char *whichf) */ if (dirname[0] == '-' && *dirlist == NULL && transflag == 0) { - retrieve("/bin/ls %s", dirname); + retrieve(RET_FILE, dirname); goto out; } perror_reply(550, whichf); Index: popen.c =================================================================== RCS file: /cvs/src/libexec/ftpd/popen.c,v retrieving revision 1.26 diff -u -p -r1.26 popen.c --- popen.c 29 Feb 2016 17:50:34 -0000 1.26 +++ popen.c 8 May 2019 22:51:38 -0000 @@ -52,7 +52,7 @@ #include "extern.h" /* - * Special version of popen which avoids call to shell. This ensures noone + * Special version of popen which avoids call to shell. This ensures none * may create a pipe to a hidden program as a side effect of a list or dir * command. */ @@ -60,24 +60,24 @@ #define MAX_GARGV 1000 FILE * -ftpd_popen(char *program, char *type, pid_t *pidptr) +ftpd_ls(char *arg, char *path, pid_t *pidptr) { char *cp; FILE *iop; - int argc, gargc, pdes[2]; + int argc = 0, gargc, pdes[2]; pid_t pid; char **pop, *argv[MAX_ARGV], *gargv[MAX_GARGV]; - if ((*type != 'r' && *type != 'w') || type[1]) - return (NULL); - if (pipe(pdes) < 0) return (NULL); /* break up string into pieces */ - for (argc = 0, cp = program;argc < MAX_ARGV-1; cp = NULL) - if (!(argv[argc++] = strtok(cp, " \t\n"))) - break; + argv[argc++] = "/bin/ls"; + if (arg != NULL) + argv[argc++] = arg; + if (path != NULL) + argv[argc++] = path; + argv[argc] = NULL; argv[MAX_ARGV-1] = NULL; /* glob each piece */ @@ -115,42 +115,24 @@ ftpd_popen(char *program, char *type, pi goto pfree; /* NOTREACHED */ case 0: /* child */ - if (*type == 'r') { - if (pdes[1] != STDOUT_FILENO) { - dup2(pdes[1], STDOUT_FILENO); - (void)close(pdes[1]); - } - dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */ - (void)close(pdes[0]); - } else { - if (pdes[0] != STDIN_FILENO) { - dup2(pdes[0], STDIN_FILENO); - (void)close(pdes[0]); - } + if (pdes[1] != STDOUT_FILENO) { + dup2(pdes[1], STDOUT_FILENO); (void)close(pdes[1]); } + dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */ + (void)close(pdes[0]); closelog(); - if (strcmp(gargv[0], "/bin/ls") == 0) { - extern int optreset; - extern int ls_main(int, char **); - - /* reset getopt for ls_main */ - optreset = optind = 1; - exit(ls_main(gargc, gargv)); - } + extern int optreset; + extern int ls_main(int, char **); - execv(gargv[0], gargv); - _exit(1); + /* reset getopt for ls_main */ + optreset = optind = 1; + exit(ls_main(gargc, gargv)); } /* parent; assume fdopen can't fail... */ - if (*type == 'r') { - iop = fdopen(pdes[0], type); - (void)close(pdes[1]); - } else { - iop = fdopen(pdes[1], type); - (void)close(pdes[0]); - } + iop = fdopen(pdes[0], "r"); + (void)close(pdes[1]); *pidptr = pid; pfree: for (argc = 1; gargv[argc] != NULL; argc++)