[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha8-994-g19553e1

Jeff Layton jlayton at samba.org
Fri Aug 14 06:03:01 MDT 2009


The branch, master has been updated
       via  19553e1552a57d5b0a9f3514bf64d2580b76a377 (commit)
       via  2f95ccc1e2c7fe8efd341cd6fc5adc402a7a0a18 (commit)
       via  acbf026012af1c87b680b8d80ea9e4123e24b91a (commit)
       via  b10bdef4e75ffe48d563b2f0825b82519a71c9a7 (commit)
       via  750ceb82390bd490bfd0431d52cd83b11201d548 (commit)
       via  685fdc33d705b0d5cbb43f16cdcb2dccd85a652e (commit)
       via  378a2d9aa5e538144083ff53578af6105cd296c9 (commit)
      from  168a7cb6a893fb56ef9fe7a4dc99bbc117a75962 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 19553e1552a57d5b0a9f3514bf64d2580b76a377
Author: Jeff Layton <jlayton at redhat.com>
Date:   Fri Aug 14 07:59:51 2009 -0400

    cifs.upcall: fix IPv6 addrs sent to upcall to have colon delimiters
    
    Current kernels don't send IPv6 addresses with the colon delimiters, add
    a routine to add them when they're not present.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit 2f95ccc1e2c7fe8efd341cd6fc5adc402a7a0a18
Author: Jeff Layton <jlayton at redhat.com>
Date:   Fri Aug 14 07:59:50 2009 -0400

    cifs.upcall: use ip address passed by kernel to get server's hostname
    
    Instead of using the hostname given by the upcall to get the server's
    principal, take the IP address given in the upcall and reverse resolve
    it to a hostname.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit acbf026012af1c87b680b8d80ea9e4123e24b91a
Author: Jeff Layton <jlayton at redhat.com>
Date:   Fri Aug 14 07:59:50 2009 -0400

    cifs.upcall: clean up flag handling
    
    Add a new stack var to hold the flags returned by the decoder routine
    so that we don't need to worry so much about preserving "rc".
    
    With this, we can drop privs before trying to find the location of
    the credcache.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit b10bdef4e75ffe48d563b2f0825b82519a71c9a7
Author: Jeff Layton <jlayton at redhat.com>
Date:   Fri Aug 14 07:59:50 2009 -0400

    cifs.upcall: try getting a "cifs/" principal and fall back to "host/"
    
    cifs.upcall takes a "-c" flag that tells the upcall to get a principal
    in the form of "cifs/hostname.example.com at REALM" instead of
    "host/hostname.example.com at REALM". This has turned out to be a source of
    great confusion for users.
    
    Instead of requiring this flag, have the upcall try to get a "cifs/"
    principal first. If that fails, fall back to getting a "host/"
    principal.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit 750ceb82390bd490bfd0431d52cd83b11201d548
Author: Jeff Layton <jlayton at redhat.com>
Date:   Fri Aug 14 07:59:49 2009 -0400

    cifs.upcall: declare a structure for holding decoded args
    
    The argument list for the decoder is becoming rather long. Declare an
    args structure and use that for holding the args. This also simplifies
    pointer handling a bit.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit 685fdc33d705b0d5cbb43f16cdcb2dccd85a652e
Author: Jeff Layton <jlayton at redhat.com>
Date:   Fri Aug 14 07:59:49 2009 -0400

    cifs.upcall: formatting cleanup
    
    Clean up some unneeded curly braces, and fix some indentation.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit 378a2d9aa5e538144083ff53578af6105cd296c9
Author: Jeff Layton <jlayton at redhat.com>
Date:   Fri Aug 14 07:59:49 2009 -0400

    cifs.upcall: clean up logging and add debug messages
    
    Change the log levels to be more appropriate to the messages being
    logged. Error messages should be LOG_ERR and not LOG_WARNING, for
    instance.
    
    Add some LOG_DEBUG messages that we can use to diagnose problems with
    krb5 upcalls. With these, someone can set up syslog to log daemon.debug
    and should be able to get more info when things aren't working.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

-----------------------------------------------------------------------

Summary of changes:
 client/cifs.upcall.c                  |  321 +++++++++++++++++++++------------
 docs-xml/manpages-3/cifs.upcall.8.xml |    4 +-
 2 files changed, 203 insertions(+), 122 deletions(-)


Changeset truncated at 500 lines:

diff --git a/client/cifs.upcall.c b/client/cifs.upcall.c
index 82b9f7b..c89df9c 100644
--- a/client/cifs.upcall.c
+++ b/client/cifs.upcall.c
@@ -30,13 +30,13 @@ create dns_resolver * * /usr/local/sbin/cifs.upcall %k
 
 #include "cifs_spnego.h"
 
-const char *CIFSSPNEGO_VERSION = "1.2";
+const char *CIFSSPNEGO_VERSION = "1.3";
 static const char *prog = "cifs.upcall";
-typedef enum _secType {
+typedef enum _sectype {
 	NONE = 0,
 	KRB5,
 	MS_KRB5
-} secType_t;
+} sectype_t;
 
 /*
  * given a process ID, get the value of the KRB5CCNAME environment variable
@@ -58,14 +58,20 @@ get_krb5_ccname(pid_t pid)
 	buf[4095] = '\0';
 	snprintf(buf, 4095, "/proc/%d/environ", pid);
 	fd = open(buf, O_RDONLY);
-	if (fd < 0)
+	if (fd < 0) {
+		syslog(LOG_DEBUG, "%s: unable to open %s: %d", __func__, buf,
+			errno);
 		return NULL;
+	}
 
 	/* FIXME: don't assume that we get it all in the first read? */
 	len = read(fd, buf, 4096);
 	close(fd);
-	if (len < 0)
+	if (len < 0) {
+		syslog(LOG_DEBUG, "%s: unable to read from /proc/%d/environ: "
+				  "%d", __func__, pid, errno);
 		return NULL;
+	}
 
 	left = len;
 	p = buf;
@@ -83,6 +89,8 @@ get_krb5_ccname(pid_t pid)
 		value = SMB_STRNDUP(p, left);
 		break;
 	}
+	syslog(LOG_DEBUG, "%s: KRB5CCNAME=%s", __func__,
+				value ? value : "(null)");
 	return value;
 }
 
@@ -105,7 +113,7 @@ get_krb5_ccname(pid_t pid)
  * 	sess_key-	pointer for SessionKey data to be stored
  *
  * ret: 0 - success, others - failure
-*/
+ */
 static int
 handle_krb5_mech(const char *oid, const char *principal, DATA_BLOB *secblob,
 		 DATA_BLOB *sess_key, const char *ccname)
@@ -113,12 +121,20 @@ handle_krb5_mech(const char *oid, const char *principal, DATA_BLOB *secblob,
 	int retval;
 	DATA_BLOB tkt, tkt_wrapped;
 
+	syslog(LOG_DEBUG, "%s: getting service ticket for %s", __func__,
+			  principal);
+
 	/* get a kerberos ticket for the service and extract the session key */
 	retval = cli_krb5_get_ticket(principal, 0, &tkt, sess_key, 0, ccname,
 				     NULL);
 
-	if (retval)
+	if (retval) {
+		syslog(LOG_DEBUG, "%s: failed to obtain service ticket (%d)",
+				  __func__, retval);
 		return retval;
+	}
+
+	syslog(LOG_DEBUG, "%s: obtained service ticket", __func__);
 
 	/* wrap that up in a nice GSS-API wrapping */
 	tkt_wrapped = spnego_gen_krb5_wrap(tkt, TOK_ID_KRB_AP_REQ);
@@ -131,19 +147,27 @@ handle_krb5_mech(const char *oid, const char *principal, DATA_BLOB *secblob,
 	return retval;
 }
 
-#define DKD_HAVE_HOSTNAME	1
-#define DKD_HAVE_VERSION	2
-#define DKD_HAVE_SEC		4
-#define DKD_HAVE_IPV4		8
-#define DKD_HAVE_IPV6		16
-#define DKD_HAVE_UID		32
-#define DKD_HAVE_PID		64
-#define DKD_MUSTHAVE_SET (DKD_HAVE_HOSTNAME|DKD_HAVE_VERSION|DKD_HAVE_SEC)
-
-static int
-decode_key_description(const char *desc, int *ver, secType_t *sec,
-			   char **hostname, uid_t *uid, pid_t *pid)
+#define DKD_HAVE_HOSTNAME	0x1
+#define DKD_HAVE_VERSION	0x2
+#define DKD_HAVE_SEC		0x4
+#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)
+
+static struct decoded_args {
+	int		ver;
+	char		*hostname;
+	char		*ip;
+	uid_t		uid;
+	pid_t		pid;
+	sectype_t	sec;
+};
+
+static unsigned int
+decode_key_description(const char *desc, struct decoded_args *arg)
 {
+	int len;
 	int retval = 0;
 	char *pos;
 	const char *tkn = desc;
@@ -151,27 +175,34 @@ decode_key_description(const char *desc, int *ver, secType_t *sec,
 	do {
 		pos = index(tkn, ';');
 		if (strncmp(tkn, "host=", 5) == 0) {
-			int len;
 
-			if (pos == NULL) {
+			if (pos == NULL)
 				len = strlen(tkn);
-			} else {
+			else
 				len = pos - tkn;
-			}
+
 			len -= 4;
-			SAFE_FREE(*hostname);
-			*hostname = SMB_XMALLOC_ARRAY(char, len);
-			strlcpy(*hostname, tkn + 5, len);
+			SAFE_FREE(arg->hostname);
+			arg->hostname = SMB_XMALLOC_ARRAY(char, len);
+			strlcpy(arg->hostname, tkn + 5, len);
 			retval |= DKD_HAVE_HOSTNAME;
-		} else if (strncmp(tkn, "ipv4=", 5) == 0) {
-			/* BB: do we need it if we have hostname already? */
-		} else if (strncmp(tkn, "ipv6=", 5) == 0) {
-			/* BB: do we need it if we have hostname already? */
+		} else if (!strncmp(tkn, "ip4=", 4) ||
+			   !strncmp(tkn, "ip6=", 4)) {
+			if (pos == NULL)
+				len = strlen(tkn);
+			else
+				len = pos - tkn;
+
+			len -= 3;
+			SAFE_FREE(arg->ip);
+			arg->ip = SMB_XMALLOC_ARRAY(char, len);
+			strlcpy(arg->ip, tkn + 4, len);
+			retval |= DKD_HAVE_IP;
 		} else if (strncmp(tkn, "pid=", 4) == 0) {
 			errno = 0;
-			*pid = strtol(tkn + 4, NULL, 0);
+			arg->pid = strtol(tkn + 4, NULL, 0);
 			if (errno != 0) {
-				syslog(LOG_WARNING, "Invalid pid format: %s",
+				syslog(LOG_ERR, "Invalid pid format: %s",
 				       strerror(errno));
 				return 1;
 			} else {
@@ -180,16 +211,16 @@ decode_key_description(const char *desc, int *ver, secType_t *sec,
 		} else if (strncmp(tkn, "sec=", 4) == 0) {
 			if (strncmp(tkn + 4, "krb5", 4) == 0) {
 				retval |= DKD_HAVE_SEC;
-				*sec = KRB5;
+				arg->sec = KRB5;
 			} else if (strncmp(tkn + 4, "mskrb5", 6) == 0) {
 				retval |= DKD_HAVE_SEC;
-				*sec = MS_KRB5;
+				arg->sec = MS_KRB5;
 			}
 		} else if (strncmp(tkn, "uid=", 4) == 0) {
 			errno = 0;
-			*uid = strtol(tkn + 4, NULL, 16);
+			arg->uid = strtol(tkn + 4, NULL, 16);
 			if (errno != 0) {
-				syslog(LOG_WARNING, "Invalid uid format: %s",
+				syslog(LOG_ERR, "Invalid uid format: %s",
 				       strerror(errno));
 				return 1;
 			} else {
@@ -197,10 +228,9 @@ decode_key_description(const char *desc, int *ver, secType_t *sec,
 			}
 		} else if (strncmp(tkn, "ver=", 4) == 0) {	/* if version */
 			errno = 0;
-			*ver = strtol(tkn + 4, NULL, 16);
+			arg->ver = strtol(tkn + 4, NULL, 16);
 			if (errno != 0) {
-				syslog(LOG_WARNING,
-				       "Invalid version format: %s",
+				syslog(LOG_ERR, "Invalid version format: %s",
 				       strerror(errno));
 				return 1;
 			} else {
@@ -226,7 +256,7 @@ cifs_resolver(const key_serial_t key, const char *key_descr)
 	for (c = 1; c <= 4; c++) {
 		keyend = index(keyend+1, ';');
 		if (!keyend) {
-			syslog(LOG_WARNING, "invalid key description: %s",
+			syslog(LOG_ERR, "invalid key description: %s",
 					key_descr);
 			return 1;
 		}
@@ -236,20 +266,19 @@ cifs_resolver(const key_serial_t key, const char *key_descr)
 	/* resolve name to ip */
 	c = getaddrinfo(keyend, NULL, NULL, &addr);
 	if (c) {
-		syslog(LOG_WARNING, "unable to resolve hostname: %s [%s]",
+		syslog(LOG_ERR, "unable to resolve hostname: %s [%s]",
 				keyend, gai_strerror(c));
 		return 1;
 	}
 
 	/* conver ip to string form */
-	if (addr->ai_family == AF_INET) {
+	if (addr->ai_family == AF_INET)
 		p = &(((struct sockaddr_in *)addr->ai_addr)->sin_addr);
-	} else {
+	else
 		p = &(((struct sockaddr_in6 *)addr->ai_addr)->sin6_addr);
-	}
+
 	if (!inet_ntop(addr->ai_family, p, ip, sizeof(ip))) {
-		syslog(LOG_WARNING, "%s: inet_ntop: %s",
-				__FUNCTION__, strerror(errno));
+		syslog(LOG_ERR, "%s: inet_ntop: %s", __func__, strerror(errno));
 		freeaddrinfo(addr);
 		return 1;
 	}
@@ -257,8 +286,8 @@ cifs_resolver(const key_serial_t key, const char *key_descr)
 	/* setup key */
 	c = keyctl_instantiate(key, ip, strlen(ip)+1, 0);
 	if (c == -1) {
-		syslog(LOG_WARNING, "%s: keyctl_instantiate: %s",
-				__FUNCTION__, strerror(errno));
+		syslog(LOG_ERR, "%s: keyctl_instantiate: %s", __func__,
+				strerror(errno));
 		freeaddrinfo(addr);
 		return 1;
 	}
@@ -267,11 +296,65 @@ cifs_resolver(const key_serial_t key, const char *key_descr)
 	return 0;
 }
 
+/*
+ * Older kernels sent IPv6 addresses without colons. Well, at least
+ * they're fixed-length strings. Convert these addresses to have colon
+ * delimiters to make getaddrinfo happy.
+ */
+static void
+convert_inet6_addr(const char *from, char *to)
+{
+	int i = 1;
+
+	while (*from) {
+		*to++ = *from++;
+		if (!(i++ % 4) && *from)
+			*to++ = ':';
+	}
+	*to = 0;
+}
+
+static int
+ip_to_fqdn(const char *addrstr, char *host, size_t hostlen)
+{
+	int rc;
+	struct addrinfo hints = { .ai_flags = AI_NUMERICHOST };
+	struct addrinfo *res;
+	const char *ipaddr = addrstr;
+	char converted[INET6_ADDRSTRLEN + 1];
+
+	if ((strlen(ipaddr) > INET_ADDRSTRLEN) && !strchr(ipaddr, ':')) {
+		convert_inet6_addr(ipaddr, converted);
+		ipaddr = converted;
+	}
+
+	rc = getaddrinfo(ipaddr, NULL, &hints, &res);
+	if (rc) {
+		syslog(LOG_DEBUG, "%s: failed to resolve %s to "
+			"ipaddr: %s", __func__, ipaddr,
+		rc == EAI_SYSTEM ? strerror(errno) : gai_strerror(rc));
+		return rc;
+	}
+
+	rc = getnameinfo(res->ai_addr, res->ai_addrlen, host, hostlen,
+			 NULL, 0, NI_NAMEREQD);
+	freeaddrinfo(res);
+	if (rc) {
+		syslog(LOG_DEBUG, "%s: failed to resolve %s to fqdn: %s",
+			__func__, ipaddr,
+			rc == EAI_SYSTEM ? strerror(errno) : gai_strerror(rc));
+		return rc;
+	}
+
+	syslog(LOG_DEBUG, "%s: resolved %s to %s", __func__, ipaddr, host);
+	return 0;
+}
+
 static void
 usage(void)
 {
-	syslog(LOG_WARNING, "Usage: %s [-c] [-v] key_serial", prog);
-	fprintf(stderr, "Usage: %s [-c] [-v] key_serial\n", prog);
+	syslog(LOG_INFO, "Usage: %s [-v] key_serial", prog);
+	fprintf(stderr, "Usage: %s [-v] key_serial\n", prog);
 }
 
 int main(const int argc, char *const argv[])
@@ -279,33 +362,29 @@ int main(const int argc, char *const argv[])
 	struct cifs_spnego_msg *keydata = NULL;
 	DATA_BLOB secblob = data_blob_null;
 	DATA_BLOB sess_key = data_blob_null;
-	secType_t sectype = NONE;
 	key_serial_t key = 0;
 	size_t datalen;
+	unsigned int have;
 	long rc = 1;
-	uid_t uid = 0;
-	pid_t pid = 0;
-	int kernel_upcall_version = 0;
-	int c, use_cifs_service_prefix = 0;
-	char *buf, *ccname = NULL, *hostname = NULL;
+	int c;
+	char *buf, *princ, *ccname = NULL;
+	char hostbuf[NI_MAXHOST];
+	struct decoded_args arg = { };
 	const char *oid;
 
 	openlog(prog, 0, LOG_DAEMON);
 
 	while ((c = getopt(argc, argv, "cv")) != -1) {
 		switch (c) {
-		case 'c':{
-			use_cifs_service_prefix = 1;
+		case 'c':
+			/* legacy option -- skip it */
 			break;
-			}
-		case 'v':{
+		case 'v':
 			printf("version: %s\n", CIFSSPNEGO_VERSION);
 			goto out;
-			}
-		default:{
-			syslog(LOG_WARNING, "unknown option: %c", c);
+		default:
+			syslog(LOG_ERR, "unknown option: %c", c);
 			goto out;
-			}
 		}
 	}
 
@@ -320,96 +399,98 @@ int main(const int argc, char *const argv[])
 	key = strtol(argv[optind], NULL, 10);
 	if (errno != 0) {
 		key = 0;
-		syslog(LOG_WARNING, "Invalid key format: %s", strerror(errno));
+		syslog(LOG_ERR, "Invalid key format: %s", strerror(errno));
 		goto out;
 	}
 
 	rc = keyctl_describe_alloc(key, &buf);
 	if (rc == -1) {
-		syslog(LOG_WARNING, "keyctl_describe_alloc failed: %s",
+		syslog(LOG_ERR, "keyctl_describe_alloc failed: %s",
 		       strerror(errno));
 		rc = 1;
 		goto out;
 	}
 
+	syslog(LOG_DEBUG, "key description: %s", buf);
+
 	if ((strncmp(buf, "cifs.resolver", sizeof("cifs.resolver")-1) == 0) ||
 	    (strncmp(buf, "dns_resolver", sizeof("dns_resolver")-1) == 0)) {
 		rc = cifs_resolver(key, buf);
 		goto out;
 	}
 
-	rc = decode_key_description(buf, &kernel_upcall_version, &sectype,
-				    &hostname, &uid, &pid);
-	if ((rc & DKD_MUSTHAVE_SET) != DKD_MUSTHAVE_SET) {
-		syslog(LOG_WARNING,
-		       "unable to get from description necessary params");
+	have = decode_key_description(buf, &arg);
+	SAFE_FREE(buf);
+	if ((have & DKD_MUSTHAVE_SET) != DKD_MUSTHAVE_SET) {
+		syslog(LOG_ERR, "unable to get necessary params from key "
+				"description (0x%x)", have);
 		rc = 1;
-		SAFE_FREE(buf);
 		goto out;
 	}
-	SAFE_FREE(buf);
 
-	if (kernel_upcall_version > CIFS_SPNEGO_UPCALL_VERSION) {
-		syslog(LOG_WARNING,
-		       "incompatible kernel upcall version: 0x%x",
-		       kernel_upcall_version);
+	if (arg.ver > CIFS_SPNEGO_UPCALL_VERSION) {
+		syslog(LOG_ERR, "incompatible kernel upcall version: 0x%x",
+				arg.ver);
 		rc = 1;
 		goto out;
 	}
 
-	if (rc & DKD_HAVE_PID)
-		ccname = get_krb5_ccname(pid);
-
-	if (rc & DKD_HAVE_UID) {
-		rc = setuid(uid);
+	if (have & DKD_HAVE_UID) {
+		rc = setuid(arg.uid);
 		if (rc == -1) {
-			syslog(LOG_WARNING, "setuid: %s", strerror(errno));
+			syslog(LOG_ERR, "setuid: %s", strerror(errno));
 			goto out;
 		}
 	}
 
-	// do mech specific authorization
-	switch (sectype) {
-	case MS_KRB5:
-	case KRB5:{
-			char *princ;
-			size_t len;
-
-			/* for "cifs/" service name + terminating 0 */
-			len = strlen(hostname) + 5 + 1;
-			princ = SMB_XMALLOC_ARRAY(char, len);
-			if (!princ) {
-				rc = 1;
-				break;
-			}
-			if (use_cifs_service_prefix) {
-				strlcpy(princ, "cifs/", len);
-			} else {
-				strlcpy(princ, "host/", len);
-			}
-			strlcpy(princ + 5, hostname, len - 5);
+	if (have & DKD_HAVE_PID)
+		ccname = get_krb5_ccname(arg.pid);
 
-			if (sectype == MS_KRB5)
-				oid = OID_KERBEROS5_OLD;
-			else
-				oid = OID_KERBEROS5;
+	if (have & DKD_HAVE_IP) {
+		rc = ip_to_fqdn(arg.ip, hostbuf, sizeof(hostbuf));
+		if (rc)
+			goto out;
+	}
 
-			rc = handle_krb5_mech(oid, princ, &secblob, &sess_key,
-					      ccname);
-			SAFE_FREE(princ);
-			break;
-		}
-	default:{
-			syslog(LOG_WARNING, "sectype: %d is not implemented",
-			       sectype);
+	// do mech specific authorization
+	switch (arg.sec) {
+	case MS_KRB5:
+	case KRB5:
+		/* for "cifs/" service name + terminating 0 */
+		datalen = strnlen(hostbuf, sizeof(hostbuf)) + 5 + 1;
+		princ = SMB_XMALLOC_ARRAY(char, datalen);
+		if (!princ) {
 			rc = 1;
 			break;
 		}
+
+		if (arg.sec == MS_KRB5)
+			oid = OID_KERBEROS5_OLD;
+		else
+			oid = OID_KERBEROS5;
+
+		/*
+		 * try getting a cifs/ principal first and then fall back to
+		 * getting a host/ principal if that doesn't work.
+		 */
+		strlcpy(princ, "cifs/", datalen);
+		strlcpy(princ + 5, hostbuf, 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);


-- 
Samba Shared Repository


More information about the samba-cvs mailing list