Merge branch 'msm-core' of git://codeaurora.org/quic/kernel/dwalker/linux-msm
[pandora-kernel.git] / fs / ceph / auth.c
1 #include "ceph_debug.h"
2
3 #include <linux/module.h>
4 #include <linux/slab.h>
5 #include <linux/err.h>
6 #include <linux/slab.h>
7
8 #include "types.h"
9 #include "auth_none.h"
10 #include "auth_x.h"
11 #include "decode.h"
12 #include "super.h"
13
14 #include "messenger.h"
15
16 /*
17  * get protocol handler
18  */
19 static u32 supported_protocols[] = {
20         CEPH_AUTH_NONE,
21         CEPH_AUTH_CEPHX
22 };
23
24 int ceph_auth_init_protocol(struct ceph_auth_client *ac, int protocol)
25 {
26         switch (protocol) {
27         case CEPH_AUTH_NONE:
28                 return ceph_auth_none_init(ac);
29         case CEPH_AUTH_CEPHX:
30                 return ceph_x_init(ac);
31         default:
32                 return -ENOENT;
33         }
34 }
35
36 /*
37  * setup, teardown.
38  */
39 struct ceph_auth_client *ceph_auth_init(const char *name, const char *secret)
40 {
41         struct ceph_auth_client *ac;
42         int ret;
43
44         dout("auth_init name '%s' secret '%s'\n", name, secret);
45
46         ret = -ENOMEM;
47         ac = kzalloc(sizeof(*ac), GFP_NOFS);
48         if (!ac)
49                 goto out;
50
51         ac->negotiating = true;
52         if (name)
53                 ac->name = name;
54         else
55                 ac->name = CEPH_AUTH_NAME_DEFAULT;
56         dout("auth_init name %s secret %s\n", ac->name, secret);
57         ac->secret = secret;
58         return ac;
59
60 out:
61         return ERR_PTR(ret);
62 }
63
64 void ceph_auth_destroy(struct ceph_auth_client *ac)
65 {
66         dout("auth_destroy %p\n", ac);
67         if (ac->ops)
68                 ac->ops->destroy(ac);
69         kfree(ac);
70 }
71
72 /*
73  * Reset occurs when reconnecting to the monitor.
74  */
75 void ceph_auth_reset(struct ceph_auth_client *ac)
76 {
77         dout("auth_reset %p\n", ac);
78         if (ac->ops && !ac->negotiating)
79                 ac->ops->reset(ac);
80         ac->negotiating = true;
81 }
82
83 int ceph_entity_name_encode(const char *name, void **p, void *end)
84 {
85         int len = strlen(name);
86
87         if (*p + 2*sizeof(u32) + len > end)
88                 return -ERANGE;
89         ceph_encode_32(p, CEPH_ENTITY_TYPE_CLIENT);
90         ceph_encode_32(p, len);
91         ceph_encode_copy(p, name, len);
92         return 0;
93 }
94
95 /*
96  * Initiate protocol negotiation with monitor.  Include entity name
97  * and list supported protocols.
98  */
99 int ceph_auth_build_hello(struct ceph_auth_client *ac, void *buf, size_t len)
100 {
101         struct ceph_mon_request_header *monhdr = buf;
102         void *p = monhdr + 1, *end = buf + len, *lenp;
103         int i, num;
104         int ret;
105
106         dout("auth_build_hello\n");
107         monhdr->have_version = 0;
108         monhdr->session_mon = cpu_to_le16(-1);
109         monhdr->session_mon_tid = 0;
110
111         ceph_encode_32(&p, 0);  /* no protocol, yet */
112
113         lenp = p;
114         p += sizeof(u32);
115
116         ceph_decode_need(&p, end, 1 + sizeof(u32), bad);
117         ceph_encode_8(&p, 1);
118         num = ARRAY_SIZE(supported_protocols);
119         ceph_encode_32(&p, num);
120         ceph_decode_need(&p, end, num * sizeof(u32), bad);
121         for (i = 0; i < num; i++)
122                 ceph_encode_32(&p, supported_protocols[i]);
123
124         ret = ceph_entity_name_encode(ac->name, &p, end);
125         if (ret < 0)
126                 return ret;
127         ceph_decode_need(&p, end, sizeof(u64), bad);
128         ceph_encode_64(&p, ac->global_id);
129
130         ceph_encode_32(&lenp, p - lenp - sizeof(u32));
131         return p - buf;
132
133 bad:
134         return -ERANGE;
135 }
136
137 int ceph_build_auth_request(struct ceph_auth_client *ac,
138                            void *msg_buf, size_t msg_len)
139 {
140         struct ceph_mon_request_header *monhdr = msg_buf;
141         void *p = monhdr + 1;
142         void *end = msg_buf + msg_len;
143         int ret;
144
145         monhdr->have_version = 0;
146         monhdr->session_mon = cpu_to_le16(-1);
147         monhdr->session_mon_tid = 0;
148
149         ceph_encode_32(&p, ac->protocol);
150
151         ret = ac->ops->build_request(ac, p + sizeof(u32), end);
152         if (ret < 0) {
153                 pr_err("error %d building request\n", ret);
154                 return ret;
155         }
156         dout(" built request %d bytes\n", ret);
157         ceph_encode_32(&p, ret);
158         return p + ret - msg_buf;
159 }
160
161 /*
162  * Handle auth message from monitor.
163  */
164 int ceph_handle_auth_reply(struct ceph_auth_client *ac,
165                            void *buf, size_t len,
166                            void *reply_buf, size_t reply_len)
167 {
168         void *p = buf;
169         void *end = buf + len;
170         int protocol;
171         s32 result;
172         u64 global_id;
173         void *payload, *payload_end;
174         int payload_len;
175         char *result_msg;
176         int result_msg_len;
177         int ret = -EINVAL;
178
179         dout("handle_auth_reply %p %p\n", p, end);
180         ceph_decode_need(&p, end, sizeof(u32) * 3 + sizeof(u64), bad);
181         protocol = ceph_decode_32(&p);
182         result = ceph_decode_32(&p);
183         global_id = ceph_decode_64(&p);
184         payload_len = ceph_decode_32(&p);
185         payload = p;
186         p += payload_len;
187         ceph_decode_need(&p, end, sizeof(u32), bad);
188         result_msg_len = ceph_decode_32(&p);
189         result_msg = p;
190         p += result_msg_len;
191         if (p != end)
192                 goto bad;
193
194         dout(" result %d '%.*s' gid %llu len %d\n", result, result_msg_len,
195              result_msg, global_id, payload_len);
196
197         payload_end = payload + payload_len;
198
199         if (global_id && ac->global_id != global_id) {
200                 dout(" set global_id %lld -> %lld\n", ac->global_id, global_id);
201                 ac->global_id = global_id;
202         }
203
204         if (ac->negotiating) {
205                 /* server does not support our protocols? */
206                 if (!protocol && result < 0) {
207                         ret = result;
208                         goto out;
209                 }
210                 /* set up (new) protocol handler? */
211                 if (ac->protocol && ac->protocol != protocol) {
212                         ac->ops->destroy(ac);
213                         ac->protocol = 0;
214                         ac->ops = NULL;
215                 }
216                 if (ac->protocol != protocol) {
217                         ret = ceph_auth_init_protocol(ac, protocol);
218                         if (ret) {
219                                 pr_err("error %d on auth protocol %d init\n",
220                                        ret, protocol);
221                                 goto out;
222                         }
223                 }
224
225                 ac->negotiating = false;
226         }
227
228         ret = ac->ops->handle_reply(ac, result, payload, payload_end);
229         if (ret == -EAGAIN) {
230                 return ceph_build_auth_request(ac, reply_buf, reply_len);
231         } else if (ret) {
232                 pr_err("authentication error %d\n", ret);
233                 return ret;
234         }
235         return 0;
236
237 bad:
238         pr_err("failed to decode auth msg\n");
239 out:
240         return ret;
241 }
242
243 int ceph_build_auth(struct ceph_auth_client *ac,
244                     void *msg_buf, size_t msg_len)
245 {
246         if (!ac->protocol)
247                 return ceph_auth_build_hello(ac, msg_buf, msg_len);
248         BUG_ON(!ac->ops);
249         if (!ac->ops->is_authenticated(ac))
250                 return ceph_build_auth_request(ac, msg_buf, msg_len);
251         return 0;
252 }
253
254 int ceph_auth_is_authenticated(struct ceph_auth_client *ac)
255 {
256         if (!ac->ops)
257                 return 0;
258         return ac->ops->is_authenticated(ac);
259 }