[SCM] Samba Shared Repository - branch v3-5-test updated - release-4-0-0alpha8-1385-gfb6a4f4

Jeremy Allison jra at samba.org
Mon Sep 7 10:33:56 MDT 2009


The branch, v3-5-test has been updated
       via  fb6a4f4eb16980aaf483207fd4f625f4d5116f86 (commit)
       via  6add49530e248c4396de159daf482ca6d13d0102 (commit)
       via  f8e300a458ac18c84013ebd067ee4663f4ce8b9c (commit)
       via  2a758612bd949ed5884e115e3d7446cf0a0a096f (commit)
       via  4d66ed585116556dc2eadc0b8340972124400e56 (commit)
      from  b01a7fce838329fa751dda34eaa5c49b2985f065 (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-5-test


- Log -----------------------------------------------------------------
commit fb6a4f4eb16980aaf483207fd4f625f4d5116f86
Author: Jeff Layton <jlayton at redhat.com>
Date:   Fri Sep 4 06:29:44 2009 -0400

    cifs.upcall: do a brute-force search for KRB5 credcache
    
    A few weeks ago, I added some code to cifs.upcall to take the pid sent
    by the kernel and use that to get the value of the $KRB5CCNAME
    environment var for the process. That works fine on the initial mount,
    but could be problematic on reconnect.
    
    There's no guarantee on a reconnect that the process that initiates the
    upcall will have $KRB5CCNAME pointed at the correct credcache. Because
    of this, the current scheme isn't going to be reliable enough and we
    need to use something different.
    
    This patch replaces that scheme with one very similar to the one used by
    rpc.gssd in nfs-utils. It searches the credcache dir (currently
    hardcoded to /tmp) for a valid credcache for the given uid. If it finds
    one then it uses that as the credentials cache. If it finds more than
    one, it uses the one with the latest TGT expiration.
    
    Signed-off-by: Jeff Layton <jlayton at redhat.com>

commit 6add49530e248c4396de159daf482ca6d13d0102
Author: Volker Lendecke <vl at samba.org>
Date:   Sat Sep 5 17:14:45 2009 +0200

    s3:winbind: Use fstr_sprintf, it is simpler than talloc_asprintf->fstrcpy

commit f8e300a458ac18c84013ebd067ee4663f4ce8b9c
Author: Volker Lendecke <vl at samba.org>
Date:   Sat Sep 5 17:05:30 2009 +0200

    s3:winbind: Remove pointless <cond> ? true : false;

commit 2a758612bd949ed5884e115e3d7446cf0a0a096f
Author: Volker Lendecke <vl at samba.org>
Date:   Sat Sep 5 17:00:21 2009 +0200

    s3:winbind: Make the pam_auth subfunctions static

commit 4d66ed585116556dc2eadc0b8340972124400e56
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Sep 3 08:02:21 2009 +0200

    s3:libsmb: Convert (state->received) to (state->received != 0)
    
    This confused me for a second, this should not happen a second time :-)

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

Summary of changes:
 client/cifs.upcall.c              |  186 +++++++++++++++++++++++++++---------
 source3/libsmb/clireadwrite.c     |    2 +-
 source3/winbindd/winbindd_pam.c   |   39 ++++----
 source3/winbindd/winbindd_proto.h |    9 --
 4 files changed, 158 insertions(+), 78 deletions(-)


Changeset truncated at 500 lines:

diff --git a/client/cifs.upcall.c b/client/cifs.upcall.c
index 1645322..71e60c6 100644
--- a/client/cifs.upcall.c
+++ b/client/cifs.upcall.c
@@ -31,6 +31,11 @@ create dns_resolver * * /usr/local/sbin/cifs.upcall %k
 
 #include "cifs_spnego.h"
 
+#define	CIFS_DEFAULT_KRB5_DIR		"/tmp"
+#define	CIFS_DEFAULT_KRB5_PREFIX	"krb5cc_"
+
+#define	MAX_CCNAME_LEN			PATH_MAX + 5
+
 const char *CIFSSPNEGO_VERSION = "1.3";
 static const char *prog = "cifs.upcall";
 typedef enum _sectype {
@@ -39,60 +44,148 @@ typedef enum _sectype {
 	MS_KRB5
 } sectype_t;
 
-/*
- * given a process ID, get the value of the KRB5CCNAME environment variable
- * in the context of that process. On error, just return NULL.
- */
-static char *
-get_krb5_ccname(pid_t pid)
+static inline int
+k5_data_equal(krb5_data d1, krb5_data d2, unsigned int length)
 {
-	int fd;
-	ssize_t len, left;
+	if (!length)
+		length = d1.length;
 
-	/*
-	 * FIXME: sysconf for ARG_MAX instead? Kernel seems to be limited to a
-	 * page however, so it may not matter.
-	 */
-	char buf[4096];
-	char *p, *value = NULL;
-	
-	buf[4095] = '\0';
-	snprintf(buf, 4095, "/proc/%d/environ", pid);
-	fd = open(buf, O_RDONLY);
-	if (fd < 0) {
-		syslog(LOG_DEBUG, "%s: unable to open %s: %d", __func__, buf,
-			errno);
-		return NULL;
+	return (d1.length == length &&
+		d1.length == d2.length &&
+		memcmp(d1.data, d2.data, length) == 0);
+
+}
+
+/* does the ccache have a valid TGT? */
+static time_t
+get_tgt_time(const char *ccname) {
+	krb5_context context;
+	krb5_ccache ccache;
+	krb5_cc_cursor cur;
+	krb5_creds creds;
+	krb5_principal principal;
+	krb5_data tgt = { .data =	"krbtgt",
+			  .length =	6 };
+	time_t credtime = 0;
+
+	if (krb5_init_context(&context)) {
+		syslog(LOG_DEBUG, "%s: unable to init krb5 context", __func__);
+		return 0;
 	}
 
-	/* FIXME: don't assume that we get it all in the first read? */
-	len = read(fd, buf, 4096);
-	close(fd);
-	if (len < 0) {
-		syslog(LOG_DEBUG, "%s: unable to read from /proc/%d/environ: "
-				  "%d", __func__, pid, errno);
+	if (krb5_cc_resolve(context, ccname, &ccache)) {
+		syslog(LOG_DEBUG, "%s: unable to resolve krb5 cache", __func__);
+		goto err_cache;
+	}
+
+	if (krb5_cc_set_flags(context, ccache, 0)) {
+		syslog(LOG_DEBUG, "%s: unable to set flags", __func__);
+		goto err_cache;
+	}
+
+	if (krb5_cc_get_principal(context, ccache, &principal)) {
+		syslog(LOG_DEBUG, "%s: unable to get principal", __func__);
+		goto err_princ;
+	}
+
+	if (krb5_cc_start_seq_get(context, ccache, &cur)) {
+		syslog(LOG_DEBUG, "%s: unable to seq start", __func__);
+		goto err_ccstart;
+	}
+
+	while (!credtime && !krb5_cc_next_cred(context, ccache, &cur, &creds)) {
+		if (k5_data_equal(creds.server->realm, principal->realm, 0) &&
+		    k5_data_equal(creds.server->data[0], tgt, tgt.length) &&
+		    k5_data_equal(creds.server->data[1], principal->realm, 0) &&
+		    creds.times.endtime > time(NULL))
+			credtime = creds.times.endtime;
+                krb5_free_cred_contents(context, &creds);
+        }
+        krb5_cc_end_seq_get(context, ccache, &cur);
+
+err_ccstart:
+	krb5_free_principal(context, principal);
+err_princ:
+	krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
+	krb5_cc_close(context, ccache);
+err_cache:
+	krb5_free_context(context);
+	return credtime;
+}
+
+static int
+krb5cc_filter(const struct dirent *dirent)
+{
+	if (strstr(dirent->d_name, CIFS_DEFAULT_KRB5_PREFIX))
+		return 1;
+	else
+		return 0;
+}
+
+/* search for a credcache that looks like a likely candidate */
+static char *
+find_krb5_cc(const char *dirname, uid_t uid)
+{
+	struct dirent **namelist;
+	struct stat sbuf;
+	char ccname[MAX_CCNAME_LEN], *credpath, *best_cache = NULL;
+	int i, n;
+	time_t cred_time, best_time = 0;
+
+	n = scandir(dirname, &namelist, krb5cc_filter, NULL);
+	if (n < 0) {
+		syslog(LOG_DEBUG, "%s: scandir error on directory '%s': %s",
+				  __func__, dirname, strerror(errno));
 		return NULL;
 	}
 
-	left = len;
-	p = buf;
+	for (i = 0; i < n; i++) {
+		snprintf(ccname, sizeof(ccname), "FILE:%s/%s", dirname,
+			 namelist[i]->d_name);
+		credpath = ccname + 5;
+		syslog(LOG_DEBUG, "%s: considering %s", __func__, credpath);
 
-	/* can't have valid KRB5CCNAME if there are < 13 bytes left */
-	while (left > 12) {
-		if (strncmp("KRB5CCNAME=", p, 11)) {
-			p += strnlen(p, left);
-			++p;
-			left = buf + len - p;
+		if (lstat(credpath, &sbuf)) {
+			syslog(LOG_DEBUG, "%s: stat error on '%s': %s",
+					  __func__, credpath, strerror(errno));
+			free(namelist[i]);
 			continue;
 		}
-		p += 11;
-		left -= 11;
-		value = SMB_STRNDUP(p, left);
-		break;
+		if (sbuf.st_uid != uid) {
+			syslog(LOG_DEBUG, "%s: %s is owned by %u, not %u",
+					__func__, credpath, sbuf.st_uid, uid);
+			free(namelist[i]);
+			continue;
+		}
+		if (!S_ISREG(sbuf.st_mode)) {
+			syslog(LOG_DEBUG, "%s: %s is not a regular file",
+					__func__, credpath);
+			free(namelist[i]);
+			continue;
+		}
+		if (!(cred_time = get_tgt_time(ccname))) {
+			syslog(LOG_DEBUG, "%s: %s is not a valid credcache.",
+					__func__, ccname);
+			free(namelist[i]);
+			continue;
+		}
+
+		if (cred_time <= best_time) {
+			syslog(LOG_DEBUG, "%s: %s expires sooner than current "
+					  "best.", __func__, ccname);
+			free(namelist[i]);
+			continue;
+		}
+
+		syslog(LOG_DEBUG, "%s: %s is valid ccache", __func__, ccname);
+		free(best_cache);
+		best_cache = SMB_STRNDUP(ccname, MAX_CCNAME_LEN);
+		best_time = cred_time;
+		free(namelist[i]);
 	}
-	syslog(LOG_DEBUG, "%s: KRB5CCNAME=%s", __func__,
-				value ? value : "(null)");
-	return value;
+	free(namelist);
+
+	return best_cache;
 }
 
 /*
@@ -453,10 +546,9 @@ int main(const int argc, char *const argv[])
 			syslog(LOG_ERR, "setuid: %s", strerror(errno));
 			goto out;
 		}
-	}
 
-	if (have & DKD_HAVE_PID)
-		ccname = get_krb5_ccname(arg.pid);
+		ccname = find_krb5_cc(CIFS_DEFAULT_KRB5_DIR, arg.uid);
+	}
 
 	host = arg.hostname;
 
diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c
index 0d1f9e5..27f9e4f 100644
--- a/source3/libsmb/clireadwrite.c
+++ b/source3/libsmb/clireadwrite.c
@@ -200,7 +200,7 @@ static void cli_read_andx_done(struct tevent_req *subreq)
 	state->buf = (uint8_t *)smb_base(inbuf) + SVAL(vwv+6, 0);
 
 	if (trans_oob(smb_len(inbuf), SVAL(vwv+6, 0), state->received)
-	    || (state->received && (state->buf < bytes))) {
+	    || ((state->received != 0) && (state->buf < bytes))) {
 		DEBUG(5, ("server returned invalid read&x data offset\n"));
 		tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
 		return;
diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 5665792..b87d2a8 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -854,9 +854,9 @@ void winbindd_pam_auth(struct winbindd_cli_state *state)
 	request_error(state);
 }
 
-NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
-				       struct winbindd_cli_state *state,
-				       struct netr_SamInfo3 **info3)
+static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
+					      struct winbindd_cli_state *state,
+					      struct netr_SamInfo3 **info3)
 {
 	NTSTATUS result = NT_STATUS_LOGON_FAILURE;
 	uint16 max_allowed_bad_attempts;
@@ -925,12 +925,12 @@ NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
 		uchar salted_hash[NT_HASH_LEN];
 		E_md5hash(cached_salt, new_nt_pass, salted_hash);
 
-		password_good = (memcmp(cached_nt_pass, salted_hash, NT_HASH_LEN) == 0) ?
-			true : false;
+		password_good = (memcmp(cached_nt_pass, salted_hash,
+					NT_HASH_LEN) == 0);
 	} else {
 		/* Old cached cred - direct store of nt_hash (bad bad bad !). */
-		password_good = (memcmp(cached_nt_pass, new_nt_pass, NT_HASH_LEN) == 0) ?
-			true : false;
+		password_good = (memcmp(cached_nt_pass, new_nt_pass,
+					NT_HASH_LEN) == 0);
 	}
 
 	if (password_good) {
@@ -1110,9 +1110,9 @@ failed:
 	return NT_STATUS_LOGON_FAILURE;
 }
 
-NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
-					 struct winbindd_cli_state *state,
-					 struct netr_SamInfo3 **info3)
+static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
+						struct winbindd_cli_state *state,
+						struct netr_SamInfo3 **info3)
 {
 	struct winbindd_domain *contact_domain;
 	fstring name_domain, name_user;
@@ -1181,9 +1181,9 @@ typedef	NTSTATUS (*netlogon_fn_t)(struct rpc_pipe_client *cli,
 				  DATA_BLOB nt_response,
 				  struct netr_SamInfo3 **info3);
 
-NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
-					 struct winbindd_cli_state *state,
-					 struct netr_SamInfo3 **info3)
+static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
+						struct winbindd_cli_state *state,
+						struct netr_SamInfo3 **info3)
 {
 
 	struct rpc_pipe_client *netlogon_pipe;
@@ -1730,20 +1730,17 @@ void winbindd_pam_auth_crap(struct winbindd_cli_state *state)
 	}
 
 	if (!state->privileged) {
-		char *error_string = NULL;
 		DEBUG(2, ("winbindd_pam_auth_crap: non-privileged access "
 			  "denied.  !\n"));
 		DEBUGADD(2, ("winbindd_pam_auth_crap: Ensure permissions "
 			     "on %s are set correctly.\n",
 			     get_winbind_priv_pipe_dir()));
 		/* send a better message than ACCESS_DENIED */
-		error_string = talloc_asprintf(state->mem_ctx,
-					       "winbind client not authorized "
-					       "to use winbindd_pam_auth_crap."
-					       " Ensure permissions on %s "
-					       "are set correctly.",
-					       get_winbind_priv_pipe_dir());
-		fstrcpy(state->response->data.auth.error_string, error_string);
+		fstr_sprintf(state->response->data.auth.error_string,
+			     "winbind client not authorized to use "
+			     "winbindd_pam_auth_crap. Ensure permissions on "
+			     "%s are set correctly.",
+			     get_winbind_priv_pipe_dir());
 		result = NT_STATUS_ACCESS_DENIED;
 		goto done;
 	}
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index 538548b..f1fc0f6 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -478,15 +478,6 @@ void ndr_print_winbindd_domain(struct ndr_print *ndr,
 struct winbindd_domain *find_auth_domain(struct winbindd_cli_state *state, 
 					const char *domain_name);
 void winbindd_pam_auth(struct winbindd_cli_state *state);
-NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
-				       struct winbindd_cli_state *state,
-				       struct netr_SamInfo3 **info3);
-NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
-					 struct winbindd_cli_state *state, 
-					 struct netr_SamInfo3 **info3);
-NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
-					 struct winbindd_cli_state *state,
-					 struct netr_SamInfo3 **info3);
 enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
 					    struct winbindd_cli_state *state) ;
 void winbindd_pam_auth_crap(struct winbindd_cli_state *state);


-- 
Samba Shared Repository


More information about the samba-cvs mailing list