aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShirish Pargaonkar <shirishpargaonkar@gmail.com>2011-04-28 00:34:35 -0400
committerSteve French <sfrench@us.ibm.com>2011-05-19 10:10:51 -0400
commit4d79dba0e00749fa40de8ef13a9b85ce57a1603b (patch)
tree55e377f53c761e70d5b90a1f901f70609ffcbcc7
parent9ad1506b42c828dff0b9d8f3914e1f837734e91c (diff)
cifs: Add idmap key and related data structures and functions (try #17 repost)
Define (global) data structures to store ids, uids and gids, to which a SID maps. There are two separate trees, one for SID/uid and another one for SID/gid. A new type of key, cifs_idmap_key_type, is used. Keys are instantiated and searched using credential of the root by overriding and restoring the credentials of the caller requesting the key. Id mapping functions are invoked under config option of cifs acl. Signed-off-by: Shirish Pargaonkar <shirishpargaonkar@gmail.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/cifsacl.c138
-rw-r--r--fs/cifs/cifsfs.c29
-rw-r--r--fs/cifs/cifsglob.h5
-rw-r--r--fs/cifs/cifsproto.h3
4 files changed, 167 insertions, 8 deletions
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index a0d11eab14e5..061fc3afd841 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -23,6 +23,10 @@
23 23
24#include <linux/fs.h> 24#include <linux/fs.h>
25#include <linux/slab.h> 25#include <linux/slab.h>
26#include <linux/string.h>
27#include <linux/keyctl.h>
28#include <linux/key-type.h>
29#include <keys/user-type.h>
26#include "cifspdu.h" 30#include "cifspdu.h"
27#include "cifsglob.h" 31#include "cifsglob.h"
28#include "cifsacl.h" 32#include "cifsacl.h"
@@ -50,6 +54,140 @@ static const struct cifs_sid sid_authusers = {
50/* group users */ 54/* group users */
51static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; 55static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
52 56
57static const struct cred *root_cred;
58
59/*
60 * Run idmap cache shrinker.
61 */
62static int
63cifs_idmap_shrinker(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask)
64{
65 /* Use a pruning scheme in a subsequent patch instead */
66 cifs_destroy_idmaptrees();
67 return 0;
68}
69
70static struct shrinker cifs_shrinker = {
71 .shrink = cifs_idmap_shrinker,
72 .seeks = DEFAULT_SEEKS,
73};
74
75static int
76cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen)
77{
78 char *payload;
79
80 payload = kmalloc(datalen, GFP_KERNEL);
81 if (!payload)
82 return -ENOMEM;
83
84 memcpy(payload, data, datalen);
85 key->payload.data = payload;
86 return 0;
87}
88
89static inline void
90cifs_idmap_key_destroy(struct key *key)
91{
92 kfree(key->payload.data);
93}
94
95static
96struct key_type cifs_idmap_key_type = {
97 .name = "cifs.cifs_idmap",
98 .instantiate = cifs_idmap_key_instantiate,
99 .destroy = cifs_idmap_key_destroy,
100 .describe = user_describe,
101 .match = user_match,
102};
103
104int
105init_cifs_idmap(void)
106{
107 struct cred *cred;
108 struct key *keyring;
109 int ret;
110
111 cFYI(1, "Registering the %s key type\n", cifs_idmap_key_type.name);
112
113 /* create an override credential set with a special thread keyring in
114 * which requests are cached
115 *
116 * this is used to prevent malicious redirections from being installed
117 * with add_key().
118 */
119 cred = prepare_kernel_cred(NULL);
120 if (!cred)
121 return -ENOMEM;
122
123 keyring = key_alloc(&key_type_keyring, ".cifs_idmap", 0, 0, cred,
124 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
125 KEY_USR_VIEW | KEY_USR_READ,
126 KEY_ALLOC_NOT_IN_QUOTA);
127 if (IS_ERR(keyring)) {
128 ret = PTR_ERR(keyring);
129 goto failed_put_cred;
130 }
131
132 ret = key_instantiate_and_link(keyring, NULL, 0, NULL, NULL);
133 if (ret < 0)
134 goto failed_put_key;
135
136 ret = register_key_type(&cifs_idmap_key_type);
137 if (ret < 0)
138 goto failed_put_key;
139
140 /* instruct request_key() to use this special keyring as a cache for
141 * the results it looks up */
142 cred->thread_keyring = keyring;
143 cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
144 root_cred = cred;
145
146 spin_lock_init(&siduidlock);
147 uidtree = RB_ROOT;
148 spin_lock_init(&sidgidlock);
149 gidtree = RB_ROOT;
150
151 register_shrinker(&cifs_shrinker);
152
153 cFYI(1, "cifs idmap keyring: %d\n", key_serial(keyring));
154 return 0;
155
156failed_put_key:
157 key_put(keyring);
158failed_put_cred:
159 put_cred(cred);
160 return ret;
161}
162
163void
164exit_cifs_idmap(void)
165{
166 key_revoke(root_cred->thread_keyring);
167 unregister_key_type(&cifs_idmap_key_type);
168 put_cred(root_cred);
169 unregister_shrinker(&cifs_shrinker);
170 cFYI(1, "Unregistered %s key type\n", cifs_idmap_key_type.name);
171}
172
173void
174cifs_destroy_idmaptrees(void)
175{
176 struct rb_root *root;
177 struct rb_node *node;
178
179 root = &uidtree;
180 spin_lock(&siduidlock);
181 while ((node = rb_first(root)))
182 rb_erase(node, root);
183 spin_unlock(&siduidlock);
184
185 root = &gidtree;
186 spin_lock(&sidgidlock);
187 while ((node = rb_first(root)))
188 rb_erase(node, root);
189 spin_unlock(&sidgidlock);
190}
53 191
54int match_sid(struct cifs_sid *ctsid) 192int match_sid(struct cifs_sid *ctsid)
55{ 193{
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 30fc505b7ef1..6c1d738418f1 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1033,22 +1033,31 @@ init_cifs(void)
1033 if (rc) 1033 if (rc)
1034 goto out_destroy_mids; 1034 goto out_destroy_mids;
1035 1035
1036 rc = register_filesystem(&cifs_fs_type);
1037 if (rc)
1038 goto out_destroy_request_bufs;
1039#ifdef CONFIG_CIFS_UPCALL 1036#ifdef CONFIG_CIFS_UPCALL
1040 rc = register_key_type(&cifs_spnego_key_type); 1037 rc = register_key_type(&cifs_spnego_key_type);
1041 if (rc) 1038 if (rc)
1042 goto out_unregister_filesystem; 1039 goto out_destroy_request_bufs;
1043#endif 1040#endif /* CONFIG_CIFS_UPCALL */
1041
1042#ifdef CONFIG_CIFS_ACL
1043 rc = init_cifs_idmap();
1044 if (rc)
1045 goto out_destroy_request_bufs;
1046#endif /* CONFIG_CIFS_ACL */
1047
1048 rc = register_filesystem(&cifs_fs_type);
1049 if (rc)
1050 goto out_destroy_request_bufs;
1044 1051
1045 return 0; 1052 return 0;
1046 1053
1054out_destroy_request_bufs:
1055#ifdef CONFIG_CIFS_ACL
1056 exit_cifs_idmap();
1057#endif
1047#ifdef CONFIG_CIFS_UPCALL 1058#ifdef CONFIG_CIFS_UPCALL
1048out_unregister_filesystem: 1059 unregister_key_type(&cifs_spnego_key_type);
1049 unregister_filesystem(&cifs_fs_type);
1050#endif 1060#endif
1051out_destroy_request_bufs:
1052 cifs_destroy_request_bufs(); 1061 cifs_destroy_request_bufs();
1053out_destroy_mids: 1062out_destroy_mids:
1054 cifs_destroy_mids(); 1063 cifs_destroy_mids();
@@ -1070,6 +1079,10 @@ exit_cifs(void)
1070#ifdef CONFIG_CIFS_DFS_UPCALL 1079#ifdef CONFIG_CIFS_DFS_UPCALL
1071 cifs_dfs_release_automount_timer(); 1080 cifs_dfs_release_automount_timer();
1072#endif 1081#endif
1082#ifdef CONFIG_CIFS_ACL
1083 cifs_destroy_idmaptrees();
1084 exit_cifs_idmap();
1085#endif
1073#ifdef CONFIG_CIFS_UPCALL 1086#ifdef CONFIG_CIFS_UPCALL
1074 unregister_key_type(&cifs_spnego_key_type); 1087 unregister_key_type(&cifs_spnego_key_type);
1075#endif 1088#endif
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 108a1e99aa9f..76b4517e74b0 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -833,6 +833,11 @@ GLOBAL_EXTERN unsigned int cifs_max_pending; /* MAX requests at once to server*/
833/* reconnect after this many failed echo attempts */ 833/* reconnect after this many failed echo attempts */
834GLOBAL_EXTERN unsigned short echo_retries; 834GLOBAL_EXTERN unsigned short echo_retries;
835 835
836GLOBAL_EXTERN struct rb_root uidtree;
837GLOBAL_EXTERN struct rb_root gidtree;
838GLOBAL_EXTERN spinlock_t siduidlock;
839GLOBAL_EXTERN spinlock_t sidgidlock;
840
836void cifs_oplock_break(struct work_struct *work); 841void cifs_oplock_break(struct work_struct *work);
837void cifs_oplock_break_get(struct cifsFileInfo *cfile); 842void cifs_oplock_break_get(struct cifsFileInfo *cfile);
838void cifs_oplock_break_put(struct cifsFileInfo *cfile); 843void cifs_oplock_break_put(struct cifsFileInfo *cfile);
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 0e4e057e2891..7c1ed01d03f8 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -53,6 +53,9 @@ do { \
53 cFYI(1, "CIFS VFS: leaving %s (xid = %d) rc = %d", \ 53 cFYI(1, "CIFS VFS: leaving %s (xid = %d) rc = %d", \
54 __func__, curr_xid, (int)rc); \ 54 __func__, curr_xid, (int)rc); \
55} while (0) 55} while (0)
56extern int init_cifs_idmap(void);
57extern void exit_cifs_idmap(void);
58extern void cifs_destroy_idmaptrees(void);
56extern char *build_path_from_dentry(struct dentry *); 59extern char *build_path_from_dentry(struct dentry *);
57extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb, 60extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb,
58 struct cifsTconInfo *tcon); 61 struct cifsTconInfo *tcon);