[PATCH 1/7] svcgssd: add client's principal name to downcall information

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

 



From: Olga Kornievskaia <aglo@xxxxxxxxxxxxxx>

This patch adds the krb5 hostbased principal, name which the
nfs client used to authenticate, to the svcgssd downcall
information.  This information is needed for the callback
authentication.

When estabishing the callback, nfsd will pass the principal
name in the upcall to the gssd.  gssd will acquire a service
ticket for the specified principal name.

Signed-off-by: Olga Kornievskaia <aglo@xxxxxxxxxxxxxx>
Signed-off-by: Kevin Coffman <kwc@xxxxxxxxxxxxxx>
---

 utils/gssd/svcgssd_proc.c |   94 ++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 87 insertions(+), 7 deletions(-)

diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c
index 6f2ba61..f1bfbef 100644
--- a/utils/gssd/svcgssd_proc.c
+++ b/utils/gssd/svcgssd_proc.c
@@ -56,6 +56,7 @@
 #include "gss_util.h"
 #include "err_util.h"
 #include "context.h"
+#include "gss_oids.h"
 
 extern char * mech2file(gss_OID mech);
 #define SVCGSSD_CONTEXT_CHANNEL "/proc/net/rpc/auth.rpcsec.context/channel"
@@ -73,7 +74,7 @@ struct svc_cred {
 static int
 do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
 		gss_OID mech, gss_buffer_desc *context_token,
-		int32_t endtime)
+		int32_t endtime, char *client_name)
 {
 	FILE *f;
 	int i;
@@ -98,9 +99,10 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
 	qword_printint(f, cred->cr_gid);
 	qword_printint(f, cred->cr_ngroups);
 	printerr(2, "mech: %s, hndl len: %d, ctx len %d, timeout: %d (%d from now), "
-		 "uid: %d, gid: %d, num aux grps: %d:\n",
+		 "clnt: %s, uid: %d, gid: %d, num aux grps: %d:\n",
 		 fname, out_handle->length, context_token->length,
 		 endtime, endtime - time(0),
+		 client_name ? client_name : "<null>",
 		 cred->cr_uid, cred->cr_gid, cred->cr_ngroups);
 	for (i=0; i < cred->cr_ngroups; i++) {
 		qword_printint(f, cred->cr_groups[i]);
@@ -108,6 +110,8 @@ do_svc_downcall(gss_buffer_desc *out_handle, struct svc_cred *cred,
 	}
 	qword_print(f, fname);
 	qword_printhex(f, context_token->value, context_token->length);
+	if (client_name)
+		qword_print(f, client_name);
 	err = qword_eol(f);
 	if (err) {
 		printerr(1, "WARNING: error writing to downcall channel "
@@ -307,6 +311,75 @@ print_hexl(const char *description, unsigned char *cp, int length)
 }
 #endif
 
+static int
+get_krb5_hostbased_name (gss_buffer_desc *name, char **hostbased_name)
+{
+	char *p, *sname = NULL;
+	if (strchr(name->value, '@') && strchr(name->value, '/')) {
+		if ((sname = calloc(name->length, 1)) == NULL) {
+			printerr(0, "ERROR: get_krb5_hostbased_name failed "
+				 "to allocate %d bytes\n", name->length);
+			return -1;
+		}
+		/* read in name and instance and replace '/' with '@' */
+		sscanf(name->value, "%[^@]", sname);
+		p = strrchr(sname, '/');
+		if (p == NULL) {    /* The '@' preceeded the '/' */
+			free(sname);
+			return -1;
+		}
+		*p = '@';
+	}
+	*hostbased_name = sname;
+	return 0;
+}
+
+static int
+get_hostbased_client_name(gss_name_t client_name, gss_OID mech,
+			  char **hostbased_name)
+{
+	u_int32_t	maj_stat, min_stat;
+	gss_buffer_desc	name;
+	gss_OID		name_type = GSS_C_NO_OID;
+	char		*cname;
+	int		res = -1;
+
+	*hostbased_name = NULL;	    /* preset in case we fail */
+
+	/* Get the client's gss authenticated name */
+	maj_stat = gss_display_name(&min_stat, client_name, &name, &name_type);
+	if (maj_stat != GSS_S_COMPLETE) {
+		pgsserr("get_hostbased_client_name: gss_display_name",
+			maj_stat, min_stat, mech);
+		goto out_err;
+	}
+	if (name.length >= 0xffff) {	    /* don't overflow */
+		printerr(0, "ERROR: get_hostbased_client_name: "
+			 "received gss_name is too long (%d bytes)\n",
+			 name.length);
+		goto out_rel_buf;
+	}
+
+	/* For Kerberos, transform the NT_KRB5_PRINCIPAL name to
+	 * an NT_HOSTBASED_SERVICE name */
+	if (g_OID_equal(&krb5oid, mech)) {
+		if (get_krb5_hostbased_name(&name, &cname) == 0)
+			*hostbased_name = cname;
+	}
+
+	/* No support for SPKM3, just print a warning (for now) */
+	if (g_OID_equal(&spkm3oid, mech)) {
+		printerr(1, "WARNING: get_hostbased_client_name: "
+			 "no hostbased_name support for SPKM3\n");
+	}
+
+	res = 0;
+out_rel_buf:
+	gss_release_buffer(&min_stat, &name);
+out_err:
+	return res;
+}
+
 void
 handle_nullreq(FILE *f) {
 	/* XXX initialize to a random integer to reduce chances of unnecessary
@@ -325,7 +398,7 @@ handle_nullreq(FILE *f) {
 				null_token = {.value = NULL};
 	u_int32_t		ret_flags;
 	gss_ctx_id_t		ctx = GSS_C_NO_CONTEXT;
-	gss_name_t		client_name;
+	gss_name_t		client_name = NULL;
 	gss_OID			mech = GSS_C_NO_OID;
 	u_int32_t		maj_stat = GSS_S_FAILURE, min_stat = 0;
 	u_int32_t		ignore_min_stat;
@@ -334,6 +407,7 @@ handle_nullreq(FILE *f) {
 	static int		lbuflen = 0;
 	static char		*cp;
 	int32_t			ctx_endtime;
+	char			*hostbased_name = NULL;
 
 	printerr(1, "handling null request\n");
 
@@ -396,11 +470,13 @@ handle_nullreq(FILE *f) {
 	if (get_ids(client_name, mech, &cred)) {
 		/* get_ids() prints error msg */
 		maj_stat = GSS_S_BAD_NAME; /* XXX ? */
-		gss_release_name(&ignore_min_stat, &client_name);
 		goto out_err;
 	}
-	gss_release_name(&ignore_min_stat, &client_name);
-
+	if (get_hostbased_client_name(client_name, mech, &hostbased_name)) {
+		/* get_hostbased_client_name() prints error msg */
+		maj_stat = GSS_S_BAD_NAME; /* XXX ? */
+		goto out_err;
+	}
 
 	/* Context complete. Pass handle_seq in out_handle to use
 	 * for context lookup in the kernel. */
@@ -419,7 +495,8 @@ handle_nullreq(FILE *f) {
 	/* We no longer need the gss context */
 	gss_delete_sec_context(&ignore_min_stat, &ctx, &ignore_out_tok);
 
-	do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime);
+	do_svc_downcall(&out_handle, &cred, mech, &ctx_token, ctx_endtime,
+			hostbased_name);
 continue_needed:
 	send_response(f, &in_handle, &in_tok, maj_stat, min_stat,
 			&out_handle, &out_tok);
@@ -428,6 +505,9 @@ out:
 		free(ctx_token.value);
 	if (out_tok.value != NULL)
 		gss_release_buffer(&ignore_min_stat, &out_tok);
+	if (client_name)
+		gss_release_name(&ignore_min_stat, &client_name);
+	free(hostbased_name);
 	printerr(1, "finished handling null request\n");
 	return;
 

--
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