diff options
Diffstat (limited to 'crypto/heimdal/appl/ftp/ftpd/ftpd.c')
-rw-r--r-- | crypto/heimdal/appl/ftp/ftpd/ftpd.c | 164 |
1 files changed, 69 insertions, 95 deletions
diff --git a/crypto/heimdal/appl/ftp/ftpd/ftpd.c b/crypto/heimdal/appl/ftp/ftpd/ftpd.c index 2005a4fb3161..5be67c866232 100644 --- a/crypto/heimdal/appl/ftp/ftpd/ftpd.c +++ b/crypto/heimdal/appl/ftp/ftpd/ftpd.c @@ -38,7 +38,7 @@ #endif #include "getarg.h" -RCSID("$Id: ftpd.c 21222 2007-06-20 10:11:14Z lha $"); +RCSID("$Id$"); static char version[] = "Version 6.00"; @@ -91,6 +91,7 @@ char tmpline[10240]; char hostname[MaxHostNameLen]; char remotehost[MaxHostNameLen]; static char ttyline[20]; +int paranoid = 1; #define AUTH_PLAIN (1 << 0) /* allow sending passwords */ #define AUTH_OTP (1 << 1) /* passwords are one-time */ @@ -190,7 +191,7 @@ parse_auth_level(char *str) else warnx("bad value for -a: `%s'", p); } - return ret; + return ret; } /* @@ -225,7 +226,7 @@ struct getargs args[] = { { "builtin-ls", 'B', arg_flag, &use_builtin_ls, "use built-in ls to list files" }, { "good-chars", 0, arg_string, &good_chars, "allowed anonymous upload filename chars" }, { "insecure-oob", 'I', arg_negative_flag, &allow_insecure_oob, "don't allow insecure OOB ABOR/STAT" }, -#ifdef KRB5 +#ifdef KRB5 { "gss-bindings", 0, arg_flag, &ftp_do_gss_bindings, "Require GSS-API bindings", NULL}, #endif { "version", 0, arg_flag, &version_flag }, @@ -271,22 +272,12 @@ main(int argc, char **argv) setprogname (argv[0]); - /* detach from any tickets and tokens */ - { -#ifdef KRB4 - char tkfile[1024]; - snprintf(tkfile, sizeof(tkfile), - "/tmp/ftp_%u", (unsigned)getpid()); - krb_set_tkt_string(tkfile); -#endif - } - if(getarg(args, num_args, argc, argv, &optind)) usage(1); if(help_flag) usage(0); - + if(version_flag) { print_version(NULL); exit(0); @@ -297,7 +288,7 @@ main(int argc, char **argv) { char *p; long val = 0; - + if(guest_umask_string) { val = strtol(guest_umask_string, &p, 8); if (*p != '\0' || val < 0) @@ -328,7 +319,7 @@ main(int argc, char **argv) else warnx("bad value for -p"); } - + if (maxtimeout < ftpd_timeout) maxtimeout = ftpd_timeout; @@ -338,7 +329,7 @@ main(int argc, char **argv) #endif if(interactive_flag) - mini_inetd (port); + mini_inetd(port, NULL); /* * LOG_NDELAY sets up the logging connection immediately, @@ -355,14 +346,9 @@ main(int argc, char **argv) syslog(LOG_ERR, "getsockname (%s): %m",argv[0]); exit(1); } -#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT) - { - int tos = IPTOS_LOWDELAY; - - if (setsockopt(STDIN_FILENO, IPPROTO_IP, IP_TOS, - (void *)&tos, sizeof(int)) < 0) - syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); - } +#if defined(IP_TOS) + if (ctrl_addr->sa_family == AF_INET) + socket_set_tos(STDIN_FILENO, IP_TOS); #endif data_source->sa_family = ctrl_addr->sa_family; socket_set_port (data_source, @@ -410,21 +396,15 @@ main(int argc, char **argv) show_file(_PATH_FTPWELCOME, 220); /* reply(220,) must follow */ gethostname(hostname, sizeof(hostname)); - + reply(220, "%s FTP server (%s" #ifdef KRB5 "+%s" #endif -#ifdef KRB4 - "+%s" -#endif ") ready.", hostname, version #ifdef KRB5 ,heimdal_version #endif -#ifdef KRB4 - ,krb4_version -#endif ); for (;;) @@ -528,7 +508,7 @@ user(char *name) guest = 0; if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) { if ((auth_level & AUTH_FTP) == 0 || - checkaccess("ftp") || + checkaccess("ftp") || checkaccess("anonymous")) reply(530, "User %s access denied.", name); else if ((pw = sgetpwnam("ftp")) != NULL) { @@ -661,7 +641,7 @@ checkuser(char *fname, char *name) /* - * Determine whether a user has access, based on information in + * Determine whether a user has access, based on information in * _PATH_FTPUSERS. The users are listed one per line, with `allow' * or `deny' after the username. If anything other than `allow', or * just nothing, is given after the username, `deny' is assumed. @@ -689,9 +669,9 @@ checkaccess(char *name) int allowed = ALLOWED; char *user, *perm, line[BUFSIZ]; char *foo; - + fd = fopen(_PATH_FTPUSERS, "r"); - + if(fd == NULL) return allowed; @@ -724,7 +704,7 @@ int do_login(int code, char *passwd) return -1; } initgroups(pw->pw_name, pw->pw_gid); -#if defined(KRB4) || defined(KRB5) +#if defined(KRB5) if(k_hasafs()) k_setpag(); #endif @@ -799,7 +779,7 @@ int do_login(int code, char *passwd) sizeof(data_addr)); syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s(%s), %s", - remotehost, + remotehost, data_addr, passwd); } @@ -850,11 +830,11 @@ end_login(void) static int krb5_verify(struct passwd *pwd, char *passwd) { - krb5_context context; + krb5_context context; krb5_ccache id; krb5_principal princ; krb5_error_code ret; - + ret = krb5_init_context(&context); if(ret) return ret; @@ -864,7 +844,7 @@ krb5_verify(struct passwd *pwd, char *passwd) krb5_free_context(context); return ret; } - ret = krb5_cc_gen_new(context, &krb5_mcc_ops, &id); + ret = krb5_cc_new_unique(context, "MEMORY", NULL, &id); if(ret){ krb5_free_principal(context, princ); krb5_free_context(context); @@ -882,7 +862,7 @@ krb5_verify(struct passwd *pwd, char *passwd) } krb5_cc_destroy(context, id); krb5_free_context (context); - if(ret) + if(ret) return ret; return 0; } @@ -917,21 +897,6 @@ pass(char *passwd) #ifdef KRB5 rval = krb5_verify(pw, passwd); #endif -#ifdef KRB4 - if (rval) { - char realm[REALM_SZ]; - if((rval = krb_get_lrealm(realm, 1)) == KSUCCESS) - rval = krb_verify_user(pw->pw_name, - "", realm, - passwd, - KRB_VERIFY_SECURE, NULL); - if (rval == KSUCCESS ) { - chown (tkt_string(), pw->pw_uid, pw->pw_gid); - if(k_hasafs()) - krb_afslog(0, 0); - } - } -#endif if (rval) rval = unix_verify_user(pw->pw_name, passwd); } else { @@ -977,7 +942,7 @@ pass(char *passwd) } if(!do_login(230, passwd)) return; - + /* Forget all about it... */ end_login(); } @@ -1013,7 +978,7 @@ retrieve(const char *cmd, char *name) for(p = cmds; p->ext; p++){ char *tail = name + strlen(name) - strlen(p->ext); char c = *tail; - + if(strcmp(tail, p->ext) == 0 && (*tail = 0) == 0 && access(name, R_OK) == 0){ @@ -1037,7 +1002,7 @@ retrieve(const char *cmd, char *name) free(ext); } } - + } if(p->ext){ fin = ftpd_popen(line, "r", 0, 0); @@ -1106,7 +1071,7 @@ done: /* filename sanity check */ -int +int filename_check(char *filename) { char *p; @@ -1127,7 +1092,7 @@ filename_check(char *filename) lreply(553, "\"%s\" is not an acceptable filename.", filename); lreply(553, "The filename must start with an alphanumeric " "character and must only"); - reply(553, "consist of alphanumeric characters or any of the following: %s", + reply(553, "consist of alphanumeric characters or any of the following: %s", good_chars); return 1; } @@ -1141,10 +1106,14 @@ do_store(char *name, char *mode, int unique) if(guest && filename_check(name)) return; - if (unique && stat(name, &st) == 0 && - (name = gunique(name)) == NULL) { - LOGCMD(*mode == 'w' ? "put" : "append", name); - return; + if (unique) { + char *uname; + if (stat(name, &st) == 0) { + if ((uname = gunique(name)) == NULL) + return; + name = uname; + } + LOGCMD(*mode == 'w' ? "put" : "append", name); } if (restart_point) @@ -1252,7 +1221,7 @@ bad: } static int -accept_with_timeout(int socket, +accept_with_timeout(int socket, struct sockaddr *address, socklen_t *address_len, struct timeval *timeout) @@ -1302,13 +1271,9 @@ dataconn(const char *name, off_t size, const char *mode) } close(pdata); pdata = s; -#if defined(IP_TOS) && defined(HAVE_SETSOCKOPT) - { - int tos = IPTOS_THROUGHPUT; - - setsockopt(s, IPPROTO_IP, IP_TOS, (void *)&tos, - sizeof(tos)); - } +#if defined(IPTOS_THROUGHPUT) + if (from->sa_family == AF_INET) + socket_set_tos(s, IPTOS_THROUGHPUT); #endif reply(150, "Opening %s mode data connection for '%s'%s.", type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf); @@ -1323,7 +1288,7 @@ dataconn(const char *name, off_t size, const char *mode) if (usedefault) data_dest = his_addr; usedefault = 1; - /* + /* * Default to using the same socket type as the ctrl address, * unless we know the type of the data address. */ @@ -1399,7 +1364,7 @@ send_data(FILE *instr, FILE *outstr) goto data_err; reply(226, "Transfer complete."); return; - + case TYPE_I: case TYPE_L: #if 0 /* XXX handle urg flag */ @@ -1411,7 +1376,7 @@ send_data(FILE *instr, FILE *outstr) struct stat st; char *chunk; int in = fileno(instr); - if(fstat(in, &st) == 0 && S_ISREG(st.st_mode) + if(fstat(in, &st) == 0 && S_ISREG(st.st_mode) && st.st_size > 0) { /* * mmap zero bytes has potential of loosing, don't do it. @@ -1505,7 +1470,7 @@ receive_data(FILE *instr, FILE *outstr) perror_reply(451, "Local resource failure: malloc"); return -1; } - + switch (type) { case TYPE_I: @@ -1534,7 +1499,7 @@ receive_data(FILE *instr, FILE *outstr) char *p, *q; int cr_flag = 0; while ((cnt = sec_read(fileno(instr), - buf + cr_flag, + buf + cr_flag, bufsize - cr_flag)) > 0){ if (urgflag && handleoobcmd()) return (-1); @@ -1583,13 +1548,13 @@ receive_data(FILE *instr, FILE *outstr) urgflag = 0; return (-1); } - + data_err: transflag = 0; urgflag = 0; perror_reply(426, "Data Connection"); return (-1); - + file_err: transflag = 0; urgflag = 0; @@ -1772,7 +1737,7 @@ do_delete(char *name) perror_reply(550, name); return; } - if ((st.st_mode&S_IFMT) == S_IFDIR) { + if (S_ISDIR(st.st_mode)) { if (rmdir(name) < 0) { perror_reply(550, name); return; @@ -1788,7 +1753,7 @@ done: } void -cwd(char *path) +cwd(const char *path) { if (chdir(path) < 0) @@ -1831,7 +1796,7 @@ pwd(void) char *ret; /* SunOS has a broken getcwd that does popen(pwd) (!!!), this - * failes miserably when running chroot + * failes miserably when running chroot */ ret = getcwd(path, sizeof(path)); if (ret == NULL) @@ -1902,7 +1867,7 @@ dologout(int status) transflag = 0; urgflag = 0; if (logged_in) { -#if KRB4 || KRB5 +#if KRB5 cond_kdestroy(); #endif seteuid((uid_t)0); /* No need to check, we call exit() below */ @@ -1913,7 +1878,7 @@ dologout(int status) exit(status); #else _exit(status); -#endif +#endif } void abor(void) @@ -2017,8 +1982,8 @@ pasv(void) socket_set_address_and_port (pasv_addr, socket_get_address (ctrl_addr), 0); - socket_set_portrange(pdata, restricted_data_ports, - pasv_addr->sa_family); + socket_set_portrange(pdata, restricted_data_ports, + pasv_addr->sa_family); if (seteuid(0) < 0) fatal("Failed to seteuid"); if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) { @@ -2064,8 +2029,8 @@ epsv(char *proto) socket_set_address_and_port (pasv_addr, socket_get_address (ctrl_addr), 0); - socket_set_portrange(pdata, restricted_data_ports, - pasv_addr->sa_family); + socket_set_portrange(pdata, restricted_data_ports, + pasv_addr->sa_family); if (seteuid(0) < 0) fatal("Failed to seteuid"); if (bind(pdata, pasv_addr, socket_sockaddr_size (pasv_addr)) < 0) { @@ -2123,7 +2088,7 @@ eprt(char *str) case 2 : data_dest->sa_family = AF_INET6; break; -#endif +#endif case 1 : data_dest->sa_family = AF_INET; break; @@ -2154,7 +2119,18 @@ eprt(char *str) reply(500, "Bad port syntax in EPRT"); return; } + if (port < IPPORT_RESERVED) { + reply(500, "Bad port in invalid range in EPRT"); + return; + } socket_set_port (data_dest, htons(port)); + + if (paranoid && + (data_dest->sa_family != his_addr->sa_family || + memcmp(socket_get_address(data_dest), socket_get_address(his_addr), socket_sockaddr_size(data_dest)) != 0)) + { + reply(500, "Bad address in EPRT"); + } reply(200, "EPRT command successful."); } @@ -2353,15 +2329,13 @@ out: transflag = 0; if (dout != NULL){ sec_write(fileno(dout), buf, 0); /* XXX flush */ - + fclose(dout); } data = -1; pdata = -1; - if (freeglob) { - freeglob = 0; + if (freeglob) globfree(&gl); - } } |