Whamcloud - gitweb
78a6276dbe826b5cb46740b4c3e41790b96ffdbd
[fs/lustre-release.git] / lustre / sec / svcsec.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Copyright (C) 2004 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 #else
31 #include <liblustre.h>
32 #endif
33
34 #include <libcfs/kp30.h>
35 #include <linux/obd_support.h>
36 #include <linux/lustre_idl.h>
37 #include <linux/lustre_net.h>
38 #include <linux/lustre_sec.h>
39
40 static spinlock_t svcsecs_lock = SPIN_LOCK_UNLOCKED;
41 static struct ptlrpc_svcsec *svcsecs[PTLRPC_SEC_MAX_FLAVORS] = {
42         NULL,
43 };
44
45 int svcsec_register(struct ptlrpc_svcsec *sec)
46 {
47         __u32 flavor = sec->pss_flavor.flavor;
48
49         if (flavor >= PTLRPC_SEC_MAX_FLAVORS)
50                 return -EINVAL;
51
52         spin_lock(&svcsecs_lock);
53         if (svcsecs[flavor]) {
54                 spin_unlock(&svcsecs_lock);
55                 return -EALREADY;
56         }
57         svcsecs[flavor] = sec;
58         spin_unlock(&svcsecs_lock);
59
60         CDEBUG(D_SEC, "Registered svc security module %s\n", sec->pss_name);
61         return 0;
62 }
63
64 int svcsec_unregister(struct ptlrpc_svcsec *sec)
65 {
66         __u32 flavor = sec->pss_flavor.flavor;
67
68         if (flavor >= PTLRPC_SEC_MAX_FLAVORS)
69                 return -EINVAL;
70
71         spin_lock(&svcsecs_lock);
72         if (!svcsecs[flavor]) {
73                 spin_unlock(&svcsecs_lock);
74                 return -EINVAL;
75         }
76
77         LASSERT(svcsecs[flavor] == sec);
78
79         CDEBUG(D_SEC, "Unregistered svc security module %s\n", sec->pss_name);
80         svcsecs[flavor] = NULL;
81         spin_unlock(&svcsecs_lock);
82
83         return 0;
84 }
85
86 static
87 struct ptlrpc_svcsec * flavor2svcsec(__u32 flavor)
88 {
89         struct ptlrpc_svcsec *sec;
90
91         if (flavor >= PTLRPC_SEC_MAX_FLAVORS)
92                 return NULL;
93
94         spin_lock(&svcsecs_lock);
95         sec = svcsecs[flavor];
96         if (sec && !try_module_get(sec->pss_owner))
97                 sec = NULL;
98         spin_unlock(&svcsecs_lock);
99         return sec;
100 }
101
102 struct ptlrpc_svcsec * svcsec_get(struct ptlrpc_svcsec *sec)
103 {
104         int rc;
105
106 //        spin_lock(&svcsecs_lock);
107         rc = try_module_get(sec->pss_owner);
108 //        spin_unlock(&svcsecs_lock);
109         LASSERT(rc);
110         return sec;
111 }
112
113 void svcsec_put(struct ptlrpc_svcsec *sec)
114 {
115 //        spin_lock(&svcsecs_lock);
116         module_put(sec->pss_owner);
117 //        spin_unlock(&svcsecs_lock);
118 }
119
120 /*
121  * common code to allocate reply_state buffer.
122  */
123 int svcsec_alloc_reply_state(struct ptlrpc_request *req,
124                              int msgsize, int secsize)
125 {
126         struct ptlrpc_reply_state *rs;
127         char *buf;
128         int repsize, bufsize;
129         ENTRY;
130
131         LASSERT(msgsize % 8 == 0);
132         LASSERT(secsize % 8 == 0);
133
134         repsize = sizeof(struct ptlrpcs_wire_hdr) + msgsize + secsize;
135         bufsize = repsize + sizeof(struct ptlrpc_reply_state);
136
137         OBD_ALLOC(buf, bufsize);
138         if (!buf) {
139                 CERROR("can't alloc %d\n", bufsize);
140                 RETURN(-ENOMEM);
141         }
142
143         /* req->rq_repbuf is not used on server side */
144         rs = (struct ptlrpc_reply_state *) (buf + repsize);
145         rs->rs_buf = buf;
146         rs->rs_buf_len = bufsize;
147         rs->rs_repbuf = buf;
148         rs->rs_repbuf_len = repsize;
149         /* current known data length is hdr + msg, security payload
150          * will be added on later.
151          */
152         rs->rs_repdata_len = sizeof(struct ptlrpcs_wire_hdr) + msgsize;
153         req->rq_repmsg = rs->rs_msg = (struct lustre_msg *)
154                          (rs->rs_repbuf + sizeof(struct ptlrpcs_wire_hdr));
155
156         req->rq_reply_state = rs;
157
158         CDEBUG(D_SEC, "alloc rs buf at %p, len %d; repbuf at %p, len %d\n",
159                rs->rs_buf, rs->rs_buf_len, rs->rs_repbuf, rs->rs_repbuf_len);
160
161         RETURN(0);
162 }
163
164 void svcsec_free_reply_state(struct ptlrpc_reply_state *rs)
165 {
166         char *p;
167         ENTRY;
168
169         /* for work around memory-alloc debug poison */
170         LASSERT(rs);
171         p = rs->rs_buf;
172         OBD_FREE(p, rs->rs_buf_len);
173         EXIT;
174 }
175
176 int svcsec_alloc_repbuf(struct ptlrpc_svcsec *svcsec,
177                         struct ptlrpc_request *req,
178                         int msgsize)
179 {
180         LASSERT(svcsec);
181         LASSERT(msgsize % 8 == 0);
182
183         if (svcsec->alloc_repbuf)
184                 return svcsec->alloc_repbuf(svcsec, req, msgsize);
185         else
186                 return svcsec_alloc_reply_state(req, msgsize, 0);
187 }
188
189 int svcsec_accept(struct ptlrpc_request *req, enum ptlrpcs_error *res)
190 {
191         struct ptlrpc_svcsec           *sec;
192         struct ptlrpcs_wire_hdr        *sec_hdr;
193         int                             rc;
194         ENTRY;
195
196         LASSERT(req->rq_reqbuf);
197         LASSERT(!req->rq_reqmsg);
198         LASSERT(!req->rq_svcsec);
199
200         *res = PTLRPCS_BADCRED;
201         if (req->rq_reqbuf_len < sizeof(*sec_hdr)) {
202                 CERROR("drop too short msg (length: %d)\n", req->rq_reqbuf_len);
203                 RETURN(SVC_DROP);
204         }
205
206         sec_hdr = (struct ptlrpcs_wire_hdr *) req->rq_reqbuf;
207         sec_hdr->flavor = le32_to_cpu(sec_hdr->flavor);
208         sec_hdr->sectype = le32_to_cpu(sec_hdr->sectype);
209         sec_hdr->msg_len = le32_to_cpu(sec_hdr->msg_len);
210         sec_hdr->sec_len = le32_to_cpu(sec_hdr->sec_len);
211
212         /* sanity check */
213         switch (sec_hdr->sectype) {
214         case PTLRPC_SEC_TYPE_NONE:
215         case PTLRPC_SEC_TYPE_AUTH:
216         case PTLRPC_SEC_TYPE_PRIV:
217                 break;
218         default:
219                 CERROR("unknown security type %d\n", sec_hdr->sectype);
220                 RETURN(SVC_DROP);
221         }
222
223         if (sizeof(*sec_hdr) + sec_hdr->msg_len + sec_hdr->sec_len >
224             req->rq_reqbuf_len) {
225                 CERROR("received %d, msg %d, sec %d\n",
226                         req->rq_reqbuf_len, sec_hdr->msg_len, sec_hdr->sec_len);
227                 RETURN(SVC_DROP);
228         }
229
230         req->rq_svcsec = sec = flavor2svcsec(sec_hdr->flavor);
231         if (!sec) {
232                 CERROR("drop msg: unsupported flavor %d\n", sec_hdr->flavor);
233                 RETURN(SVC_DROP);
234         }
235         LASSERT(sec->accept);
236
237         rc = sec->accept(req, res);
238
239         switch (rc) {
240         case SVC_DROP:
241                 svcsec_put(sec);
242                 req->rq_svcsec = NULL;
243                 break;
244         case SVC_OK:
245         case SVC_LOGIN:
246         case SVC_LOGOUT:
247                 LASSERT(req->rq_reqmsg);
248                 break;
249         }
250
251         RETURN(rc);
252 }
253
254 int svcsec_authorize(struct ptlrpc_request *req)
255 {
256         LASSERT(req->rq_svcsec);
257         LASSERT(req->rq_svcsec->authorize);
258
259         return (req->rq_svcsec->authorize(req));
260 }
261
262 void svcsec_cleanup_req(struct ptlrpc_request *req)
263 {
264         struct ptlrpc_svcsec *svcsec = req->rq_svcsec;
265         ENTRY;
266
267         LASSERT(svcsec);
268         LASSERT(svcsec->cleanup_req || !req->rq_sec_svcdata);
269
270         if (svcsec->cleanup_req)
271                 svcsec->cleanup_req(svcsec, req);
272         EXIT;
273 }