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