aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/idmap.c
diff options
context:
space:
mode:
authorGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
committerGlenn Elliott <gelliott@cs.unc.edu>2012-03-04 19:47:13 -0500
commitc71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch)
treeecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /fs/nfs/idmap.c
parentea53c912f8a86a8567697115b6a0d8152beee5c8 (diff)
parent6a00f206debf8a5c8899055726ad127dbeeed098 (diff)
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts: litmus/sched_cedf.c
Diffstat (limited to 'fs/nfs/idmap.c')
-rw-r--r--fs/nfs/idmap.c283
1 files changed, 272 insertions, 11 deletions
diff --git a/fs/nfs/idmap.c b/fs/nfs/idmap.c
index 21a84d45916f..79664a1025af 100644
--- a/fs/nfs/idmap.c
+++ b/fs/nfs/idmap.c
@@ -33,11 +33,257 @@
33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */ 35 */
36#include <linux/types.h>
37#include <linux/string.h>
38#include <linux/kernel.h>
39
40static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res)
41{
42 unsigned long val;
43 char buf[16];
44
45 if (memchr(name, '@', namelen) != NULL || namelen >= sizeof(buf))
46 return 0;
47 memcpy(buf, name, namelen);
48 buf[namelen] = '\0';
49 if (strict_strtoul(buf, 0, &val) != 0)
50 return 0;
51 *res = val;
52 return 1;
53}
54
55static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
56{
57 return snprintf(buf, buflen, "%u", id);
58}
59
60#ifdef CONFIG_NFS_USE_NEW_IDMAPPER
61
62#include <linux/slab.h>
63#include <linux/cred.h>
64#include <linux/sunrpc/sched.h>
65#include <linux/nfs4.h>
66#include <linux/nfs_fs_sb.h>
67#include <linux/nfs_idmap.h>
68#include <linux/keyctl.h>
69#include <linux/key-type.h>
70#include <linux/rcupdate.h>
71#include <linux/err.h>
72
73#include <keys/user-type.h>
74
75#define NFS_UINT_MAXLEN 11
76
77const struct cred *id_resolver_cache;
78
79struct key_type key_type_id_resolver = {
80 .name = "id_resolver",
81 .instantiate = user_instantiate,
82 .match = user_match,
83 .revoke = user_revoke,
84 .destroy = user_destroy,
85 .describe = user_describe,
86 .read = user_read,
87};
88
89int nfs_idmap_init(void)
90{
91 struct cred *cred;
92 struct key *keyring;
93 int ret = 0;
94
95 printk(KERN_NOTICE "Registering the %s key type\n", key_type_id_resolver.name);
96
97 cred = prepare_kernel_cred(NULL);
98 if (!cred)
99 return -ENOMEM;
100
101 keyring = key_alloc(&key_type_keyring, ".id_resolver", 0, 0, cred,
102 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
103 KEY_USR_VIEW | KEY_USR_READ,
104 KEY_ALLOC_NOT_IN_QUOTA);
105 if (IS_ERR(keyring)) {
106 ret = PTR_ERR(keyring);
107 goto failed_put_cred;
108 }
109
110 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
111 if (ret < 0)
112 goto failed_put_key;
113
114 ret = register_key_type(&key_type_id_resolver);
115 if (ret < 0)
116 goto failed_put_key;
117
118 cred->thread_keyring = keyring;
119 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
120 id_resolver_cache = cred;
121 return 0;
122
123failed_put_key:
124 key_put(keyring);
125failed_put_cred:
126 put_cred(cred);
127 return ret;
128}
129
130void nfs_idmap_quit(void)
131{
132 key_revoke(id_resolver_cache->thread_keyring);
133 unregister_key_type(&key_type_id_resolver);
134 put_cred(id_resolver_cache);
135}
136
137/*
138 * Assemble the description to pass to request_key()
139 * This function will allocate a new string and update dest to point
140 * at it. The caller is responsible for freeing dest.
141 *
142 * On error 0 is returned. Otherwise, the length of dest is returned.
143 */
144static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen,
145 const char *type, size_t typelen, char **desc)
146{
147 char *cp;
148 size_t desclen = typelen + namelen + 2;
149
150 *desc = kmalloc(desclen, GFP_KERNEL);
151 if (!*desc)
152 return -ENOMEM;
153
154 cp = *desc;
155 memcpy(cp, type, typelen);
156 cp += typelen;
157 *cp++ = ':';
158
159 memcpy(cp, name, namelen);
160 cp += namelen;
161 *cp = '\0';
162 return desclen;
163}
164
165static ssize_t nfs_idmap_request_key(const char *name, size_t namelen,
166 const char *type, void *data, size_t data_size)
167{
168 const struct cred *saved_cred;
169 struct key *rkey;
170 char *desc;
171 struct user_key_payload *payload;
172 ssize_t ret;
173
174 ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc);
175 if (ret <= 0)
176 goto out;
177
178 saved_cred = override_creds(id_resolver_cache);
179 rkey = request_key(&key_type_id_resolver, desc, "");
180 revert_creds(saved_cred);
181 kfree(desc);
182 if (IS_ERR(rkey)) {
183 ret = PTR_ERR(rkey);
184 goto out;
185 }
186
187 rcu_read_lock();
188 rkey->perm |= KEY_USR_VIEW;
189
190 ret = key_validate(rkey);
191 if (ret < 0)
192 goto out_up;
193
194 payload = rcu_dereference(rkey->payload.data);
195 if (IS_ERR_OR_NULL(payload)) {
196 ret = PTR_ERR(payload);
197 goto out_up;
198 }
199
200 ret = payload->datalen;
201 if (ret > 0 && ret <= data_size)
202 memcpy(data, payload->data, ret);
203 else
204 ret = -EINVAL;
205
206out_up:
207 rcu_read_unlock();
208 key_put(rkey);
209out:
210 return ret;
211}
212
213
214/* ID -> Name */
215static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf, size_t buflen)
216{
217 char id_str[NFS_UINT_MAXLEN];
218 int id_len;
219 ssize_t ret;
220
221 id_len = snprintf(id_str, sizeof(id_str), "%u", id);
222 ret = nfs_idmap_request_key(id_str, id_len, type, buf, buflen);
223 if (ret < 0)
224 return -EINVAL;
225 return ret;
226}
227
228/* Name -> ID */
229static int nfs_idmap_lookup_id(const char *name, size_t namelen,
230 const char *type, __u32 *id)
231{
232 char id_str[NFS_UINT_MAXLEN];
233 long id_long;
234 ssize_t data_size;
235 int ret = 0;
236
237 data_size = nfs_idmap_request_key(name, namelen, type, id_str, NFS_UINT_MAXLEN);
238 if (data_size <= 0) {
239 ret = -EINVAL;
240 } else {
241 ret = strict_strtol(id_str, 10, &id_long);
242 *id = (__u32)id_long;
243 }
244 return ret;
245}
246
247int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
248{
249 if (nfs_map_string_to_numeric(name, namelen, uid))
250 return 0;
251 return nfs_idmap_lookup_id(name, namelen, "uid", uid);
252}
253
254int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *gid)
255{
256 if (nfs_map_string_to_numeric(name, namelen, gid))
257 return 0;
258 return nfs_idmap_lookup_id(name, namelen, "gid", gid);
259}
260
261int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
262{
263 int ret = -EINVAL;
264
265 if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
266 ret = nfs_idmap_lookup_name(uid, "user", buf, buflen);
267 if (ret < 0)
268 ret = nfs_map_numeric_to_string(uid, buf, buflen);
269 return ret;
270}
271int nfs_map_gid_to_group(const struct nfs_server *server, __u32 gid, char *buf, size_t buflen)
272{
273 int ret = -EINVAL;
274
275 if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
276 ret = nfs_idmap_lookup_name(gid, "group", buf, buflen);
277 if (ret < 0)
278 ret = nfs_map_numeric_to_string(gid, buf, buflen);
279 return ret;
280}
281
282#else /* CONFIG_NFS_USE_NEW_IDMAPPER not defined */
36 283
37#include <linux/module.h> 284#include <linux/module.h>
38#include <linux/mutex.h> 285#include <linux/mutex.h>
39#include <linux/init.h> 286#include <linux/init.h>
40#include <linux/types.h>
41#include <linux/slab.h> 287#include <linux/slab.h>
42#include <linux/socket.h> 288#include <linux/socket.h>
43#include <linux/in.h> 289#include <linux/in.h>
@@ -489,30 +735,45 @@ static unsigned int fnvhash32(const void *buf, size_t buflen)
489 return hash; 735 return hash;
490} 736}
491 737
492int nfs_map_name_to_uid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) 738int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
493{ 739{
494 struct idmap *idmap = clp->cl_idmap; 740 struct idmap *idmap = server->nfs_client->cl_idmap;
495 741
742 if (nfs_map_string_to_numeric(name, namelen, uid))
743 return 0;
496 return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid); 744 return nfs_idmap_id(idmap, &idmap->idmap_user_hash, name, namelen, uid);
497} 745}
498 746
499int nfs_map_group_to_gid(struct nfs_client *clp, const char *name, size_t namelen, __u32 *uid) 747int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
500{ 748{
501 struct idmap *idmap = clp->cl_idmap; 749 struct idmap *idmap = server->nfs_client->cl_idmap;
502 750
751 if (nfs_map_string_to_numeric(name, namelen, uid))
752 return 0;
503 return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid); 753 return nfs_idmap_id(idmap, &idmap->idmap_group_hash, name, namelen, uid);
504} 754}
505 755
506int nfs_map_uid_to_name(struct nfs_client *clp, __u32 uid, char *buf) 756int nfs_map_uid_to_name(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
507{ 757{
508 struct idmap *idmap = clp->cl_idmap; 758 struct idmap *idmap = server->nfs_client->cl_idmap;
759 int ret = -EINVAL;
509 760
510 return nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf); 761 if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
762 ret = nfs_idmap_name(idmap, &idmap->idmap_user_hash, uid, buf);
763 if (ret < 0)
764 ret = nfs_map_numeric_to_string(uid, buf, buflen);
765 return ret;
511} 766}
512int nfs_map_gid_to_group(struct nfs_client *clp, __u32 uid, char *buf) 767int nfs_map_gid_to_group(const struct nfs_server *server, __u32 uid, char *buf, size_t buflen)
513{ 768{
514 struct idmap *idmap = clp->cl_idmap; 769 struct idmap *idmap = server->nfs_client->cl_idmap;
770 int ret = -EINVAL;
515 771
516 return nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf); 772 if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
773 ret = nfs_idmap_name(idmap, &idmap->idmap_group_hash, uid, buf);
774 if (ret < 0)
775 ret = nfs_map_numeric_to_string(uid, buf, buflen);
776 return ret;
517} 777}
518 778
779#endif /* CONFIG_NFS_USE_NEW_IDMAPPER */