[PATCH v1] gssd: Add "srchost=" upcall parameter

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The callback client used by NFSv4.0 servers to send CB calls has to
use a source principal that is the same as the target principal
that the client used to establish the forward channel.

In multi-homed server set-ups, the domain part of the principal's
hostname may not be the same as server's DNS domain. So gssd can
no longer assume that. The kernel can scrape that domain off the
forward channel's principal and pass that up to gssd.

This patch adds a new parameter, "srchost", to the kernel upcall.
When the kernel presents this new parameter in an upcall, gssd will
use it, along with the "service" parameter, to construct the service
principal for the keytab lookup.

Signed-off-by: Chuck Lever <chuck.lever@xxxxxxxxxx>
---
 utils/gssd/gssd_proc.c |   23 +++++++++++++----------
 utils/gssd/krb5_util.c |   27 ++++++++++++++++++---------
 utils/gssd/krb5_util.h |    2 +-
 3 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
index ce73777..8767e26 100644
--- a/utils/gssd/gssd_proc.c
+++ b/utils/gssd/gssd_proc.c
@@ -520,8 +520,9 @@ out:
 }
 
 static AUTH *
-krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname,
-		    char *service, CLIENT **rpc_clnt)
+krb5_use_machine_creds(struct clnt_info *clp, uid_t uid,
+		       char *srchost, char *tgtname, char *service,
+		       CLIENT **rpc_clnt)
 {
 	AUTH	*auth = NULL;
 	char	**credlist = NULL;
@@ -534,7 +535,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid, char *tgtname,
 
 	do {
 		gssd_refresh_krb5_machine_credential(clp->servername, NULL,
-						service);
+						     service, srchost);
 	/*
 	 * Get a list of credential cache names and try each
 	 * of them until one works or we've tried them all
@@ -594,8 +595,8 @@ out:
  * context on behalf of the kernel
  */
 static void
-process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
-		    char *service)
+process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *srchost,
+		    char *tgtname, char *service)
 {
 	CLIENT			*rpc_clnt = NULL;
 	AUTH			*auth = NULL;
@@ -643,7 +644,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
 	if (auth == NULL) {
 		if (uid == 0 && (root_uses_machine_creds == 1 ||
 				service != NULL)) {
-			auth =	krb5_use_machine_creds(clp, uid, tgtname,
+			auth =	krb5_use_machine_creds(clp, uid, srchost, tgtname,
 							service, &rpc_clnt);
 			if (auth == NULL)
 				goto out_return_error;
@@ -714,7 +715,7 @@ handle_krb5_upcall(struct clnt_upcall_info *info)
 
 	printerr(2, "\n%s: uid %d (%s)\n", __func__, info->uid, clp->relpath);
 
-	process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL);
+	process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL, NULL);
 	free(info);
 }
 
@@ -728,11 +729,12 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
 	char			*uidstr = NULL;
 	char			*target = NULL;
 	char			*service = NULL;
+	char			*srchost = NULL;
 	char			*enctypes = NULL;
 	char			*upcall_str;
 	char			*pbuf = info->lbuf;
 
-	printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath);
+	printerr(2, "%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath);
 
 	upcall_str = strdup(info->lbuf);
 	if (upcall_str == NULL) {
@@ -751,6 +753,8 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
 			target = p + strlen("target=");
 		else if (!strncmp(p, "service=", strlen("service=")))
 			service = p + strlen("service=");
+		else if (!strncmp(p, "srchost=", strlen("srchost=")))
+			srchost = p + strlen("srchost=");
 	}
 
 	if (!mech || strlen(mech) < 1) {
@@ -802,7 +806,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
 	}
 
 	if (strcmp(mech, "krb5") == 0 && clp->servername)
-		process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
+		process_krb5_upcall(clp, uid, clp->gssd_fd, srchost, target, service);
 	else {
 		if (clp->servername)
 			printerr(0, "WARNING: handle_gssd_upcall: "
@@ -815,4 +819,3 @@ out_nomem:
 	free(info);
 	return;
 }
-
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
index b342b06..eba1aac 100644
--- a/utils/gssd/krb5_util.c
+++ b/utils/gssd/krb5_util.c
@@ -757,7 +757,8 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
  * the server hostname.
  */
 static int
-find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname,
+find_keytab_entry(krb5_context context, krb5_keytab kt,
+		  const char *srchost, const char *tgtname,
 		  krb5_keytab_entry *kte, const char **svcnames)
 {
 	krb5_error_code code;
@@ -781,7 +782,9 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname,
 		goto out;
 
 	/* Get full local hostname */
-	if (gethostname(myhostname, sizeof(myhostname)) == -1) {
+	if (srchost) {
+		strcpy(myhostname, srchost);
+	} else if (gethostname(myhostname, sizeof(myhostname)) == -1) {
 		retval = errno;
 		k5err = gssd_k5_err_msg(context, retval);
 		printerr(1, "%s while getting local hostname\n", k5err);
@@ -807,10 +810,12 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname,
 	        myhostad[i+1] = 0;
 	}
 
-	retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname));
-	if (retval) {
-		/* Don't use myhostname */
-		myhostname[0] = 0;
+	if (!srchost) {
+		retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname));
+		if (retval) {
+			/* Don't use myhostname */
+			myhostname[0] = 0;
+		}
 	}
 
 	code = krb5_get_default_realm(context, &default_realm);
@@ -1140,7 +1145,7 @@ gssd_get_krb5_machine_cred_list(char ***list)
 		if (ple->ccname) {
 			/* Make sure cred is up-to-date before returning it */
 			retval = gssd_refresh_krb5_machine_credential(NULL, ple,
-				NULL);
+								      NULL, NULL);
 			if (retval)
 				continue;
 			if (i + 1 > listsize) {
@@ -1231,7 +1236,7 @@ gssd_destroy_krb5_machine_creds(void)
 int
 gssd_refresh_krb5_machine_credential(char *hostname,
 				     struct gssd_k5_kt_princ *ple, 
-					 char *service)
+				     char *service, char *srchost)
 {
 	krb5_error_code code = 0;
 	krb5_context context;
@@ -1240,6 +1245,9 @@ gssd_refresh_krb5_machine_credential(char *hostname,
 	char *k5err = NULL;
 	const char *svcnames[] = { "$", "root", "nfs", "host", NULL };
 
+	printerr(2, "%s: hostname=%s ple=%p service=%s srchost=%s\n",
+		__func__, hostname, ple, service, srchost);
+
 	/*
 	 * If a specific service name was specified, use it.
 	 * Otherwise, use the default list.
@@ -1270,7 +1278,8 @@ gssd_refresh_krb5_machine_credential(char *hostname,
 	if (ple == NULL) {
 		krb5_keytab_entry kte;
 
-		code = find_keytab_entry(context, kt, hostname, &kte, svcnames);
+		code = find_keytab_entry(context, kt, srchost, hostname,
+					 &kte, svcnames);
 		if (code) {
 			printerr(0, "ERROR: %s: no usable keytab entry found "
 				 "in keytab %s for connection with host %s\n",
diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h
index e3bbb07..b000b44 100644
--- a/utils/gssd/krb5_util.h
+++ b/utils/gssd/krb5_util.h
@@ -30,7 +30,7 @@ void gssd_free_krb5_machine_cred_list(char **list);
 void gssd_destroy_krb5_machine_creds(void);
 int  gssd_refresh_krb5_machine_credential(char *hostname,
 					  struct gssd_k5_kt_princ *ple, 
-					  char *service);
+					  char *service, char *srchost);
 char *gssd_k5_err_msg(krb5_context context, krb5_error_code code);
 void gssd_k5_get_default_realm(char **def_realm);
 

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux