--- appl/gssftp/ftpd/ftpd.c.orig Wed Feb 28 16:06:45 2001 +++ appl/gssftp/ftpd/ftpd.c Fri Apr 27 10:18:01 2001 @@ -485,7 +485,13 @@ #ifndef LOG_DAEMON #define LOG_DAEMON 0 #endif - openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_DAEMON); + +#ifndef LOG_FTP +#define FACILITY LOG_DAEMON +#else +#define FACILITY LOG_FTP +#endif + openlog("ftpd", LOG_PID | LOG_NDELAY, FACILITY); addrlen = sizeof (his_addr); if (getpeername(0, (struct sockaddr *)&his_addr, &addrlen) < 0) { @@ -761,7 +767,16 @@ int result; #ifdef GSSAPI if (auth_type && strcmp(auth_type, "GSSAPI") == 0) { + int len; authorized = ftpd_gss_userok(&client_name, name) == 0; + len = sizeof("GSSAPI user is not authorized as " + "; Password required.") + + strlen(client_name.value) + + strlen(name); + if (len >= sizeof(buf)) { + syslog(LOG_ERR, "user: username too long"); + name = "[username too long]"; + } sprintf(buf, "GSSAPI user %s is%s authorized as %s", client_name.value, authorized ? "" : " not", name); @@ -772,7 +787,18 @@ #endif /* GSSAPI */ #ifdef KRB5_KRB4_COMPAT if (auth_type && strcmp(auth_type, "KERBEROS_V4") == 0) { + int len; authorized = kuserok(&kdata,name) == 0; + len = sizeof("Kerberos user .@ is not authorized as " + "; Password required.") + + strlen(kdata.pname) + + strlen(kdata.pinst) + + strlen(kdata.prealm) + + strlen(name); + if (len >= sizeof(buf)) { + syslog(LOG_ERR, "user: username too long"); + name = "[username too long]"; + } sprintf(buf, "Kerberos user %s%s%s@%s is%s authorized as %s", kdata.pname, *kdata.pinst ? "." : "", kdata.pinst, kdata.prealm, @@ -1179,6 +1205,11 @@ } else { char line[FTP_BUFSIZ]; + if (strlen(cmd) + strlen(name) + 1 >= sizeof(line)) { + syslog(LOG_ERR, "retrieve: filename too long"); + reply(501, "filename too long"); + return; + } (void) sprintf(line, cmd, name), name = line; fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; st.st_size = -1; @@ -1417,6 +1448,10 @@ return (file); } +/* + * XXX callers need to limit total length of output string to + * FTP_BUFSIZ + */ #ifdef STDARG secure_error(char *fmt, ...) #else @@ -1616,13 +1651,19 @@ { char line[FTP_BUFSIZ]; FILE *fin; - int c; + int c, n; char str[FTP_BUFSIZ], *p; + if (strlen(filename) + sizeof("/bin/ls -lgA ") + >= sizeof(line)) { + reply(501, "filename too long"); + return; + } (void) sprintf(line, "/bin/ls -lgA %s", filename); fin = ftpd_popen(line, "r"); lreply(211, "status of %s:", filename); p = str; + n = 0; while ((c = getc(fin)) != EOF) { if (c == '\n') { if (ferror(stdout)){ @@ -1639,7 +1680,16 @@ *p = '\0'; reply(0, "%s", str); p = str; - } else *p++ = c; + n = 0; + } else { + *p++ = c; + n++; + if (n >= sizeof(str)) { + reply(551, "output line too long"); + (void) ftpd_pclose(fin); + return; + } + } } if (p != str) { *p = '\0'; @@ -1723,6 +1773,10 @@ char cont_char = ' '; +/* + * XXX callers need to limit total length of output string to + * FTP_BUFSIZ bytes for now. + */ #ifdef STDARG reply(int n, char *fmt, ...) #else @@ -1744,22 +1798,32 @@ #endif if (auth_type) { - char in[FTP_BUFSIZ], out[FTP_BUFSIZ]; + /* + * Deal with expansion in mk_{safe,priv}, + * radix_encode, gss_seal, plus slop. + */ + char in[FTP_BUFSIZ*3/2], out[FTP_BUFSIZ*3/2]; int length, kerror; if (n) sprintf(in, "%d%c", n, cont_char); else in[0] = '\0'; strncat(in, buf, sizeof (in) - strlen(in) - 1); #ifdef KRB5_KRB4_COMPAT if (strcmp(auth_type, "KERBEROS_V4") == 0) { - if ((length = clevel == PROT_P ? - krb_mk_priv((unsigned char *)in, - (unsigned char *)out, - strlen(in), schedule, &kdata.session, - &ctrl_addr, &his_addr) - : krb_mk_safe((unsigned char *)in, - (unsigned char *)out, - strlen(in), &kdata.session, - &ctrl_addr, &his_addr)) == -1) { + if (clevel == PROT_P) + length = krb_mk_priv((unsigned char *)in, + (unsigned char *)out, + strlen(in), + schedule, &kdata.session, + &ctrl_addr, + &his_addr); + else + length = krb_mk_safe((unsigned char *)in, + (unsigned char *)out, + strlen(in), + &kdata.session, + &ctrl_addr, + &his_addr); + if (length == -1) { syslog(LOG_ERR, "krb_mk_%s failed for KERBEROS_V4", clevel == PROT_P ? "priv" : "safe"); @@ -1803,13 +1867,16 @@ } #endif /* GSSAPI */ /* Other auth types go here ... */ - if (kerror = radix_encode(out, in, &length, 0)) { + if (length >= sizeof(in) / 4 * 3) { + syslog(LOG_ERR, "input to radix_encode too long"); + fputs(in, stdout); + } else if (kerror = radix_encode(out, in, &length, 0)) { syslog(LOG_ERR, "Couldn't encode reply (%s)", radix_error(kerror)); fputs(in,stdout); } else - printf("%s%c%s", clevel == PROT_P ? "632" : "631", - n ? cont_char : '-', in); + printf("%s%c%s", clevel == PROT_P ? "632" : "631", + n ? cont_char : '-', in); } else { if (n) printf("%d%c", n, cont_char); fputs(buf, stdout); @@ -1822,6 +1889,10 @@ } } +/* + * XXX callers need to limit total length of output string to + * FTP_BUFSIZ + */ #ifdef STDARG lreply(int n, char *fmt, ...) #else @@ -1866,7 +1937,8 @@ if (cp = strchr(cbuf,'\n')) *cp = '\0'; - reply(500, "'%s': command not understood.", cbuf); + reply(500, "'%.*s': command not understood.", + FTP_BUFSIZ - sizeof("'': command not understood."), cbuf); } delete_file(name) @@ -2143,7 +2215,21 @@ int code; char *string; { - reply(code, "%s: %s.", string, strerror(errno)); + char *err_string; + size_t extra_len; + err_string = strerror(errno); + if (err_string == NULL) + err_string = "(unknown error)"; + extra_len = strlen(err_string) + sizeof("(truncated): ."); + /* + * XXX knows about FTP_BUFSIZ in reply() + */ + if (strlen(string) + extra_len > FTP_BUFSIZ) { + reply(code, "(truncated)%.*s: %s.", + FTP_BUFSIZ - extra_len, string, err_string); + } else { + reply(code, "%s: %s.", string, err_string); + } } auth(type) @@ -2226,6 +2312,10 @@ secure_error("ADAT: krb_mk_safe failed"); return(0); } + if (length >= (FTP_BUFSIZ - sizeof("ADAT=")) / 4 * 3) { + secure_error("ADAT: reply too long"); + return(0); + } if (kerror = radix_encode(out_buf, buf, &length, 0)) { secure_error("Couldn't encode ADAT reply (%s)", radix_error(kerror)); @@ -2360,6 +2450,16 @@ } if (out_tok.length) { + if (out_tok.length >= ((FTP_BUFSIZ - sizeof("ADAT=")) + / 4 * 3)) { + secure_error("ADAT: reply too long"); + syslog(LOG_ERR, "ADAT: reply too long"); + (void) gss_release_cred(&stat_min, &server_creds); + if (ret_flags & GSS_C_DELEG_FLAG) + (void) gss_release_cred(&stat_min, + &deleg_creds); + return(0); + } if (kerror = radix_encode(out_tok.value, gbuf, &out_tok.length, 0)) { secure_error("Couldn't encode ADAT reply (%s)", radix_error(kerror)); @@ -2458,6 +2558,9 @@ * n>=0 on success * -1 on error * -2 on security error + * + * XXX callers need to limit total length of output string to + * FTP_BUFSIZ */ #ifdef STDARG secure_fprintf(FILE *stream, char *fmt, ...) @@ -2575,6 +2678,15 @@ dir->d_name[2] == '\0') continue; + if (strlen(dirname) + strlen(dir->d_name) + + 1 /* slash */ + + 2 /* CRLF */ + + 1 > sizeof(nbuf)) { + syslog(LOG_ERR, + "send_file_list: pathname too long"); + ret = -2; /* XXX */ + goto data_err; + } sprintf(nbuf, "%s/%s", dirname, dir->d_name); /*