2 * linux/net/sunrpc/gss_rpc_upcall.c
4 * Copyright (C) 2012 Simo Sorce <simo@redhat.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <linux/types.h>
24 #include <linux/sunrpc/svcauth.h>
25 #include "gss_rpc_upcall.h"
27 #define GSSPROXY_SOCK_PATHNAME "/var/run/gssproxy.sock"
29 #define GSSPROXY_PROGRAM (400112u)
30 #define GSSPROXY_VERS_1 (1u)
33 * Encoding/Decoding functions
37 GSSX_NULL
= 0, /* Unused */
38 GSSX_INDICATE_MECHS
= 1,
39 GSSX_GET_CALL_CONTEXT
= 2,
40 GSSX_IMPORT_AND_CANON_NAME
= 3,
43 GSSX_ACQUIRE_CRED
= 6,
45 GSSX_INIT_SEC_CONTEXT
= 8,
46 GSSX_ACCEPT_SEC_CONTEXT
= 9,
47 GSSX_RELEASE_HANDLE
= 10,
52 GSSX_WRAP_SIZE_LIMIT
= 15,
55 #define PROC(proc, name) \
57 .p_proc = GSSX_##proc, \
58 .p_encode = (kxdreproc_t)gssx_enc_##name, \
59 .p_decode = (kxdrdproc_t)gssx_dec_##name, \
60 .p_arglen = GSSX_ARG_##name##_sz, \
61 .p_replen = GSSX_RES_##name##_sz, \
62 .p_statidx = GSSX_##proc, \
66 static struct rpc_procinfo gssp_procedures
[] = {
67 PROC(INDICATE_MECHS
, indicate_mechs
),
68 PROC(GET_CALL_CONTEXT
, get_call_context
),
69 PROC(IMPORT_AND_CANON_NAME
, import_and_canon_name
),
70 PROC(EXPORT_CRED
, export_cred
),
71 PROC(IMPORT_CRED
, import_cred
),
72 PROC(ACQUIRE_CRED
, acquire_cred
),
73 PROC(STORE_CRED
, store_cred
),
74 PROC(INIT_SEC_CONTEXT
, init_sec_context
),
75 PROC(ACCEPT_SEC_CONTEXT
, accept_sec_context
),
76 PROC(RELEASE_HANDLE
, release_handle
),
77 PROC(GET_MIC
, get_mic
),
81 PROC(WRAP_SIZE_LIMIT
, wrap_size_limit
),
87 * Common transport functions
90 static const struct rpc_program gssp_program
;
92 static int gssp_rpc_create(struct net
*net
, struct rpc_clnt
**_clnt
)
94 static const struct sockaddr_un gssp_localaddr
= {
95 .sun_family
= AF_LOCAL
,
96 .sun_path
= GSSPROXY_SOCK_PATHNAME
,
98 struct rpc_create_args args
= {
100 .protocol
= XPRT_TRANSPORT_LOCAL
,
101 .address
= (struct sockaddr
*)&gssp_localaddr
,
102 .addrsize
= sizeof(gssp_localaddr
),
103 .servername
= "localhost",
104 .program
= &gssp_program
,
105 .version
= GSSPROXY_VERS_1
,
106 .authflavor
= RPC_AUTH_NULL
,
108 * Note we want connection to be done in the caller's
109 * filesystem namespace. We therefore turn off the idle
110 * timeout, which would result in reconnections being
111 * done without the correct namespace:
113 .flags
= RPC_CLNT_CREATE_NOPING
|
114 RPC_CLNT_CREATE_NO_IDLE_TIMEOUT
116 struct rpc_clnt
*clnt
;
119 clnt
= rpc_create(&args
);
121 dprintk("RPC: failed to create AF_LOCAL gssproxy "
122 "client (errno %ld).\n", PTR_ERR(clnt
));
123 result
= -PTR_ERR(clnt
);
128 dprintk("RPC: created new gssp local client (gssp_local_clnt: "
136 void init_gssp_clnt(struct sunrpc_net
*sn
)
138 mutex_init(&sn
->gssp_lock
);
139 sn
->gssp_clnt
= NULL
;
140 init_waitqueue_head(&sn
->gssp_wq
);
143 int set_gssp_clnt(struct net
*net
)
145 struct sunrpc_net
*sn
= net_generic(net
, sunrpc_net_id
);
146 struct rpc_clnt
*clnt
;
149 mutex_lock(&sn
->gssp_lock
);
150 ret
= gssp_rpc_create(net
, &clnt
);
153 rpc_shutdown_client(sn
->gssp_clnt
);
154 sn
->gssp_clnt
= clnt
;
156 mutex_unlock(&sn
->gssp_lock
);
157 wake_up(&sn
->gssp_wq
);
161 void clear_gssp_clnt(struct sunrpc_net
*sn
)
163 mutex_lock(&sn
->gssp_lock
);
165 rpc_shutdown_client(sn
->gssp_clnt
);
166 sn
->gssp_clnt
= NULL
;
168 mutex_unlock(&sn
->gssp_lock
);
171 static struct rpc_clnt
*get_gssp_clnt(struct sunrpc_net
*sn
)
173 struct rpc_clnt
*clnt
;
175 mutex_lock(&sn
->gssp_lock
);
176 clnt
= sn
->gssp_clnt
;
178 atomic_inc(&clnt
->cl_count
);
179 mutex_unlock(&sn
->gssp_lock
);
183 static int gssp_call(struct net
*net
, struct rpc_message
*msg
)
185 struct sunrpc_net
*sn
= net_generic(net
, sunrpc_net_id
);
186 struct rpc_clnt
*clnt
;
189 clnt
= get_gssp_clnt(sn
);
192 status
= rpc_call_sync(clnt
, msg
, 0);
194 dprintk("gssp: rpc_call returned error %d\n", -status
);
196 case -EPROTONOSUPPORT
:
212 rpc_release_client(clnt
);
221 /* numbers somewhat arbitrary but large enough for current needs */
222 #define GSSX_MAX_OUT_HANDLE 128
223 #define GSSX_MAX_SRC_PRINC 256
224 #define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \
226 GSSX_max_princ_sz + \
227 sizeof(struct svc_cred))
229 int gssp_accept_sec_context_upcall(struct net
*net
,
230 struct gssp_upcall_data
*data
)
232 struct gssx_ctx ctxh
= {
233 .state
= data
->in_handle
235 struct gssx_arg_accept_sec_context arg
= {
236 .input_token
= data
->in_token
,
238 struct gssx_ctx rctxh
= {
240 * pass in the max length we expect for each of these
241 * buffers but let the xdr code kmalloc them:
243 .exported_context_token
.len
= GSSX_max_output_handle_sz
,
244 .mech
.len
= GSS_OID_MAX_LEN
,
245 .src_name
.display_name
.len
= GSSX_max_princ_sz
247 struct gssx_res_accept_sec_context res
= {
248 .context_handle
= &rctxh
,
249 .output_token
= &data
->out_token
251 struct rpc_message msg
= {
252 .rpc_proc
= &gssp_procedures
[GSSX_ACCEPT_SEC_CONTEXT
],
255 .rpc_cred
= NULL
, /* FIXME ? */
257 struct xdr_netobj client_name
= { 0 , NULL
};
260 if (data
->in_handle
.len
!= 0)
261 arg
.context_handle
= &ctxh
;
262 res
.output_token
->len
= GSSX_max_output_token_sz
;
264 /* use nfs/ for targ_name ? */
266 ret
= gssp_call(net
, &msg
);
268 /* we need to fetch all data even in case of error so
269 * that we can free special strctures is they have been allocated */
270 data
->major_status
= res
.status
.major_status
;
271 data
->minor_status
= res
.status
.minor_status
;
272 if (res
.context_handle
) {
273 data
->out_handle
= rctxh
.exported_context_token
;
274 data
->mech_oid
.len
= rctxh
.mech
.len
;
275 memcpy(data
->mech_oid
.data
, rctxh
.mech
.data
,
277 client_name
= rctxh
.src_name
.display_name
;
280 if (res
.options
.count
== 1) {
281 gssx_buffer
*value
= &res
.options
.data
[0].value
;
282 /* Currently we only decode CREDS_VALUE, if we add
283 * anything else we'll have to loop and match on the
285 if (value
->len
== 1) {
286 /* steal group info from struct svc_cred */
287 data
->creds
= *(struct svc_cred
*)value
->data
;
288 data
->found_creds
= 1;
290 /* whether we use it or not, free data */
294 if (res
.options
.count
!= 0) {
295 kfree(res
.options
.data
);
298 /* convert to GSS_NT_HOSTBASED_SERVICE form and set into creds */
299 if (data
->found_creds
&& client_name
.data
!= NULL
) {
302 data
->creds
.cr_principal
= kstrndup(client_name
.data
,
303 client_name
.len
, GFP_KERNEL
);
304 if (data
->creds
.cr_principal
) {
305 /* terminate and remove realm part */
306 c
= strchr(data
->creds
.cr_principal
, '@');
310 /* change service-hostname delimiter */
311 c
= strchr(data
->creds
.cr_principal
, '/');
315 /* not a service principal */
316 kfree(data
->creds
.cr_principal
);
317 data
->creds
.cr_principal
= NULL
;
321 kfree(client_name
.data
);
326 void gssp_free_upcall_data(struct gssp_upcall_data
*data
)
328 kfree(data
->in_handle
.data
);
329 kfree(data
->out_handle
.data
);
330 kfree(data
->out_token
.data
);
331 kfree(data
->mech_oid
.data
);
332 free_svc_cred(&data
->creds
);
336 * Initialization stuff
339 static const struct rpc_version gssp_version1
= {
340 .number
= GSSPROXY_VERS_1
,
341 .nrprocs
= ARRAY_SIZE(gssp_procedures
),
342 .procs
= gssp_procedures
,
345 static const struct rpc_version
*gssp_version
[] = {
350 static struct rpc_stat gssp_stats
;
352 static const struct rpc_program gssp_program
= {
354 .number
= GSSPROXY_PROGRAM
,
355 .nrvers
= ARRAY_SIZE(gssp_version
),
356 .version
= gssp_version
,
357 .stats
= &gssp_stats
,