Commit | Line | Data |
---|---|---|
d7e09d03 PT |
1 | /* |
2 | * GPL HEADER START | |
3 | * | |
4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License version 2 only, | |
8 | * as published by the Free Software Foundation. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, but | |
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * General Public License version 2 for more details (a copy is included | |
14 | * in the LICENSE file that accompanied this code). | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * version 2 along with this program; If not, see | |
18 | * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf | |
19 | * | |
20 | * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
21 | * CA 95054 USA or visit www.sun.com if you need additional information or | |
22 | * have any questions. | |
23 | * | |
24 | * GPL HEADER END | |
25 | */ | |
26 | /* | |
27 | * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. | |
28 | * Use is subject to license terms. | |
29 | */ | |
30 | /* | |
31 | * This file is part of Lustre, http://www.lustre.org/ | |
32 | * Lustre is a trademark of Sun Microsystems, Inc. | |
33 | * | |
34 | * lustre/ptlrpc/gss/gss_bulk.c | |
35 | * | |
36 | * Author: Eric Mei <eric.mei@sun.com> | |
37 | */ | |
38 | ||
39 | #define DEBUG_SUBSYSTEM S_SEC | |
40 | #include <linux/init.h> | |
41 | #include <linux/module.h> | |
42 | #include <linux/slab.h> | |
43 | #include <linux/dcache.h> | |
44 | #include <linux/fs.h> | |
45 | #include <linux/mutex.h> | |
46 | #include <linux/crypto.h> | |
47 | ||
48 | #include <obd.h> | |
49 | #include <obd_class.h> | |
50 | #include <obd_support.h> | |
51 | #include <lustre/lustre_idl.h> | |
52 | #include <lustre_net.h> | |
53 | #include <lustre_import.h> | |
54 | #include <lustre_sec.h> | |
55 | ||
56 | #include "gss_err.h" | |
57 | #include "gss_internal.h" | |
58 | #include "gss_api.h" | |
59 | ||
60 | int gss_cli_ctx_wrap_bulk(struct ptlrpc_cli_ctx *ctx, | |
61 | struct ptlrpc_request *req, | |
62 | struct ptlrpc_bulk_desc *desc) | |
63 | { | |
64 | struct gss_cli_ctx *gctx; | |
65 | struct lustre_msg *msg; | |
66 | struct ptlrpc_bulk_sec_desc *bsd; | |
67 | rawobj_t token; | |
68 | __u32 maj; | |
69 | int offset; | |
70 | int rc; | |
d7e09d03 PT |
71 | |
72 | LASSERT(req->rq_pack_bulk); | |
73 | LASSERT(req->rq_bulk_read || req->rq_bulk_write); | |
74 | ||
75 | gctx = container_of(ctx, struct gss_cli_ctx, gc_base); | |
76 | LASSERT(gctx->gc_mechctx); | |
77 | ||
78 | switch (SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc)) { | |
79 | case SPTLRPC_SVC_NULL: | |
80 | LASSERT(req->rq_reqbuf->lm_bufcount >= 3); | |
81 | msg = req->rq_reqbuf; | |
82 | offset = msg->lm_bufcount - 1; | |
83 | break; | |
84 | case SPTLRPC_SVC_AUTH: | |
85 | case SPTLRPC_SVC_INTG: | |
86 | LASSERT(req->rq_reqbuf->lm_bufcount >= 4); | |
87 | msg = req->rq_reqbuf; | |
88 | offset = msg->lm_bufcount - 2; | |
89 | break; | |
90 | case SPTLRPC_SVC_PRIV: | |
91 | LASSERT(req->rq_clrbuf->lm_bufcount >= 2); | |
92 | msg = req->rq_clrbuf; | |
93 | offset = msg->lm_bufcount - 1; | |
94 | break; | |
95 | default: | |
96 | LBUG(); | |
97 | } | |
98 | ||
99 | bsd = lustre_msg_buf(msg, offset, sizeof(*bsd)); | |
100 | bsd->bsd_version = 0; | |
101 | bsd->bsd_flags = 0; | |
102 | bsd->bsd_type = SPTLRPC_BULK_DEFAULT; | |
103 | bsd->bsd_svc = SPTLRPC_FLVR_BULK_SVC(req->rq_flvr.sf_rpc); | |
104 | ||
105 | if (bsd->bsd_svc == SPTLRPC_BULK_SVC_NULL) | |
0a3bdb00 | 106 | return 0; |
d7e09d03 PT |
107 | |
108 | LASSERT(bsd->bsd_svc == SPTLRPC_BULK_SVC_INTG || | |
109 | bsd->bsd_svc == SPTLRPC_BULK_SVC_PRIV); | |
110 | ||
111 | if (req->rq_bulk_read) { | |
112 | /* | |
113 | * bulk read: prepare receiving pages only for privacy mode. | |
114 | */ | |
115 | if (bsd->bsd_svc == SPTLRPC_BULK_SVC_PRIV) | |
116 | return gss_cli_prep_bulk(req, desc); | |
117 | } else { | |
118 | /* | |
119 | * bulk write: sign or encrypt bulk pages. | |
120 | */ | |
121 | bsd->bsd_nob = desc->bd_nob; | |
122 | ||
123 | if (bsd->bsd_svc == SPTLRPC_BULK_SVC_INTG) { | |
124 | /* integrity mode */ | |
125 | token.data = bsd->bsd_data; | |
126 | token.len = lustre_msg_buflen(msg, offset) - | |
127 | sizeof(*bsd); | |
128 | ||
129 | maj = lgss_get_mic(gctx->gc_mechctx, 0, NULL, | |
130 | desc->bd_iov_count, desc->bd_iov, | |
131 | &token); | |
132 | if (maj != GSS_S_COMPLETE) { | |
133 | CWARN("failed to sign bulk data: %x\n", maj); | |
0a3bdb00 | 134 | return -EACCES; |
d7e09d03 PT |
135 | } |
136 | } else { | |
137 | /* privacy mode */ | |
138 | if (desc->bd_iov_count == 0) | |
0a3bdb00 | 139 | return 0; |
d7e09d03 PT |
140 | |
141 | rc = sptlrpc_enc_pool_get_pages(desc); | |
142 | if (rc) { | |
143 | CERROR("bulk write: failed to allocate " | |
144 | "encryption pages: %d\n", rc); | |
0a3bdb00 | 145 | return rc; |
d7e09d03 PT |
146 | } |
147 | ||
148 | token.data = bsd->bsd_data; | |
149 | token.len = lustre_msg_buflen(msg, offset) - | |
150 | sizeof(*bsd); | |
151 | ||
152 | maj = lgss_wrap_bulk(gctx->gc_mechctx, desc, &token, 0); | |
153 | if (maj != GSS_S_COMPLETE) { | |
154 | CWARN("fail to encrypt bulk data: %x\n", maj); | |
0a3bdb00 | 155 | return -EACCES; |
d7e09d03 PT |
156 | } |
157 | } | |
158 | } | |
159 | ||
0a3bdb00 | 160 | return 0; |
d7e09d03 PT |
161 | } |
162 | ||
163 | int gss_cli_ctx_unwrap_bulk(struct ptlrpc_cli_ctx *ctx, | |
164 | struct ptlrpc_request *req, | |
165 | struct ptlrpc_bulk_desc *desc) | |
166 | { | |
167 | struct gss_cli_ctx *gctx; | |
168 | struct lustre_msg *rmsg, *vmsg; | |
169 | struct ptlrpc_bulk_sec_desc *bsdr, *bsdv; | |
170 | rawobj_t token; | |
171 | __u32 maj; | |
172 | int roff, voff; | |
d7e09d03 PT |
173 | |
174 | LASSERT(req->rq_pack_bulk); | |
175 | LASSERT(req->rq_bulk_read || req->rq_bulk_write); | |
176 | ||
177 | switch (SPTLRPC_FLVR_SVC(req->rq_flvr.sf_rpc)) { | |
178 | case SPTLRPC_SVC_NULL: | |
179 | vmsg = req->rq_repdata; | |
180 | voff = vmsg->lm_bufcount - 1; | |
181 | LASSERT(vmsg && vmsg->lm_bufcount >= 3); | |
182 | ||
183 | rmsg = req->rq_reqbuf; | |
184 | roff = rmsg->lm_bufcount - 1; /* last segment */ | |
185 | LASSERT(rmsg && rmsg->lm_bufcount >= 3); | |
186 | break; | |
187 | case SPTLRPC_SVC_AUTH: | |
188 | case SPTLRPC_SVC_INTG: | |
189 | vmsg = req->rq_repdata; | |
190 | voff = vmsg->lm_bufcount - 2; | |
191 | LASSERT(vmsg && vmsg->lm_bufcount >= 4); | |
192 | ||
193 | rmsg = req->rq_reqbuf; | |
194 | roff = rmsg->lm_bufcount - 2; /* second last segment */ | |
195 | LASSERT(rmsg && rmsg->lm_bufcount >= 4); | |
196 | break; | |
197 | case SPTLRPC_SVC_PRIV: | |
198 | vmsg = req->rq_repdata; | |
199 | voff = vmsg->lm_bufcount - 1; | |
200 | LASSERT(vmsg && vmsg->lm_bufcount >= 2); | |
201 | ||
202 | rmsg = req->rq_clrbuf; | |
203 | roff = rmsg->lm_bufcount - 1; /* last segment */ | |
204 | LASSERT(rmsg && rmsg->lm_bufcount >= 2); | |
205 | break; | |
206 | default: | |
207 | LBUG(); | |
208 | } | |
209 | ||
210 | bsdr = lustre_msg_buf(rmsg, roff, sizeof(*bsdr)); | |
211 | bsdv = lustre_msg_buf(vmsg, voff, sizeof(*bsdv)); | |
212 | LASSERT(bsdr && bsdv); | |
213 | ||
214 | if (bsdr->bsd_version != bsdv->bsd_version || | |
215 | bsdr->bsd_type != bsdv->bsd_type || | |
216 | bsdr->bsd_svc != bsdv->bsd_svc) { | |
217 | CERROR("bulk security descriptor mismatch: " | |
218 | "(%u,%u,%u) != (%u,%u,%u)\n", | |
219 | bsdr->bsd_version, bsdr->bsd_type, bsdr->bsd_svc, | |
220 | bsdv->bsd_version, bsdv->bsd_type, bsdv->bsd_svc); | |
0a3bdb00 | 221 | return -EPROTO; |
d7e09d03 PT |
222 | } |
223 | ||
224 | LASSERT(bsdv->bsd_svc == SPTLRPC_BULK_SVC_NULL || | |
225 | bsdv->bsd_svc == SPTLRPC_BULK_SVC_INTG || | |
226 | bsdv->bsd_svc == SPTLRPC_BULK_SVC_PRIV); | |
227 | ||
228 | /* | |
229 | * in privacy mode if return success, make sure bd_nob_transferred | |
230 | * is the actual size of the clear text, otherwise upper layer | |
231 | * may be surprised. | |
232 | */ | |
233 | if (req->rq_bulk_write) { | |
234 | if (bsdv->bsd_flags & BSD_FL_ERR) { | |
235 | CERROR("server reported bulk i/o failure\n"); | |
0a3bdb00 | 236 | return -EIO; |
d7e09d03 PT |
237 | } |
238 | ||
239 | if (bsdv->bsd_svc == SPTLRPC_BULK_SVC_PRIV) | |
240 | desc->bd_nob_transferred = desc->bd_nob; | |
241 | } else { | |
242 | /* | |
243 | * bulk read, upon return success, bd_nob_transferred is | |
244 | * the size of plain text actually received. | |
245 | */ | |
246 | gctx = container_of(ctx, struct gss_cli_ctx, gc_base); | |
247 | LASSERT(gctx->gc_mechctx); | |
248 | ||
249 | if (bsdv->bsd_svc == SPTLRPC_BULK_SVC_INTG) { | |
250 | int i, nob; | |
251 | ||
252 | /* fix the actual data size */ | |
253 | for (i = 0, nob = 0; i < desc->bd_iov_count; i++) { | |
254 | if (desc->bd_iov[i].kiov_len + nob > | |
255 | desc->bd_nob_transferred) { | |
256 | desc->bd_iov[i].kiov_len = | |
257 | desc->bd_nob_transferred - nob; | |
258 | } | |
259 | nob += desc->bd_iov[i].kiov_len; | |
260 | } | |
261 | ||
262 | token.data = bsdv->bsd_data; | |
263 | token.len = lustre_msg_buflen(vmsg, voff) - | |
264 | sizeof(*bsdv); | |
265 | ||
266 | maj = lgss_verify_mic(gctx->gc_mechctx, 0, NULL, | |
267 | desc->bd_iov_count, desc->bd_iov, | |
268 | &token); | |
269 | if (maj != GSS_S_COMPLETE) { | |
270 | CERROR("failed to verify bulk read: %x\n", maj); | |
0a3bdb00 | 271 | return -EACCES; |
d7e09d03 PT |
272 | } |
273 | } else if (bsdv->bsd_svc == SPTLRPC_BULK_SVC_PRIV) { | |
274 | desc->bd_nob = bsdv->bsd_nob; | |
275 | if (desc->bd_nob == 0) | |
0a3bdb00 | 276 | return 0; |
d7e09d03 PT |
277 | |
278 | token.data = bsdv->bsd_data; | |
279 | token.len = lustre_msg_buflen(vmsg, voff) - | |
280 | sizeof(*bsdr); | |
281 | ||
282 | maj = lgss_unwrap_bulk(gctx->gc_mechctx, desc, | |
283 | &token, 1); | |
284 | if (maj != GSS_S_COMPLETE) { | |
285 | CERROR("failed to decrypt bulk read: %x\n", | |
286 | maj); | |
0a3bdb00 | 287 | return -EACCES; |
d7e09d03 PT |
288 | } |
289 | ||
290 | desc->bd_nob_transferred = desc->bd_nob; | |
291 | } | |
292 | } | |
293 | ||
0a3bdb00 | 294 | return 0; |
d7e09d03 PT |
295 | } |
296 | ||
297 | static int gss_prep_bulk(struct ptlrpc_bulk_desc *desc, | |
298 | struct gss_ctx *mechctx) | |
299 | { | |
300 | int rc; | |
301 | ||
302 | if (desc->bd_iov_count == 0) | |
303 | return 0; | |
304 | ||
305 | rc = sptlrpc_enc_pool_get_pages(desc); | |
306 | if (rc) | |
307 | return rc; | |
308 | ||
309 | if (lgss_prep_bulk(mechctx, desc) != GSS_S_COMPLETE) | |
310 | return -EACCES; | |
311 | ||
312 | return 0; | |
313 | } | |
314 | ||
315 | int gss_cli_prep_bulk(struct ptlrpc_request *req, | |
316 | struct ptlrpc_bulk_desc *desc) | |
317 | { | |
318 | int rc; | |
d7e09d03 PT |
319 | |
320 | LASSERT(req->rq_cli_ctx); | |
321 | LASSERT(req->rq_pack_bulk); | |
322 | LASSERT(req->rq_bulk_read); | |
323 | ||
324 | if (SPTLRPC_FLVR_BULK_SVC(req->rq_flvr.sf_rpc) != SPTLRPC_BULK_SVC_PRIV) | |
0a3bdb00 | 325 | return 0; |
d7e09d03 PT |
326 | |
327 | rc = gss_prep_bulk(desc, ctx2gctx(req->rq_cli_ctx)->gc_mechctx); | |
328 | if (rc) | |
329 | CERROR("bulk read: failed to prepare encryption " | |
330 | "pages: %d\n", rc); | |
331 | ||
0a3bdb00 | 332 | return rc; |
d7e09d03 PT |
333 | } |
334 | ||
335 | int gss_svc_prep_bulk(struct ptlrpc_request *req, | |
336 | struct ptlrpc_bulk_desc *desc) | |
337 | { | |
338 | struct gss_svc_reqctx *grctx; | |
339 | struct ptlrpc_bulk_sec_desc *bsd; | |
340 | int rc; | |
d7e09d03 PT |
341 | |
342 | LASSERT(req->rq_svc_ctx); | |
343 | LASSERT(req->rq_pack_bulk); | |
344 | LASSERT(req->rq_bulk_write); | |
345 | ||
346 | grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx); | |
347 | LASSERT(grctx->src_reqbsd); | |
348 | LASSERT(grctx->src_repbsd); | |
349 | LASSERT(grctx->src_ctx); | |
350 | LASSERT(grctx->src_ctx->gsc_mechctx); | |
351 | ||
352 | bsd = grctx->src_reqbsd; | |
353 | if (bsd->bsd_svc != SPTLRPC_BULK_SVC_PRIV) | |
0a3bdb00 | 354 | return 0; |
d7e09d03 PT |
355 | |
356 | rc = gss_prep_bulk(desc, grctx->src_ctx->gsc_mechctx); | |
357 | if (rc) | |
358 | CERROR("bulk write: failed to prepare encryption " | |
359 | "pages: %d\n", rc); | |
360 | ||
0a3bdb00 | 361 | return rc; |
d7e09d03 PT |
362 | } |
363 | ||
364 | int gss_svc_unwrap_bulk(struct ptlrpc_request *req, | |
365 | struct ptlrpc_bulk_desc *desc) | |
366 | { | |
367 | struct gss_svc_reqctx *grctx; | |
368 | struct ptlrpc_bulk_sec_desc *bsdr, *bsdv; | |
369 | rawobj_t token; | |
370 | __u32 maj; | |
d7e09d03 PT |
371 | |
372 | LASSERT(req->rq_svc_ctx); | |
373 | LASSERT(req->rq_pack_bulk); | |
374 | LASSERT(req->rq_bulk_write); | |
375 | ||
376 | grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx); | |
377 | ||
378 | LASSERT(grctx->src_reqbsd); | |
379 | LASSERT(grctx->src_repbsd); | |
380 | LASSERT(grctx->src_ctx); | |
381 | LASSERT(grctx->src_ctx->gsc_mechctx); | |
382 | ||
383 | bsdr = grctx->src_reqbsd; | |
384 | bsdv = grctx->src_repbsd; | |
385 | ||
386 | /* bsdr has been sanity checked during unpacking */ | |
387 | bsdv->bsd_version = 0; | |
388 | bsdv->bsd_type = SPTLRPC_BULK_DEFAULT; | |
389 | bsdv->bsd_svc = bsdr->bsd_svc; | |
390 | bsdv->bsd_flags = 0; | |
391 | ||
392 | switch (bsdv->bsd_svc) { | |
393 | case SPTLRPC_BULK_SVC_INTG: | |
394 | token.data = bsdr->bsd_data; | |
395 | token.len = grctx->src_reqbsd_size - sizeof(*bsdr); | |
396 | ||
397 | maj = lgss_verify_mic(grctx->src_ctx->gsc_mechctx, 0, NULL, | |
398 | desc->bd_iov_count, desc->bd_iov, &token); | |
399 | if (maj != GSS_S_COMPLETE) { | |
400 | bsdv->bsd_flags |= BSD_FL_ERR; | |
401 | CERROR("failed to verify bulk signature: %x\n", maj); | |
0a3bdb00 | 402 | return -EACCES; |
d7e09d03 PT |
403 | } |
404 | break; | |
405 | case SPTLRPC_BULK_SVC_PRIV: | |
406 | if (bsdr->bsd_nob != desc->bd_nob) { | |
407 | bsdv->bsd_flags |= BSD_FL_ERR; | |
408 | CERROR("prepared nob %d doesn't match the actual " | |
409 | "nob %d\n", desc->bd_nob, bsdr->bsd_nob); | |
0a3bdb00 | 410 | return -EPROTO; |
d7e09d03 PT |
411 | } |
412 | ||
413 | if (desc->bd_iov_count == 0) { | |
414 | LASSERT(desc->bd_nob == 0); | |
415 | break; | |
416 | } | |
417 | ||
418 | token.data = bsdr->bsd_data; | |
419 | token.len = grctx->src_reqbsd_size - sizeof(*bsdr); | |
420 | ||
421 | maj = lgss_unwrap_bulk(grctx->src_ctx->gsc_mechctx, | |
422 | desc, &token, 0); | |
423 | if (maj != GSS_S_COMPLETE) { | |
424 | bsdv->bsd_flags |= BSD_FL_ERR; | |
425 | CERROR("failed decrypt bulk data: %x\n", maj); | |
0a3bdb00 | 426 | return -EACCES; |
d7e09d03 PT |
427 | } |
428 | break; | |
429 | } | |
430 | ||
0a3bdb00 | 431 | return 0; |
d7e09d03 PT |
432 | } |
433 | ||
434 | int gss_svc_wrap_bulk(struct ptlrpc_request *req, | |
435 | struct ptlrpc_bulk_desc *desc) | |
436 | { | |
437 | struct gss_svc_reqctx *grctx; | |
438 | struct ptlrpc_bulk_sec_desc *bsdr, *bsdv; | |
439 | rawobj_t token; | |
440 | __u32 maj; | |
441 | int rc; | |
d7e09d03 PT |
442 | |
443 | LASSERT(req->rq_svc_ctx); | |
444 | LASSERT(req->rq_pack_bulk); | |
445 | LASSERT(req->rq_bulk_read); | |
446 | ||
447 | grctx = gss_svc_ctx2reqctx(req->rq_svc_ctx); | |
448 | ||
449 | LASSERT(grctx->src_reqbsd); | |
450 | LASSERT(grctx->src_repbsd); | |
451 | LASSERT(grctx->src_ctx); | |
452 | LASSERT(grctx->src_ctx->gsc_mechctx); | |
453 | ||
454 | bsdr = grctx->src_reqbsd; | |
455 | bsdv = grctx->src_repbsd; | |
456 | ||
457 | /* bsdr has been sanity checked during unpacking */ | |
458 | bsdv->bsd_version = 0; | |
459 | bsdv->bsd_type = SPTLRPC_BULK_DEFAULT; | |
460 | bsdv->bsd_svc = bsdr->bsd_svc; | |
461 | bsdv->bsd_flags = 0; | |
462 | ||
463 | switch (bsdv->bsd_svc) { | |
464 | case SPTLRPC_BULK_SVC_INTG: | |
465 | token.data = bsdv->bsd_data; | |
466 | token.len = grctx->src_repbsd_size - sizeof(*bsdv); | |
467 | ||
468 | maj = lgss_get_mic(grctx->src_ctx->gsc_mechctx, 0, NULL, | |
469 | desc->bd_iov_count, desc->bd_iov, &token); | |
470 | if (maj != GSS_S_COMPLETE) { | |
471 | bsdv->bsd_flags |= BSD_FL_ERR; | |
472 | CERROR("failed to sign bulk data: %x\n", maj); | |
0a3bdb00 | 473 | return -EACCES; |
d7e09d03 PT |
474 | } |
475 | break; | |
476 | case SPTLRPC_BULK_SVC_PRIV: | |
477 | bsdv->bsd_nob = desc->bd_nob; | |
478 | ||
479 | if (desc->bd_iov_count == 0) { | |
480 | LASSERT(desc->bd_nob == 0); | |
481 | break; | |
482 | } | |
483 | ||
484 | rc = sptlrpc_enc_pool_get_pages(desc); | |
485 | if (rc) { | |
486 | bsdv->bsd_flags |= BSD_FL_ERR; | |
487 | CERROR("bulk read: failed to allocate encryption " | |
488 | "pages: %d\n", rc); | |
0a3bdb00 | 489 | return rc; |
d7e09d03 PT |
490 | } |
491 | ||
492 | token.data = bsdv->bsd_data; | |
493 | token.len = grctx->src_repbsd_size - sizeof(*bsdv); | |
494 | ||
495 | maj = lgss_wrap_bulk(grctx->src_ctx->gsc_mechctx, | |
496 | desc, &token, 1); | |
497 | if (maj != GSS_S_COMPLETE) { | |
498 | bsdv->bsd_flags |= BSD_FL_ERR; | |
499 | CERROR("failed to encrypt bulk data: %x\n", maj); | |
0a3bdb00 | 500 | return -EACCES; |
d7e09d03 PT |
501 | } |
502 | break; | |
503 | } | |
504 | ||
0a3bdb00 | 505 | return 0; |
d7e09d03 | 506 | } |