diff mbox

[linux-cifs-client] cifs.upcall: make using ip address conditional on new option

Message ID 1250703037-3640-1-git-send-email-jlayton@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jeff Layton Aug. 19, 2009, 5:30 p.m. UTC
Igor Mammedov pointed out that reverse resolving an IP address to get
the hostname portion of a principal could open a possible attack
vector. If an attacker were to gain control of DNS, then he could
redirect the mount to a server of his choosing, and fix the reverse
resolution to point to a hostname of his choosing (one where he has
the key for the corresponding cifs/ or host/ principal).

That said, we often trust DNS for other reasons and it can be useful
to do so. Make the code that allows trusting DNS to be enabled by
adding --trust-dns to the cifs.upcall invocation.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
---
 client/cifs.upcall.c |   62 ++++++++++++++++++++++++++++++++-----------------
 1 files changed, 40 insertions(+), 22 deletions(-)

Comments

Jeff Layton Aug. 26, 2009, 10:29 a.m. UTC | #1
On Wed, 19 Aug 2009 13:30:37 -0400
Jeff Layton <jlayton@redhat.com> wrote:

> Igor Mammedov pointed out that reverse resolving an IP address to get
> the hostname portion of a principal could open a possible attack
> vector. If an attacker were to gain control of DNS, then he could
> redirect the mount to a server of his choosing, and fix the reverse
> resolution to point to a hostname of his choosing (one where he has
> the key for the corresponding cifs/ or host/ principal).
> 
> That said, we often trust DNS for other reasons and it can be useful
> to do so. Make the code that allows trusting DNS to be enabled by
> adding --trust-dns to the cifs.upcall invocation.
> 
> Signed-off-by: Jeff Layton <jlayton@redhat.com>
> ---
>  client/cifs.upcall.c |   62 ++++++++++++++++++++++++++++++++-----------------
>  1 files changed, 40 insertions(+), 22 deletions(-)
> 

Pushed to samba master branch (along with a corresponding manpage update).
simo Aug. 26, 2009, 12:02 p.m. UTC | #2
On Wed, 2009-08-26 at 06:29 -0400, Jeff Layton wrote:
> On Wed, 19 Aug 2009 13:30:37 -0400
> Jeff Layton <jlayton@redhat.com> wrote:
> 
> > Igor Mammedov pointed out that reverse resolving an IP address to get
> > the hostname portion of a principal could open a possible attack
> > vector. If an attacker were to gain control of DNS, then he could
> > redirect the mount to a server of his choosing, and fix the reverse
> > resolution to point to a hostname of his choosing (one where he has
> > the key for the corresponding cifs/ or host/ principal).
> > 
> > That said, we often trust DNS for other reasons and it can be useful
> > to do so. Make the code that allows trusting DNS to be enabled by
> > adding --trust-dns to the cifs.upcall invocation.
> > 
> > Signed-off-by: Jeff Layton <jlayton@redhat.com>
> > ---
> >  client/cifs.upcall.c |   62 ++++++++++++++++++++++++++++++++-----------------
> >  1 files changed, 40 insertions(+), 22 deletions(-)
> > 
> 
> Pushed to samba master branch (along with a corresponding manpage update).

We discussed this a few times in the past, I have no objections to the
patch, I am only wondering if the default shouldn't be reversed and make
only paranoid people disable it ?

Simo.
Jeff Layton Aug. 26, 2009, 12:35 p.m. UTC | #3
On Wed, 26 Aug 2009 08:02:59 -0400
simo <idra@samba.org> wrote:

> On Wed, 2009-08-26 at 06:29 -0400, Jeff Layton wrote:
> > On Wed, 19 Aug 2009 13:30:37 -0400
> > Jeff Layton <jlayton@redhat.com> wrote:
> > 
> > > Igor Mammedov pointed out that reverse resolving an IP address to get
> > > the hostname portion of a principal could open a possible attack
> > > vector. If an attacker were to gain control of DNS, then he could
> > > redirect the mount to a server of his choosing, and fix the reverse
> > > resolution to point to a hostname of his choosing (one where he has
> > > the key for the corresponding cifs/ or host/ principal).
> > > 
> > > That said, we often trust DNS for other reasons and it can be useful
> > > to do so. Make the code that allows trusting DNS to be enabled by
> > > adding --trust-dns to the cifs.upcall invocation.
> > > 
> > > Signed-off-by: Jeff Layton <jlayton@redhat.com>
> > > ---
> > >  client/cifs.upcall.c |   62 ++++++++++++++++++++++++++++++++-----------------
> > >  1 files changed, 40 insertions(+), 22 deletions(-)
> > > 
> > 
> > Pushed to samba master branch (along with a corresponding manpage update).
> 
> We discussed this a few times in the past, I have no objections to the
> patch, I am only wondering if the default shouldn't be reversed and make
> only paranoid people disable it ?
> 

*shrug*

The attack vector is a little contrived, but it is valid. When in
doubt, it's probably best to make the safest option the default and
require a conscious step to lower security.
diff mbox

Patch

diff --git a/client/cifs.upcall.c b/client/cifs.upcall.c
index f06d563..1645322 100644
--- a/client/cifs.upcall.c
+++ b/client/cifs.upcall.c
@@ -154,9 +154,9 @@  handle_krb5_mech(const char *oid, const char *principal, DATA_BLOB *secblob,
 #define DKD_HAVE_IP		0x8
 #define DKD_HAVE_UID		0x10
 #define DKD_HAVE_PID		0x20
-#define DKD_MUSTHAVE_SET (DKD_HAVE_IP|DKD_HAVE_VERSION|DKD_HAVE_SEC)
+#define DKD_MUSTHAVE_SET (DKD_HAVE_HOSTNAME|DKD_HAVE_VERSION|DKD_HAVE_SEC)
 
-static struct decoded_args {
+struct decoded_args {
 	int		ver;
 	char		*hostname;
 	char		*ip;
@@ -354,11 +354,12 @@  ip_to_fqdn(const char *addrstr, char *host, size_t hostlen)
 static void
 usage(void)
 {
-	syslog(LOG_INFO, "Usage: %s [-v] key_serial", prog);
-	fprintf(stderr, "Usage: %s [-v] key_serial\n", prog);
+	syslog(LOG_INFO, "Usage: %s [-t] [-v] key_serial", prog);
+	fprintf(stderr, "Usage: %s [-t] [-v] key_serial\n", prog);
 }
 
 const struct option long_options[] = {
+	{ "trust-dns",	0, NULL, 't' },
 	{ "version",	0, NULL, 'v' },
 	{ NULL,		0, NULL, 0 }
 };
@@ -372,19 +373,24 @@  int main(const int argc, char *const argv[])
 	size_t datalen;
 	unsigned int have;
 	long rc = 1;
-	int c;
-	char *buf, *princ, *ccname = NULL;
-	char hostbuf[NI_MAXHOST];
+	int c, try_dns = 0;
+	char *buf, *princ = NULL, *ccname = NULL;
+	char hostbuf[NI_MAXHOST], *host;
 	struct decoded_args arg = { };
 	const char *oid;
 
+	hostbuf[0] = '\0';
+
 	openlog(prog, 0, LOG_DAEMON);
 
-	while ((c = getopt_long(argc, argv, "cv", long_options, NULL)) != -1) {
+	while ((c = getopt_long(argc, argv, "ctv", long_options, NULL)) != -1) {
 		switch (c) {
 		case 'c':
 			/* legacy option -- skip it */
 			break;
+		case 't':
+			try_dns++;
+			break;
 		case 'v':
 			printf("version: %s\n", CIFSSPNEGO_VERSION);
 			goto out;
@@ -452,21 +458,18 @@  int main(const int argc, char *const argv[])
 	if (have & DKD_HAVE_PID)
 		ccname = get_krb5_ccname(arg.pid);
 
-	if (have & DKD_HAVE_IP) {
-		rc = ip_to_fqdn(arg.ip, hostbuf, sizeof(hostbuf));
-		if (rc)
-			goto out;
-	}
+	host = arg.hostname;
 
 	// do mech specific authorization
 	switch (arg.sec) {
 	case MS_KRB5:
 	case KRB5:
+retry_new_hostname:
 		/* for "cifs/" service name + terminating 0 */
-		datalen = strnlen(hostbuf, sizeof(hostbuf)) + 5 + 1;
+		datalen = strlen(host) + 5 + 1;
 		princ = SMB_XMALLOC_ARRAY(char, datalen);
 		if (!princ) {
-			rc = 1;
+			rc = -ENOMEM;
 			break;
 		}
 
@@ -480,21 +483,35 @@  int main(const int argc, char *const argv[])
 		 * getting a host/ principal if that doesn't work.
 		 */
 		strlcpy(princ, "cifs/", datalen);
-		strlcpy(princ + 5, hostbuf, datalen - 5);
+		strlcpy(princ + 5, host, datalen - 5);
 		rc = handle_krb5_mech(oid, princ, &secblob, &sess_key, ccname);
-		if (rc) {
-			memcpy(princ, "host/", 5);
-			rc = handle_krb5_mech(oid, princ, &secblob, &sess_key,
-						ccname);
-		}
+		if (!rc)
+			break;
+
+		memcpy(princ, "host/", 5);
+		rc = handle_krb5_mech(oid, princ, &secblob, &sess_key, ccname);
+		if (!rc)
+			break;
+
+		if (!try_dns || !(have & DKD_HAVE_IP))
+			break;
+
+		rc = ip_to_fqdn(arg.ip, hostbuf, sizeof(hostbuf));
+		if (rc)
+			break;
+
 		SAFE_FREE(princ);
-		break;
+		try_dns = 0;
+		host = hostbuf;
+		goto retry_new_hostname;
 	default:
 		syslog(LOG_ERR, "sectype: %d is not implemented", arg.sec);
 		rc = 1;
 		break;
 	}
 
+	SAFE_FREE(princ);
+
 	if (rc)
 		goto out;
 
@@ -536,6 +553,7 @@  out:
 	data_blob_free(&sess_key);
 	SAFE_FREE(ccname);
 	SAFE_FREE(arg.hostname);
+	SAFE_FREE(arg.ip);
 	SAFE_FREE(keydata);
 	return rc;
 }