GSS Masquerade: auth_gss

Benjamin Coddington Benjamin.Coddington at uvm.edu
Mon Mar 17 16:14:20 EDT 2008


This patch allows a process to masquerade as a desired user by passing 
an uid to auth_gss via "nfsid" key.  The process' actual uid must be 
listed in the implemented sysctl interface in order to masquerade as 
another user.

There are only changes to auth_gss, because I wanted to stay at the 
module level, and I only needed it for auth_gss.

Masquerading users can be added
	
	echo add 33 > /proc/sys/fs/nfs/masqueraders

and removed

	echo remove 33 > /proc/sys/fs/nfs/masqueraders


---
  net/sunrpc/auth_gss/auth_gss.c |  248 
++++++++++++++++++++++++++++++++++++++++
  1 files changed, 248 insertions(+), 0 deletions(-)

diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 6dac387..afc1938 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -54,6 +54,14 @@
  #include <linux/sunrpc/gss_api.h>
  #include <asm/uaccess.h>

+#define NFS_MASQUERADE 1
+#ifdef NFS_MASQUERADE
+#include <linux/key.h>
+#include <linux/list.h>
+#include <linux/proc_fs.h>
+#include <linux/sysctl.h>
+#endif
+
  static const struct rpc_authops authgss_ops;

  static const struct rpc_credops gss_credops;
@@ -91,6 +99,16 @@ struct gss_auth {
  static void gss_free_ctx(struct gss_cl_ctx *);
  static struct rpc_pipe_ops gss_upcall_ops;

+#ifdef NFS_MASQUERADE
+struct hlist_head masqueraders;
+struct ctl_table_header *masq_sysctl_header;
+
+struct masquerader {
+	struct hlist_node m_hash;
+	uid_t uid;
+}
+#endif
+
  static inline struct gss_cl_ctx *
  gss_get_ctx(struct gss_cl_ctx *ctx)
  {
@@ -797,12 +815,51 @@ gss_lookup_cred(struct rpc_auth *auth, struct 
auth_cred *acred, int flags)
  	return rpcauth_lookup_credcache(auth, acred, flags);
  }

+#ifdef NFS_MASQUERADE
+/* begin nfsid keytype */
+static int
+nfsid_key_instantiate(struct key *key, const void *data, size_t buflen) {
+	const uid_t *uid = data;
+	key->payload.value = *uid;
+	return 0;
+}
+
+static int
+nfsid_key_match(const struct key *key, const void *desc) {
+	return key->description != NULL &&
+		strcmp(key->description, desc) == 0;
+}
+
+static struct key_type key_type_nfsid = {
+	.name			= "nfsid",
+	.def_datalen	= sizeof(uid_t),
+	.instantiate 	= nfsid_key_instantiate,
+	.match			= nfsid_key_match
+};
+/* end nfsid keytype */
+
+static int
+is_masq_user(uid_t uid) {
+	struct masquerader *m;
+	struct hlist_node *pos, *next;
+	hlist_for_each_safe(pos, next, &masqueraders) {
+		m = hlist_entry(pos, struct masquerader, m_hash);
+		if (m->uid == uid)
+			return 1;
+	}
+	return 0;
+}
+#endif
+
  static struct rpc_cred *
  gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
  {
  	struct gss_auth *gss_auth = container_of(auth, struct gss_auth, 
rpc_auth);
  	struct gss_cred	*cred = NULL;
  	int err = -ENOMEM;
+#ifdef NFS_MASQUERADE
+	struct key *key;
+#endif

  	dprintk("RPC:       gss_create_cred for uid %d, flavor %d\n",
  		acred->uid, auth->au_flavor);
@@ -811,6 +868,28 @@ gss_create_cred(struct rpc_auth *auth, struct 
auth_cred *acred, int flags)
  		goto out_err;

  	rpcauth_init_cred(&cred->gc_base, acred, auth, &gss_credops);
+
+#ifdef NFS_MASQUERADE
+		/* this user may masquerade?? */
+		if (is_masq_user(acred->uid)) {
+			/* ok, lets see if we can get a uid from our keyrings */
+			key = request_key(&key_type_nfsid, "nfsid", NULL);
+			if (IS_ERR(key)) {
+				dprintk("RPC:      user is set to masquerade,"
+					" but no nfsid key!\n");
+				err = PTR_ERR(key);
+				dprintk("RPC:      request_key err is %d\n",
+					err);
+				goto out_err;
+			} else {
+				cred->gc_uid = key->payload.value;
+				key_put(key);
+				dprintk("RPC:      using uid %lu"
+					" from nfsid keyring\n",
+					(unsigned long int)cred->gc_uid);
+			}
+		}
+#endif
  	/*
  	 * Note: in order to force a call to call_refresh(), we deliberately
  	 * fail to flag the credential as RPCAUTH_CRED_UPTODATE.
@@ -842,6 +921,10 @@ static int
  gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
  {
  	struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
+#ifdef NFS_MASQUERADE
+	int ret;
+	struct key *key;
+#endif

  	/*
  	 * If the searchflags have set RPCAUTH_LOOKUP_NEW, then
@@ -854,7 +937,29 @@ gss_match(struct auth_cred *acred, struct rpc_cred 
*rc, int flags)
  	if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
  		return 0;
  out:
+#ifdef NFS_MASQUERADE
+	if (is_masq_user(acred->uid)) {
+		key = request_key(&key_type_nfsid, "nfsid", NULL);
+		if (IS_ERR(key)) {
+			dprintk("RPC:      user is set to masquerade,"
+				" but no nfsid key!\n");
+			dprintk("RPC:      request_key err is %li\n",
+				PTR_ERR(key));
+			ret = 0;
+		} else {
+			ret = (rc->cr_uid == key->payload.value);
+			key_put(key);
+			dprintk("RPC:      using masquerade uid %lu"
+				" from nfsid keyring\n",
+				(unsigned long int)rc->cr_uid);
+		}
+	} else {
+		ret = (rc->cr_uid == acred->uid);
+	}
+	return ret;
+#else
  	return (rc->cr_uid == acred->uid);
+#endif
  }

  /*
@@ -1283,6 +1388,137 @@ out:
  	return status;
  }

+#ifdef NFS_MASQUERADE
+/* begin sysctl */
+static void
+add_masq_user(uid_t uid) {
+		struct masquerader *m;
+		struct hlist_node *pos, *next;
+		int cmax = 0;
+
+		if (uid) {
+			hlist_for_each_safe(pos, next, &masqueraders) {
+				cmax++;
+				m = hlist_entry(pos, struct masquerader, m_hash);
+				if (m->uid == uid || cmax >= 32)
+					goto out;
+			}
+			m = kmalloc(sizeof(*m), GFP_KERNEL);
+			hlist_add_head(&m->m_hash, &masqueraders);
+			m->uid = uid;
+		}
+	out:
+		return;
+}
+
+static void
+remove_masq_user(uid_t uid) {
+	struct masquerader *m;
+	struct hlist_node *pos, *next;
+
+	if (uid) {
+		hlist_for_each_safe(pos, next, &masqueraders) {
+			m = hlist_entry(pos, struct masquerader, m_hash);
+			if (m->uid == uid) {
+				hlist_del(&m->m_hash);
+				kfree(m);
+				break;
+			}
+		}
+	}
+}
+
+static int
+read_masq_users(char *s) {
+	int len = 0;
+	struct hlist_node *pos, *next;
+	struct masquerader *m;
+
+	hlist_for_each_safe(pos, next, &masqueraders) {
+		m = hlist_entry(pos, struct masquerader, m_hash);
+		len += sprintf(s + len, "%lu\n", (long unsigned int)m->uid);
+	}
+	return len;
+}
+
+static int
+masq_sysctl_handler(ctl_table *ctl, int write, struct file *filp,
+				void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+	size_t len;
+	char __user *p;
+	char *sread;
+
+	if (!*lenp || (*ppos && !write)) {
+		*lenp = 0;
+		return 0;
+	}
+
+	if (write) {
+		p = buffer;
+		if (!strncmp(p, "add ", 4))
+			add_masq_user(simple_strtoul(p+=4, NULL, 0));
+		else if (!strncmp(p, "remove ", 7))
+			remove_masq_user(simple_strtoul(p+=7, NULL, 0));
+		else printk("nfs_masquerade: unknown command\n"
+				"nfs_masquerade: use add/remove <uid>\n");
+	} else {
+		sread = kmalloc(1024*sizeof(char), GFP_KERNEL);
+		len = read_masq_users(sread);
+		if(copy_to_user(buffer, sread, len)) {
+			kfree(sread);
+			return -EFAULT;
+		}
+		*lenp = len;
+		*ppos = len;
+		kfree(sread);
+	}
+	return 0;
+}
+
+static void
+free_masq_users(void) {
+	struct masquerader *m;
+	struct hlist_node *pos, *next;
+	hlist_for_each_safe(pos, next, &masqueraders) {
+		m = hlist_entry(pos, struct masquerader, m_hash);
+		hlist_del(&m->m_hash);
+		kfree(m);
+	}
+}
+
+static ctl_table sys_fs_nfs_masq_table[] = {
+	{
+		.ctl_name = -2,
+		.procname = "masqueraders",
+		.mode = 0644,
+		.proc_handler = &masq_sysctl_handler
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table sys_fs_nfs_table[] = {
+	{
+		.ctl_name = -2,
+		.procname = "nfs",
+		.mode = 0555,
+		.child = sys_fs_nfs_masq_table,
+	},
+	{ .ctl_name = 0 }
+};
+
+static ctl_table sys_fs_table[] = {
+	{
+		.ctl_name = CTL_FS,
+		.procname = "fs",
+		.mode = 0555,
+		.child = sys_fs_nfs_table
+	},
+	{ .ctl_name = 0 }
+};
+/* end sysctl */
+#endif
+
  static const struct rpc_authops authgss_ops = {
  	.owner		= THIS_MODULE,
  	.au_flavor	= RPC_AUTH_GSS,
@@ -1332,6 +1568,13 @@ static int __init init_rpcsec_gss(void)
  {
  	int err = 0;

+#ifdef NFS_MASQUERADE
+	INIT_HLIST_HEAD(&masqueraders);
+	err = register_key_type(&key_type_nfsid);
+	if (err)
+		goto out;
+	masq_sysctl_header = register_sysctl_table(sys_fs_table,  1);
+#endif
  	err = rpcauth_register(&authgss_ops);
  	if (err)
  		goto out;
@@ -1347,6 +1590,11 @@ out:

  static void __exit exit_rpcsec_gss(void)
  {
+#ifdef NFS_MASQUERADE
+	free_masq_users();
+	unregister_sysctl_table(masq_sysctl_header);
+	unregister_key_type(&key_type_nfsid);
+#endif
  	gss_svc_shutdown();
  	rpcauth_unregister(&authgss_ops);
  }


More information about the NFSv4 mailing list