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