Whamcloud - gitweb
cede7916ba4471c16ef5cef68ebe917e6f85f3d9
[fs/lustre-release.git] / lustre / ptlrpc / gss / gss_bulk.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2006 Cluster File Systems, Inc.
5  *
6  *   This file is part of Lustre, http://www.lustre.org.
7  *
8  *   Lustre is free software; you can redistribute it and/or
9  *   modify it under the terms of version 2 of the GNU General Public
10  *   License as published by the Free Software Foundation.
11  *
12  *   Lustre is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with Lustre; if not, write to the Free Software
19  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #ifndef EXPORT_SYMTAB
23 # define EXPORT_SYMTAB
24 #endif
25 #define DEBUG_SUBSYSTEM S_SEC
26 #ifdef __KERNEL__
27 #include <linux/init.h>
28 #include <linux/module.h>
29 #include <linux/slab.h>
30 #include <linux/dcache.h>
31 #include <linux/fs.h>
32 #include <linux/random.h>
33 #include <linux/mutex.h>
34 #include <linux/crypto.h>
35 #else
36 #include <liblustre.h>
37 #endif
38
39 #include <obd.h>
40 #include <obd_class.h>
41 #include <obd_support.h>
42 #include <lustre/lustre_idl.h>
43 #include <lustre_net.h>
44 #include <lustre_import.h>
45 #include <lustre_sec.h>
46
47 #include "gss_err.h"
48 #include "gss_internal.h"
49 #include "gss_api.h"
50
51 static
52 int do_bulk_privacy(struct gss_ctx *gctx,
53                     struct ptlrpc_bulk_desc *desc,
54                     int encrypt, __u32 alg,
55                     struct ptlrpc_bulk_sec_desc *bsd)
56 {
57         struct crypto_tfm  *tfm;
58         struct scatterlist  sg, sg2, *sgd;
59         int                 i, rc;
60         __u8                local_iv[sizeof(bsd->bsd_iv)];
61
62         LASSERT(alg < BULK_PRIV_ALG_MAX);
63
64         if (encrypt)
65                 bsd->bsd_priv_alg = BULK_PRIV_ALG_NULL;
66
67         if (alg == BULK_PRIV_ALG_NULL)
68                 return 0;
69
70         if (encrypt)
71                 get_random_bytes(bsd->bsd_iv, sizeof(bsd->bsd_iv));
72
73         /* compute the secret iv */
74         lgss_plain_encrypt(gctx, sizeof(local_iv), bsd->bsd_iv, local_iv);
75
76         tfm = crypto_alloc_tfm(sptlrpc_bulk_priv_alg2name(alg),
77                                sptlrpc_bulk_priv_alg2flags(alg));
78         if (tfm == NULL) {
79                 CERROR("Failed to allocate TFM %s\n",
80                        sptlrpc_bulk_priv_alg2name(alg));
81                 return -ENOMEM;
82         }
83
84         rc = crypto_cipher_setkey(tfm, local_iv, sizeof(local_iv));
85         if (rc) {
86                 CERROR("Failed to set key for TFM %s: %d\n",
87                        sptlrpc_bulk_priv_alg2name(alg), rc);
88                 crypto_free_tfm(tfm);
89                 return rc;
90         }
91
92         for (i = 0; i < desc->bd_iov_count; i++) {
93                 sg.page = desc->bd_iov[i].kiov_page;
94                 sg.offset = desc->bd_iov[i].kiov_offset;
95                 sg.length = desc->bd_iov[i].kiov_len;
96
97                 if (desc->bd_enc_pages) {
98                         sg2.page = desc->bd_enc_pages[i];
99                         sg2.offset = desc->bd_iov[i].kiov_offset;
100                         sg2.length = desc->bd_iov[i].kiov_len;
101
102                         sgd = &sg2;
103                 } else
104                         sgd = &sg;
105
106                 if (encrypt)
107                         rc = crypto_cipher_encrypt(tfm, sgd, &sg, sg.length);
108                 else
109                         rc = crypto_cipher_decrypt(tfm, sgd, &sg, sg.length);
110
111                 LASSERT(rc == 0);
112
113                 if (desc->bd_enc_pages)
114                         desc->bd_iov[i].kiov_page = desc->bd_enc_pages[i];
115
116                 /* although the procedure might be lengthy, the crypto functions
117                  * internally called cond_resched() from time to time.
118                  */
119         }
120
121         crypto_free_tfm(tfm);
122
123         if (encrypt)
124                 bsd->bsd_priv_alg = alg;
125
126         return 0;
127 }
128
129 int gss_cli_ctx_wrap_bulk(struct ptlrpc_cli_ctx *ctx,
130                           struct ptlrpc_request *req,
131                           struct ptlrpc_bulk_desc *desc)
132 {
133         struct gss_cli_ctx              *gctx;
134         struct lustre_msg               *msg;
135         struct ptlrpc_bulk_sec_desc     *bsdr;
136         struct sec_flavor_config        *conf;
137         int                              offset, rc;
138         ENTRY;
139
140         LASSERT(SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor));
141         LASSERT(req->rq_bulk_read || req->rq_bulk_write);
142
143         switch (SEC_FLAVOR_SVC(req->rq_sec_flavor)) {
144         case SPTLRPC_SVC_AUTH:
145                 LASSERT(req->rq_reqbuf->lm_bufcount >= 4);
146                 msg = req->rq_reqbuf;
147                 offset = msg->lm_bufcount - 2;
148                 break;
149         case SPTLRPC_SVC_PRIV:
150                 LASSERT(req->rq_clrbuf->lm_bufcount >= 2);
151                 msg = req->rq_clrbuf;
152                 offset = msg->lm_bufcount - 1;
153                 break;
154         default:
155                 LBUG();
156         }
157
158         /* make checksum */
159         conf = &req->rq_import->imp_obd->u.cli.cl_sec_conf;
160         rc = bulk_csum_cli_request(desc, req->rq_bulk_read, conf->sfc_bulk_csum,
161                                    msg, offset);
162         if (rc) {
163                 CERROR("client bulk %s: failed to generate checksum: %d\n",
164                        req->rq_bulk_read ? "read" : "write", rc);
165                 RETURN(rc);
166         }
167
168         if (conf->sfc_bulk_priv == BULK_PRIV_ALG_NULL)
169                 RETURN(0);
170
171         /* previous bulk_csum_cli_request() has verified bsdr is good */
172         bsdr = lustre_msg_buf(msg, offset, 0);
173
174         if (req->rq_bulk_read) {
175                 bsdr->bsd_priv_alg = conf->sfc_bulk_priv;
176                 RETURN(0);
177         }
178
179         /* it turn out to be bulk write */
180         rc = sptlrpc_enc_pool_get_pages(desc);
181         if (rc) {
182                 CERROR("bulk write: failed to allocate encryption pages\n");
183                 RETURN(rc);
184         }
185
186         gctx = container_of(ctx, struct gss_cli_ctx, gc_base);
187         LASSERT(gctx->gc_mechctx);
188
189         rc = do_bulk_privacy(gctx->gc_mechctx, desc, 1,
190                              conf->sfc_bulk_priv, bsdr);
191         if (rc)
192                 CERROR("bulk write: client failed to encrypt pages\n");
193
194         RETURN(rc);
195 }
196
197 int gss_cli_ctx_unwrap_bulk(struct ptlrpc_cli_ctx *ctx,
198                             struct ptlrpc_request *req,
199                             struct ptlrpc_bulk_desc *desc)
200 {
201         struct gss_cli_ctx              *gctx;
202         struct lustre_msg               *rmsg, *vmsg;
203         struct ptlrpc_bulk_sec_desc     *bsdr, *bsdv;
204         int                              roff, voff, rc;
205         ENTRY;
206
207         LASSERT(SEC_FLAVOR_HAS_BULK(req->rq_sec_flavor));
208         LASSERT(req->rq_bulk_read || req->rq_bulk_write);
209
210         switch (SEC_FLAVOR_SVC(req->rq_sec_flavor)) {
211         case SPTLRPC_SVC_AUTH:
212                 vmsg = req->rq_repbuf;
213                 voff = vmsg->lm_bufcount - 2;
214                 LASSERT(vmsg && vmsg->lm_bufcount >= 4);
215
216                 rmsg = req->rq_reqbuf;
217                 roff = rmsg->lm_bufcount - 2; /* second last segment */
218                 LASSERT(rmsg && rmsg->lm_bufcount >= 4);
219                 break;
220         case SPTLRPC_SVC_PRIV:
221                 vmsg = req->rq_repbuf;
222                 voff = vmsg->lm_bufcount - 1;
223                 LASSERT(vmsg && vmsg->lm_bufcount >= 2);
224
225                 rmsg = req->rq_clrbuf;
226                 roff = rmsg->lm_bufcount - 1; /* last segment */
227                 LASSERT(rmsg && rmsg->lm_bufcount >= 2);
228                 break;
229         default:
230                 LBUG();
231         }
232
233         if (req->rq_bulk_read) {
234                 bsdr = lustre_msg_buf(rmsg, roff, 0);
235                 if (bsdr->bsd_priv_alg == BULK_PRIV_ALG_NULL)
236                         goto verify_csum;
237
238                 bsdv = lustre_msg_buf(vmsg, voff, 0);
239                 if (bsdr->bsd_priv_alg != bsdv->bsd_priv_alg) {
240                         CERROR("bulk read: cipher algorithm mismatch: client "
241                                "request %s but server reply with %s. try to "
242                                "use the new one for decryption\n",
243                                sptlrpc_bulk_priv_alg2name(bsdr->bsd_priv_alg),
244                                sptlrpc_bulk_priv_alg2name(bsdv->bsd_priv_alg));
245                 }
246
247                 gctx = container_of(ctx, struct gss_cli_ctx, gc_base);
248                 LASSERT(gctx->gc_mechctx);
249
250                 rc = do_bulk_privacy(gctx->gc_mechctx, desc, 0,
251                                      bsdv->bsd_priv_alg, bsdv);
252                 if (rc) {
253                         CERROR("bulk read: client failed to decrypt data\n");
254                         RETURN(rc);
255                 }
256         }
257
258 verify_csum:
259         rc = bulk_csum_cli_reply(desc, req->rq_bulk_read,
260                                  rmsg, roff, vmsg, voff);
261         RETURN(rc);
262 }
263
264 int gss_svc_unwrap_bulk(struct ptlrpc_request *req,
265                         struct ptlrpc_bulk_desc *desc)
266 {
267         struct ptlrpc_reply_state    *rs = req->rq_reply_state;
268         struct gss_svc_reqctx        *grctx;
269         struct ptlrpc_bulk_sec_desc  *bsdv;
270         int                           voff, roff, rc;
271         ENTRY;
272
273         LASSERT(rs);
274         LASSERT(req->rq_bulk_write);
275
276         if (SEC_FLAVOR_SVC(req->rq_sec_flavor) == SPTLRPC_SVC_PRIV) {
277                 LASSERT(req->rq_reqbuf->lm_bufcount >= 2);
278                 LASSERT(rs->rs_repbuf->lm_bufcount >= 2);
279                 voff = req->rq_reqbuf->lm_bufcount - 1;
280                 roff = rs->rs_repbuf->lm_bufcount - 1;
281         } else {
282                 LASSERT(req->rq_reqbuf->lm_bufcount >= 4);
283                 LASSERT(rs->rs_repbuf->lm_bufcount >= 4);
284                 voff = req->rq_reqbuf->lm_bufcount - 2;
285                 roff = rs->rs_repbuf->lm_bufcount - 2;
286         }
287
288         bsdv = lustre_msg_buf(req->rq_reqbuf, voff, sizeof(*bsdv));
289         if (bsdv->bsd_priv_alg != BULK_PRIV_ALG_NULL) {
290                 grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
291                 LASSERT(grctx->src_ctx);
292                 LASSERT(grctx->src_ctx->gsc_mechctx);
293
294                 rc = do_bulk_privacy(grctx->src_ctx->gsc_mechctx, desc, 0,
295                                      bsdv->bsd_priv_alg, bsdv);
296                 if (rc) {
297                         CERROR("bulk write: server failed to decrypt data\n");
298                         RETURN(rc);
299                 }
300         }
301
302         rc = bulk_csum_svc(desc, req->rq_bulk_read,
303                            req->rq_reqbuf, voff, rs->rs_repbuf, roff);
304
305         RETURN(rc);
306 }
307
308 int gss_svc_wrap_bulk(struct ptlrpc_request *req,
309                       struct ptlrpc_bulk_desc *desc)
310 {
311         struct ptlrpc_reply_state    *rs = req->rq_reply_state;
312         struct gss_svc_reqctx        *grctx;
313         struct ptlrpc_bulk_sec_desc  *bsdv, *bsdr;
314         int                           voff, roff, rc;
315         ENTRY;
316
317         LASSERT(rs);
318         LASSERT(req->rq_bulk_read);
319
320         if (SEC_FLAVOR_SVC(req->rq_sec_flavor) == SPTLRPC_SVC_PRIV) {
321                 voff = req->rq_reqbuf->lm_bufcount - 1;
322                 roff = rs->rs_repbuf->lm_bufcount - 1;
323         } else {
324                 voff = req->rq_reqbuf->lm_bufcount - 2;
325                 roff = rs->rs_repbuf->lm_bufcount - 2;
326         }
327
328         rc = bulk_csum_svc(desc, req->rq_bulk_read,
329                            req->rq_reqbuf, voff, rs->rs_repbuf, roff);
330         if (rc)
331                 RETURN(rc);
332
333         bsdv = lustre_msg_buf(req->rq_reqbuf, voff, sizeof(*bsdv));
334         if (bsdv->bsd_priv_alg != BULK_PRIV_ALG_NULL) {
335                 grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx);
336                 LASSERT(grctx->src_ctx);
337                 LASSERT(grctx->src_ctx->gsc_mechctx);
338
339                 bsdr = lustre_msg_buf(rs->rs_repbuf, roff, sizeof(*bsdr));
340
341                 rc = do_bulk_privacy(grctx->src_ctx->gsc_mechctx, desc, 1,
342                                      bsdv->bsd_priv_alg, bsdr);
343                 if (rc)
344                         CERROR("bulk read: server failed to encrypt data\n");
345         }
346
347         RETURN(rc);
348 }
349