Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/libexec/ftpd/ftpd.c,v rcsdiff: /ftp/cvs/cvsroot/src/libexec/ftpd/ftpd.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.89 retrieving revision 1.89.2.1 diff -u -p -r1.89 -r1.89.2.1 --- src/libexec/ftpd/ftpd.c 2000/05/20 23:34:55 1.89 +++ src/libexec/ftpd/ftpd.c 2000/06/22 15:58:17 1.89.2.1 @@ -1,4 +1,4 @@ -/* $NetBSD: ftpd.c,v 1.89 2000/05/20 23:34:55 lukem Exp $ */ +/* $NetBSD: ftpd.c,v 1.89.2.1 2000/06/22 15:58:17 minoura Exp $ */ /* * Copyright (c) 1997-2000 The NetBSD Foundation, Inc. @@ -109,7 +109,7 @@ __COPYRIGHT( #if 0 static char sccsid[] = "@(#)ftpd.c 8.5 (Berkeley) 4/28/95"; #else -__RCSID("$NetBSD: ftpd.c,v 1.89 2000/05/20 23:34:55 lukem Exp $"); +__RCSID("$NetBSD: ftpd.c,v 1.89.2.1 2000/06/22 15:58:17 minoura Exp $"); #endif #endif /* not lint */ @@ -144,6 +144,7 @@ __RCSID("$NetBSD: ftpd.c,v 1.89 2000/05/ #include #include #include +#include #include #include #include @@ -165,8 +166,6 @@ __RCSID("$NetBSD: ftpd.c,v 1.89 2000/05/ #include "pathnames.h" #include "version.h" -#include - int data; jmp_buf urgcatch; struct passwd *pw; @@ -178,15 +177,17 @@ int mapped = 0; /* IPv4 connection on A off_t file_size; off_t byte_count; static char ttyline[20]; -char *tty = ttyline; /* for klogin */ static struct utmp utmp; /* for utmp */ static char *anondir = NULL; static char confdir[MAXPATHLEN]; #if defined(KERBEROS) || defined(KERBEROS5) +int has_ccache = 0; int notickets = 1; char *krbtkfile_env = NULL; +char *tty = ttyline; +int login_krb5_forwardable_tgt = 0; #endif int epsvall = 0; @@ -202,16 +203,9 @@ int epsvall = 0; int swaitmax = SWAITMAX; int swaitint = SWAITINT; -#define CURCLASSTYPE curclass.type == CLASS_GUEST ? "GUEST" : \ - curclass.type == CLASS_CHROOT ? "CHROOT" : \ - curclass.type == CLASS_REAL ? "REAL" : \ - "" - -static void ack(const char *); static int bind_pasv_addr(void); static int checkuser(const char *, const char *, int, int, char **); static int checkaccess(const char *); -static FILE *dataconn(const char *, off_t, const char *); static void dolog(struct sockaddr *); static void end_login(void); static FILE *getdatasock(const char *); @@ -219,16 +213,19 @@ static char *gunique(const char *); static void lostconn(int); static void myoob(int); static int receive_data(FILE *, FILE *); -static void replydirname(const char *, const char *); static int send_data(FILE *, FILE *, off_t, int); static struct passwd *sgetpwnam(const char *); int main(int, char *[]); -#if defined(KERBEROS) || defined(KERBEROS5) +#if defined(KERBEROS) int klogin(struct passwd *, char *, char *, char *); void kdestroy(void); #endif +#if defined(KERBEROS5) +int k5login(struct passwd *, char *, char *, char *); +void k5destroy(void); +#endif int main(int argc, char *argv[]) @@ -246,6 +243,7 @@ main(int argc, char *argv[]) usedefault = 1; (void)strcpy(confdir, _DEFAULT_CONFDIR); hostname[0] = '\0'; + gidcount = 0; while ((ch = getopt(argc, argv, "a:c:C:dh:lst:T:u:Uv")) != -1) { switch (ch) { @@ -319,6 +317,8 @@ main(int argc, char *argv[]) /* * IPv4 control connection arrived to AF_INET6 socket. * I hate to do this, but this is the easiest solution. + * + * The assumption is untrue on SIIT environment. */ union sockunion tmp_addr; const int off = sizeof(struct in6_addr) - sizeof(struct in_addr); @@ -344,7 +344,7 @@ main(int argc, char *argv[]) while (fgets(line, sizeof(line), fd) != NULL) { if ((cp = strchr(line, '\n')) != NULL) *cp = '\0'; - lreply(530, "%s", line); + reply(-530, "%s", line); } (void) fflush(stdout); (void) fclose(fd); @@ -479,9 +479,9 @@ sgetpwnam(const char *name) return (&save); } -static int login_attempts; /* number of failed login attempts */ -static int askpasswd; /* had user command, ask for passwd */ -static char curname[10]; /* current USER name */ +static int login_attempts; /* number of failed login attempts */ +static int askpasswd; /* had user command, ask for passwd */ +static char curname[10]; /* current USER name */ /* * USER command. @@ -513,9 +513,12 @@ user(const char *name) } } -#if defined(KERBEROS) || defined(KERBEROS5) +#if defined(KERBEROS) kdestroy(); #endif +#if defined(KERBEROS5) + k5destroy(); +#endif curclass.type = CLASS_REAL; if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { @@ -732,6 +735,7 @@ end_login(void) pw = NULL; logged_in = 0; quietmessages = 0; + gidcount = 0; curclass.type = CLASS_REAL; } @@ -754,12 +758,18 @@ pass(const char *passwd) rval = 1; /* failure below */ goto skip; } -#if defined(KERBEROS) || defined(KERBEROS5) +#if defined(KERBEROS) if (klogin(pw, "", hostname, (char *)passwd) == 0) { rval = 0; goto skip; } #endif +#if defined(KERBEROS5) + if (k5login(pw, "", hostname, (char *)passwd) == 0) { + rval = 0; + goto skip; + } +#endif #ifdef SKEY if (skey_haskey(pw->pw_name) == 0) { char *p; @@ -839,6 +849,7 @@ pass(const char *passwd) goto bad; } (void) initgroups(pw->pw_name, pw->pw_gid); + gidcount = getgroups(sizeof(gidlist), gidlist); /* open wtmp before chroot */ logwtmp(ttyline, pw->pw_name, remotehost); @@ -924,7 +935,7 @@ pass(const char *passwd) pw->pw_name, pw->pw_dir); goto bad; } else - lreply(230, + reply(-230, "No directory! Logging in with home=/"); } else home = pw->pw_dir; @@ -985,7 +996,7 @@ pass(const char *passwd) void retrieve(char *argv[], const char *name) { - FILE *fin = NULL, *dout; + FILE *fin, *dout; struct stat st; int (*closefunc)(FILE *) = NULL; int log, sendrv, closerv, stderrfd, isconversion, isdata, isls; @@ -996,6 +1007,7 @@ retrieve(char *argv[], const char *name) isconversion = isdata = isls = log = 0; tdp = NULL; dispname = name; + fin = dout = NULL; if (argv == NULL) { log = 1; isdata = 1; @@ -1067,10 +1079,10 @@ retrieve(char *argv[], const char *name) (void)gettimeofday(&start, NULL); sendrv = send_data(fin, dout, st.st_blksize, isdata); (void)gettimeofday(&finish, NULL); - (void) fclose(dout); + (void) fclose(dout); /* close now to affect timing stats */ + dout = NULL; timersub(&finish, &start, &td); tdp = &td; - data = -1; done: if (log) logcmd("get", byte_count, name, NULL, tdp, NULL); @@ -1080,7 +1092,7 @@ retrieve(char *argv[], const char *name) struct stat sb; if (!isls && argv != NULL && closerv != 0) { - lreply(226, + reply(-226, "Command returned an exit status of %d", closerv); if (isconversion) @@ -1093,12 +1105,12 @@ retrieve(char *argv[], const char *name) ((err = fdopen(stderrfd, "r")) != NULL)) { char *cp, line[LINE_MAX]; - lreply(226, "Command error messages:"); + reply(-226, "Command error messages:"); rewind(err); while (fgets(line, sizeof(line), err) != NULL) { if ((cp = strchr(line, '\n')) != NULL) *cp = '\0'; - lreply(0, " %s", line); + reply(0, " %s", line); } (void) fflush(stdout); (void) fclose(err); @@ -1107,9 +1119,7 @@ retrieve(char *argv[], const char *name) reply(226, "Transfer complete."); } cleanupretrieve: - if (pdata >= 0) - (void)close(pdata); - pdata = -1; + closedataconn(dout); if (stderrfd != -1) (void)close(stderrfd); if (isconversion) @@ -1125,6 +1135,7 @@ store(const char *name, const char *mode struct timeval start, finish, td, *tdp; char *desc; + din = NULL; desc = (*mode == 'w') ? "put" : "append"; if (unique && stat(name, &st) == 0 && (name = gunique(name)) == NULL) { @@ -1182,17 +1193,15 @@ store(const char *name, const char *mode reply(226, "Transfer complete."); } (void)gettimeofday(&finish, NULL); - (void) fclose(din); + (void) fclose(din); /* close now to affect timing stats */ + din = NULL; timersub(&finish, &start, &td); tdp = &td; - data = -1; done: logcmd(desc, byte_count, name, NULL, tdp, NULL); (*closefunc)(fout); cleanupstore: - if (pdata >= 0) - (void)close(pdata); - pdata = -1; + closedataconn(din); } static FILE * @@ -1242,7 +1251,7 @@ getdatasock(const char *mode) return (NULL); } -static FILE * +FILE * dataconn(const char *name, off_t size, const char *mode) { char sizebuf[32]; @@ -1330,6 +1339,18 @@ dataconn(const char *name, off_t size, c return (file); } +void +closedataconn(FILE *fd) +{ + + if (fd != NULL) + (void)fclose(fd); + data = -1; + if (pdata >= 0) + (void)close(pdata); + pdata = -1; +} + /* * Tranfer the contents of "instr" to "outstr" peer using the appropriate * encapsulation of the data subject * to Mode, Structure, and Type. @@ -1597,10 +1618,10 @@ receive_data(FILE *instr, FILE *outstr) if (ferror(outstr)) goto file_err; if (bare_lfs) { - lreply(226, + reply(-226, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs); - lreply(0, "File may not have transferred correctly."); + reply(0, "File may not have transferred correctly."); } rval = 0; goto cleanup_recv_data; @@ -1631,133 +1652,76 @@ receive_data(FILE *instr, FILE *outstr) } void -statfilecmd(const char *filename) -{ - FILE *fin; - int c; - char *argv[] = { INTERNAL_LS, "-lgA", "", NULL }; - - argv[2] = (char *)filename; - fin = ftpd_popen(argv, "r", STDOUT_FILENO); - lreply(211, "status of %s:", filename); - while ((c = getc(fin)) != EOF) { - if (c == '\n') { - if (ferror(stdout)){ - perror_reply(421, "control connection"); - (void) ftpd_pclose(fin); - dologout(1); - /* NOTREACHED */ - } - if (ferror(fin)) { - perror_reply(551, filename); - (void) ftpd_pclose(fin); - return; - } - (void) putchar('\r'); - total_bytes++; - total_bytes_out++; - } - (void) putchar(c); - total_bytes++; - total_bytes_out++; - } - (void) ftpd_pclose(fin); - reply(211, "End of Status"); -} - -void statcmd(void) { union sockunion *su = NULL; static char ntop_buf[INET6_ADDRSTRLEN]; u_char *a, *p; int ispassive, af; - off_t b, otbi, otbo, otb; + off_t otbi, otbo, otb; a = p = (u_char *)NULL; - lreply(211, "%s FTP server status:", hostname); - lreply(0, "Version: %s", FTPD_VERSION); + reply(-211, "%s FTP server status:", hostname); + reply(0, "Version: %s", FTPD_VERSION); ntop_buf[0] = '\0'; if (!getnameinfo((struct sockaddr *)&his_addr, his_addr.su_len, ntop_buf, sizeof(ntop_buf), NULL, 0, NI_NUMERICHOST) && strcmp(remotehost, ntop_buf) != 0) { - lreply(0, "Connected to %s (%s)", remotehost, ntop_buf); + reply(0, "Connected to %s (%s)", remotehost, ntop_buf); } else - lreply(0, "Connected to %s", remotehost); + reply(0, "Connected to %s", remotehost); if (logged_in) { if (curclass.type == CLASS_GUEST) - lreply(0, "Logged in anonymously"); + reply(0, "Logged in anonymously"); else - lreply(0, "Logged in as %s%s", pw->pw_name, + reply(0, "Logged in as %s%s", pw->pw_name, curclass.type == CLASS_CHROOT ? " (chroot)" : ""); } else if (askpasswd) - lreply(0, "Waiting for password"); + reply(0, "Waiting for password"); else - lreply(0, "Waiting for user name"); - b = printf(" TYPE: %s", typenames[type]); - total_bytes += b; - total_bytes_out += b; - if (type == TYPE_A || type == TYPE_E) { - b = printf(", FORM: %s", formnames[form]); - total_bytes += b; - total_bytes_out += b; - } + reply(0, "Waiting for user name"); + cprintf(stdout, " TYPE: %s", typenames[type]); + if (type == TYPE_A || type == TYPE_E) + cprintf(stdout, ", FORM: %s", formnames[form]); if (type == TYPE_L) { #if NBBY == 8 - b = printf(" %d", NBBY); + cprintf(stdout, " %d", NBBY); #else /* XXX: `bytesize' needs to be defined in this case */ - b = printf(" %d", bytesize); + cprintf(stdout, " %d", bytesize); #endif - total_bytes += b; - total_bytes_out += b; } - b = printf("; STRUcture: %s; transfer MODE: %s\r\n", + cprintf(stdout, "; STRUcture: %s; transfer MODE: %s\r\n", strunames[stru], modenames[mode]); - total_bytes += b; - total_bytes_out += b; ispassive = 0; if (data != -1) { - lreply(0, "Data connection open"); + reply(0, "Data connection open"); su = NULL; } else if (pdata != -1) { - b = printf(" in Passive mode"); - total_bytes += b; - total_bytes_out += b; + reply(0, "in Passive mode"); su = (union sockunion *)&pasv_addr; ispassive = 1; goto printaddr; } else if (usedefault == 0) { if (epsvall) { - b = printf("211- EPSV only mode (EPSV ALL )\r\n"); - total_bytes += b; - total_bytes_out += b; + reply(0, "EPSV only mode (EPSV ALL)"); goto epsvonly; } - b = printf("211- %s", - (data_dest.su_family == AF_INET) ? "PORT" : "LPRT"); - total_bytes += b; - total_bytes_out += b; su = (union sockunion *)&data_dest; printaddr: - /* PASV/PORT */ + /* PASV/PORT */ if (su->su_family == AF_INET) { - if (ispassive) - b = printf("211- PASV "); - else - b = printf("211- PORT "); a = (u_char *) &su->su_sin.sin_addr; p = (u_char *) &su->su_sin.sin_port; #define UC(b) (((int) b) & 0xff) - b += printf("(%d,%d,%d,%d,%d,%d)\r\n", + reply(0, "%s (%d,%d,%d,%d,%d,%d)", + ispassive ? "PASV" : "PORT" , UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1])); - total_bytes += b; - total_bytes_out += b; } - /* LPSV/LPRT */ + /* LPSV/LPRT */ { int alen, af, i; @@ -1780,16 +1744,11 @@ statcmd(void) break; } if (af) { - if (ispassive) - b = printf("211- LPSV "); - else - b = printf("211- LPRT "); - printf("(%d,%d", af, alen); + cprintf(stdout, " %s (%d,%d", + ispassive ? "LPSV" : "LPRT", af, alen); for (i = 0; i < alen; i++) - b += printf("%d,", UC(a[alen])); - b += printf("%d,%d,%d)\r\n", 2, UC(p[0]), UC(p[1])); - total_bytes += b; - total_bytes_out += b; + cprintf(stdout, ",%d", UC(a[i])); + cprintf(stdout, ",%d,%d,%d)", 2, UC(p[0]), UC(p[1])); #undef UC } } @@ -1809,95 +1768,88 @@ statcmd(void) } if (af) { if (getnameinfo((struct sockaddr *)su, su->su_len, - ntop_buf, sizeof(ntop_buf), NULL, 0, + ntop_buf, sizeof(ntop_buf), NULL, 0, NI_NUMERICHOST) == 0) { - if (ispassive) - b = printf("211 - EPSV "); - else - b = printf("211 - EPRT "); - b += printf("(|%d|%s|%d|)\r\n", - af, ntop_buf, ntohs(su->su_port)); - total_bytes += b; - total_bytes_out += b; + reply(0, "%s (|%d|%s|%d|)", + ispassive ? "EPSV" : "EPRT", + af, ntop_buf, ntohs(su->su_port)); } } } else - lreply(0, "No data connection"); + reply(0, "No data connection"); if (logged_in) { - lreply(0, "Data sent: %qd byte%s in %qd file%s", + reply(0, "Data sent: %qd byte%s in %qd file%s", (qdfmt_t)total_data_out, PLURAL(total_data_out), (qdfmt_t)total_files_out, PLURAL(total_files_out)); - lreply(0, "Data received: %qd byte%s in %qd file%s", + reply(0, "Data received: %qd byte%s in %qd file%s", (qdfmt_t)total_data_in, PLURAL(total_data_in), (qdfmt_t)total_files_in, PLURAL(total_files_in)); - lreply(0, "Total data: %qd byte%s in %qd file%s", + reply(0, "Total data: %qd byte%s in %qd file%s", (qdfmt_t)total_data, PLURAL(total_data), (qdfmt_t)total_files, PLURAL(total_files)); } otbi = total_bytes_in; otbo = total_bytes_out; otb = total_bytes; - lreply(0, "Traffic sent: %qd byte%s in %qd transfer%s", + reply(0, "Traffic sent: %qd byte%s in %qd transfer%s", (qdfmt_t)otbo, PLURAL(otbo), (qdfmt_t)total_xfers_out, PLURAL(total_xfers_out)); - lreply(0, "Traffic received: %qd byte%s in %qd transfer%s", + reply(0, "Traffic received: %qd byte%s in %qd transfer%s", (qdfmt_t)otbi, PLURAL(otbi), (qdfmt_t)total_xfers_in, PLURAL(total_xfers_in)); - lreply(0, "Total traffic: %qd byte%s in %qd transfer%s", + reply(0, "Total traffic: %qd byte%s in %qd transfer%s", (qdfmt_t)otb, PLURAL(otb), (qdfmt_t)total_xfers, PLURAL(total_xfers)); if (logged_in) { struct ftpconv *cp; - lreply(0, ""); - lreply(0, "Class: %s, type: %s", + reply(0, ""); + reply(0, "Class: %s, type: %s", curclass.classname, CURCLASSTYPE); - lreply(0, "Check PORT/LPRT commands: %sabled", + reply(0, "Check PORT/LPRT commands: %sabled", curclass.checkportcmd ? "en" : "dis"); if (curclass.display != NULL) - lreply(0, "Display file: %s", curclass.display); + reply(0, "Display file: %s", curclass.display); if (curclass.notify != NULL) - lreply(0, "Notify fileglob: %s", curclass.notify); - lreply(0, "Idle timeout: %d, maximum timeout: %d", + reply(0, "Notify fileglob: %s", curclass.notify); + reply(0, "Idle timeout: %d, maximum timeout: %d", curclass.timeout, curclass.maxtimeout); - lreply(0, "Current connections: %d", connections); + reply(0, "Current connections: %d", connections); if (curclass.limit == -1) - lreply(0, "Maximum connections: unlimited"); + reply(0, "Maximum connections: unlimited"); else - lreply(0, "Maximum connections: %d", curclass.limit); + reply(0, "Maximum connections: %d", curclass.limit); if (curclass.limitfile) - lreply(0, "Connection limit exceeded file: %s", + reply(0, "Connection limit exceeded file: %s", curclass.limitfile); if (curclass.motd != NULL) - lreply(0, "MotD file: %s", curclass.motd); - lreply(0, + reply(0, "MotD file: %s", curclass.motd); + reply(0, "Modify commands (CHMOD, DELE, MKD, RMD, RNFR, UMASK): %sabled", curclass.modify ? "en" : "dis"); - lreply(0, - "Upload commands (APPE, STOR, STOU): %sabled", + reply(0, "Upload commands (APPE, STOR, STOU): %sabled", curclass.upload ? "en" : "dis"); if (curclass.portmin && curclass.portmax) - lreply(0, "PASV port range: %d - %d", + reply(0, "PASV port range: %d - %d", curclass.portmin, curclass.portmax); if (curclass.rateget) - lreply(0, "Rate get limit: %d bytes/sec", + reply(0, "Rate get limit: %d bytes/sec", curclass.rateget); else - lreply(0, "Rate get limit: disabled"); + reply(0, "Rate get limit: disabled"); if (curclass.rateput) - lreply(0, "Rate put limit: %d bytes/sec", + reply(0, "Rate put limit: %d bytes/sec", curclass.rateput); else - lreply(0, "Rate put limit: disabled"); - lreply(0, "Umask: %.04o", curclass.umask); + reply(0, "Rate put limit: disabled"); + reply(0, "Umask: %.04o", curclass.umask); for (cp = curclass.conversions; cp != NULL; cp=cp->next) { if (cp->suffix == NULL || cp->types == NULL || cp->command == NULL) continue; - lreply(0, - "Conversion: %s [%s] disable: %s, command: %s", + reply(0, "Conversion: %s [%s] disable: %s, command: %s", cp->suffix, cp->types, cp->disable, cp->command); } } @@ -1915,6 +1867,14 @@ fatal(const char *s) /* NOTREACHED */ } +/* + * reply() -- + * depending on the value of n, display fmt with a trailing CRLF and + * prefix of: + * n < -1 prefix the message with abs(n) + "-" (initial line) + * n == 0 prefix the message with 4 spaces (middle lines) + * n > 0 prefix the message with n + " " (final line) + */ void reply(int n, const char *fmt, ...) { @@ -1923,158 +1883,24 @@ reply(int n, const char *fmt, ...) va_start(ap, fmt); b = 0; - b += printf("%d ", n); - b += vprintf(fmt, ap); - b += printf("\r\n"); - total_bytes += b; - total_bytes_out += b; - (void)fflush(stdout); - if (debug) { - syslog(LOG_DEBUG, "<--- %d ", n); - vsyslog(LOG_DEBUG, fmt, ap); - } -} - -void -lreply(int n, const char *fmt, ...) -{ - off_t b; - va_list ap; - - va_start(ap, fmt); - b = 0; - switch (n) { - case 0: - b += printf(" "); - case -1: - break; - default: - b += printf("%d-", n); - break; - } - b += vprintf(fmt, ap); - b += printf("\r\n"); + if (n == 0) + cprintf(stdout, " "); + else if (n < 0) + cprintf(stdout, "%d-", -n); + else + cprintf(stdout, "%d ", n); + b = vprintf(fmt, ap); total_bytes += b; total_bytes_out += b; + cprintf(stdout, "\r\n"); (void)fflush(stdout); if (debug) { - syslog(LOG_DEBUG, "<--- %d- ", n); + syslog(LOG_DEBUG, "<--- %d%c", abs(n), (n < 0) ? '-' : ' '); vsyslog(LOG_DEBUG, fmt, ap); } } static void -ack(const char *s) -{ - - reply(250, "%s command successful.", s); -} - -void -delete(const char *name) -{ - char *p = NULL; - - if (remove(name) < 0) { - p = strerror(errno); - perror_reply(550, name); - } else - ack("DELE"); - logcmd("delete", -1, name, NULL, NULL, p); -} - -void -cwd(const char *path) -{ - - if (chdir(path) < 0) - perror_reply(550, path); - else { - show_chdir_messages(250); - ack("CWD"); - } -} - -static void -replydirname(const char *name, const char *message) -{ - char npath[MAXPATHLEN]; - int i; - - for (i = 0; *name != '\0' && i < sizeof(npath) - 1; i++, name++) { - npath[i] = *name; - if (*name == '"') - npath[++i] = '"'; - } - npath[i] = '\0'; - reply(257, "\"%s\" %s", npath, message); -} - -void -makedir(const char *name) -{ - char *p = NULL; - - if (mkdir(name, 0777) < 0) { - p = strerror(errno); - perror_reply(550, name); - } else - replydirname(name, "directory created."); - logcmd("mkdir", -1, name, NULL, NULL, p); -} - -void -removedir(const char *name) -{ - char *p = NULL; - - if (rmdir(name) < 0) { - p = strerror(errno); - perror_reply(550, name); - } else - ack("RMD"); - logcmd("rmdir", -1, name, NULL, NULL, p); -} - -void -pwd(void) -{ - char path[MAXPATHLEN]; - - if (getcwd(path, sizeof(path) - 1) == NULL) - reply(550, "Can't get the current directory: %s.", - strerror(errno)); - else - replydirname(path, "is the current directory."); -} - -char * -renamefrom(const char *name) -{ - struct stat st; - - if (stat(name, &st) < 0) { - perror_reply(550, name); - return (NULL); - } - reply(350, "File exists, ready for destination name"); - return (xstrdup(name)); -} - -void -renamecmd(const char *from, const char *to) -{ - char *p = NULL; - - if (rename(from, to) < 0) { - p = strerror(errno); - perror_reply(550, "rename"); - } else - ack("RNTO"); - logcmd("rename", -1, from, to, NULL, p); -} - -static void dolog(struct sockaddr *who) { getnameinfo(who, who->sa_len, remotehost, sizeof(remotehost), NULL,0,0); @@ -2444,15 +2270,7 @@ send_file_list(const char *whichf) goto out; } perror_reply(550, whichf); - if (dout != NULL) { - (void) fclose(dout); - transflag = 0; - data = -1; - if (pdata >= 0) - (void)close(pdata); - pdata = -1; - } - goto out; + goto cleanup_send_file_list; } if (S_ISREG(st.st_mode)) { @@ -2480,10 +2298,7 @@ send_file_list(const char *whichf) while ((dir = readdir(dirp)) != NULL) { char nbuf[MAXPATHLEN]; - if (dir->d_name[0] == '.' && dir->d_namlen == 1) - continue; - if (dir->d_name[0] == '.' && dir->d_name[1] == '.' && - dir->d_namlen == 2) + if (ISDOTDIR(dir->d_name) || ISDOTDOTDIR(dir->d_name)) continue; (void)snprintf(nbuf, sizeof(nbuf), "%s%s%s", dirname, @@ -2525,13 +2340,9 @@ send_file_list(const char *whichf) else reply(226, "Transfer complete."); + cleanup_send_file_list: transflag = 0; - if (dout != NULL) - (void) fclose(dout); - else if (pdata >= 0) - (void)close(pdata); - data = -1; - pdata = -1; + closedataconn(dout); out: total_xfers++; total_xfers_out++; @@ -2562,7 +2373,6 @@ conffilename(const char *s) * if elapsed != NULL, append "in xxx.yyy seconds" * if error != NULL, append ": " + error */ - void logcmd(const char *command, off_t bytes, const char *file1, const char *file2, const struct timeval *elapsed, const char *error) @@ -2619,3 +2429,19 @@ xstrdup(const char *s) /* NOTREACHED */ return (new); } + +/* + * As per fprintf(), but increment total_bytes and total_bytes_out, + * by the appropriate amount. + */ +void +cprintf(FILE *fd, const char *fmt, ...) +{ + off_t b; + va_list ap; + + va_start(ap, fmt); + b = vfprintf(fd, fmt, ap); + total_bytes += b; + total_bytes_out += b; +}