3f37ef937e
``Buffer overflows exist in the FTP daemon included with MIT krb5.'' See <URL:http://web.mit.edu/kerberos/www/advisories/ftpbuf.txt> and <URL:http://web.mit.edu/kerberos/www/advisories/ftpbuf_122_patch.txt>. Obtained from: MIT Kerberos mailing list
287 lines
7.6 KiB
Text
287 lines
7.6 KiB
Text
--- 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);
|
|
|
|
/*
|