1 // SPDX-License-Identifier: GPL-2.0+
3 * linux/net/sunrpc/gss_rpc_upcall.c
5 * Copyright (C) 2012 Simo Sorce <simo@redhat.com>
8 #include <linux/types.h>
11 #include <linux/sunrpc/svcauth.h>
12 #include "gss_rpc_upcall.h"
14 #define GSSPROXY_SOCK_PATHNAME "/var/run/gssproxy.sock"
16 #define GSSPROXY_PROGRAM (400112u)
17 #define GSSPROXY_VERS_1 (1u)
20 * Encoding/Decoding functions
24 GSSX_NULL
= 0, /* Unused */
25 GSSX_INDICATE_MECHS
= 1,
26 GSSX_GET_CALL_CONTEXT
= 2,
27 GSSX_IMPORT_AND_CANON_NAME
= 3,
30 GSSX_ACQUIRE_CRED
= 6,
32 GSSX_INIT_SEC_CONTEXT
= 8,
33 GSSX_ACCEPT_SEC_CONTEXT
= 9,
34 GSSX_RELEASE_HANDLE
= 10,
39 GSSX_WRAP_SIZE_LIMIT
= 15,
42 #define PROC(proc, name) \
44 .p_proc = GSSX_##proc, \
45 .p_encode = gssx_enc_##name, \
46 .p_decode = gssx_dec_##name, \
47 .p_arglen = GSSX_ARG_##name##_sz, \
48 .p_replen = GSSX_RES_##name##_sz, \
49 .p_statidx = GSSX_##proc, \
53 static const struct rpc_procinfo gssp_procedures
[] = {
54 PROC(INDICATE_MECHS
, indicate_mechs
),
55 PROC(GET_CALL_CONTEXT
, get_call_context
),
56 PROC(IMPORT_AND_CANON_NAME
, import_and_canon_name
),
57 PROC(EXPORT_CRED
, export_cred
),
58 PROC(IMPORT_CRED
, import_cred
),
59 PROC(ACQUIRE_CRED
, acquire_cred
),
60 PROC(STORE_CRED
, store_cred
),
61 PROC(INIT_SEC_CONTEXT
, init_sec_context
),
62 PROC(ACCEPT_SEC_CONTEXT
, accept_sec_context
),
63 PROC(RELEASE_HANDLE
, release_handle
),
64 PROC(GET_MIC
, get_mic
),
68 PROC(WRAP_SIZE_LIMIT
, wrap_size_limit
),
74 * Common transport functions
77 static const struct rpc_program gssp_program
;
79 static int gssp_rpc_create(struct net
*net
, struct rpc_clnt
**_clnt
)
81 static const struct sockaddr_un gssp_localaddr
= {
82 .sun_family
= AF_LOCAL
,
83 .sun_path
= GSSPROXY_SOCK_PATHNAME
,
85 struct rpc_create_args args
= {
87 .protocol
= XPRT_TRANSPORT_LOCAL
,
88 .address
= (struct sockaddr
*)&gssp_localaddr
,
89 .addrsize
= sizeof(gssp_localaddr
),
90 .servername
= "localhost",
91 .program
= &gssp_program
,
92 .version
= GSSPROXY_VERS_1
,
93 .authflavor
= RPC_AUTH_NULL
,
95 * Note we want connection to be done in the caller's
96 * filesystem namespace. We therefore turn off the idle
97 * timeout, which would result in reconnections being
98 * done without the correct namespace:
100 .flags
= RPC_CLNT_CREATE_NOPING
|
101 RPC_CLNT_CREATE_CONNECTED
|
102 RPC_CLNT_CREATE_NO_IDLE_TIMEOUT
104 struct rpc_clnt
*clnt
;
107 clnt
= rpc_create(&args
);
109 dprintk("RPC: failed to create AF_LOCAL gssproxy "
110 "client (errno %ld).\n", PTR_ERR(clnt
));
111 result
= PTR_ERR(clnt
);
116 dprintk("RPC: created new gssp local client (gssp_local_clnt: "
124 void init_gssp_clnt(struct sunrpc_net
*sn
)
126 mutex_init(&sn
->gssp_lock
);
127 sn
->gssp_clnt
= NULL
;
130 int set_gssp_clnt(struct net
*net
)
132 struct sunrpc_net
*sn
= net_generic(net
, sunrpc_net_id
);
133 struct rpc_clnt
*clnt
;
136 mutex_lock(&sn
->gssp_lock
);
137 ret
= gssp_rpc_create(net
, &clnt
);
140 rpc_shutdown_client(sn
->gssp_clnt
);
141 sn
->gssp_clnt
= clnt
;
143 mutex_unlock(&sn
->gssp_lock
);
147 void clear_gssp_clnt(struct sunrpc_net
*sn
)
149 mutex_lock(&sn
->gssp_lock
);
151 rpc_shutdown_client(sn
->gssp_clnt
);
152 sn
->gssp_clnt
= NULL
;
154 mutex_unlock(&sn
->gssp_lock
);
157 static struct rpc_clnt
*get_gssp_clnt(struct sunrpc_net
*sn
)
159 struct rpc_clnt
*clnt
;
161 mutex_lock(&sn
->gssp_lock
);
162 clnt
= sn
->gssp_clnt
;
164 refcount_inc(&clnt
->cl_count
);
165 mutex_unlock(&sn
->gssp_lock
);
169 static int gssp_call(struct net
*net
, struct rpc_message
*msg
)
171 struct sunrpc_net
*sn
= net_generic(net
, sunrpc_net_id
);
172 struct rpc_clnt
*clnt
;
175 clnt
= get_gssp_clnt(sn
);
178 status
= rpc_call_sync(clnt
, msg
, 0);
180 dprintk("gssp: rpc_call returned error %d\n", -status
);
182 case -EPROTONOSUPPORT
:
198 rpc_release_client(clnt
);
202 static void gssp_free_receive_pages(struct gssx_arg_accept_sec_context
*arg
)
206 for (i
= 0; i
< arg
->npages
&& arg
->pages
[i
]; i
++)
207 __free_page(arg
->pages
[i
]);
212 static int gssp_alloc_receive_pages(struct gssx_arg_accept_sec_context
*arg
)
216 arg
->npages
= DIV_ROUND_UP(NGROUPS_MAX
* 4, PAGE_SIZE
);
217 arg
->pages
= kcalloc(arg
->npages
, sizeof(struct page
*), GFP_KERNEL
);
220 for (i
= 0; i
< arg
->npages
; i
++) {
221 arg
->pages
[i
] = alloc_page(GFP_KERNEL
);
222 if (!arg
->pages
[i
]) {
223 gssp_free_receive_pages(arg
);
230 static char *gssp_stringify(struct xdr_netobj
*netobj
)
232 return kmemdup_nul(netobj
->data
, netobj
->len
, GFP_KERNEL
);
235 static void gssp_hostbased_service(char **principal
)
242 /* terminate and remove realm part */
243 c
= strchr(*principal
, '@');
247 /* change service-hostname delimiter */
248 c
= strchr(*principal
, '/');
253 /* not a service principal */
263 /* numbers somewhat arbitrary but large enough for current needs */
264 #define GSSX_MAX_OUT_HANDLE 128
265 #define GSSX_MAX_SRC_PRINC 256
266 #define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \
268 GSSX_max_princ_sz + \
269 sizeof(struct svc_cred))
271 int gssp_accept_sec_context_upcall(struct net
*net
,
272 struct gssp_upcall_data
*data
)
274 struct gssx_ctx ctxh
= {
275 .state
= data
->in_handle
277 struct gssx_arg_accept_sec_context arg
= {
278 .input_token
= data
->in_token
,
280 struct gssx_ctx rctxh
= {
282 * pass in the max length we expect for each of these
283 * buffers but let the xdr code kmalloc them:
285 .exported_context_token
.len
= GSSX_max_output_handle_sz
,
286 .mech
.len
= GSS_OID_MAX_LEN
,
287 .targ_name
.display_name
.len
= GSSX_max_princ_sz
,
288 .src_name
.display_name
.len
= GSSX_max_princ_sz
290 struct gssx_res_accept_sec_context res
= {
291 .context_handle
= &rctxh
,
292 .output_token
= &data
->out_token
294 struct rpc_message msg
= {
295 .rpc_proc
= &gssp_procedures
[GSSX_ACCEPT_SEC_CONTEXT
],
298 .rpc_cred
= NULL
, /* FIXME ? */
300 struct xdr_netobj client_name
= { 0 , NULL
};
301 struct xdr_netobj target_name
= { 0, NULL
};
304 if (data
->in_handle
.len
!= 0)
305 arg
.context_handle
= &ctxh
;
306 res
.output_token
->len
= GSSX_max_output_token_sz
;
308 ret
= gssp_alloc_receive_pages(&arg
);
312 ret
= gssp_call(net
, &msg
);
314 gssp_free_receive_pages(&arg
);
316 /* we need to fetch all data even in case of error so
317 * that we can free special strctures is they have been allocated */
318 data
->major_status
= res
.status
.major_status
;
319 data
->minor_status
= res
.status
.minor_status
;
320 if (res
.context_handle
) {
321 data
->out_handle
= rctxh
.exported_context_token
;
322 data
->mech_oid
.len
= rctxh
.mech
.len
;
323 if (rctxh
.mech
.data
) {
324 memcpy(data
->mech_oid
.data
, rctxh
.mech
.data
,
326 kfree(rctxh
.mech
.data
);
328 client_name
= rctxh
.src_name
.display_name
;
329 target_name
= rctxh
.targ_name
.display_name
;
332 if (res
.options
.count
== 1) {
333 gssx_buffer
*value
= &res
.options
.data
[0].value
;
334 /* Currently we only decode CREDS_VALUE, if we add
335 * anything else we'll have to loop and match on the
337 if (value
->len
== 1) {
338 /* steal group info from struct svc_cred */
339 data
->creds
= *(struct svc_cred
*)value
->data
;
340 data
->found_creds
= 1;
342 /* whether we use it or not, free data */
346 if (res
.options
.count
!= 0) {
347 kfree(res
.options
.data
);
350 /* convert to GSS_NT_HOSTBASED_SERVICE form and set into creds */
351 if (data
->found_creds
) {
352 if (client_name
.data
) {
353 data
->creds
.cr_raw_principal
=
354 gssp_stringify(&client_name
);
355 data
->creds
.cr_principal
=
356 gssp_stringify(&client_name
);
357 gssp_hostbased_service(&data
->creds
.cr_principal
);
359 if (target_name
.data
) {
360 data
->creds
.cr_targ_princ
=
361 gssp_stringify(&target_name
);
362 gssp_hostbased_service(&data
->creds
.cr_targ_princ
);
365 kfree(client_name
.data
);
366 kfree(target_name
.data
);
371 void gssp_free_upcall_data(struct gssp_upcall_data
*data
)
373 kfree(data
->in_handle
.data
);
374 kfree(data
->out_handle
.data
);
375 kfree(data
->out_token
.data
);
376 free_svc_cred(&data
->creds
);
380 * Initialization stuff
382 static unsigned int gssp_version1_counts
[ARRAY_SIZE(gssp_procedures
)];
383 static const struct rpc_version gssp_version1
= {
384 .number
= GSSPROXY_VERS_1
,
385 .nrprocs
= ARRAY_SIZE(gssp_procedures
),
386 .procs
= gssp_procedures
,
387 .counts
= gssp_version1_counts
,
390 static const struct rpc_version
*gssp_version
[] = {
395 static struct rpc_stat gssp_stats
;
397 static const struct rpc_program gssp_program
= {
399 .number
= GSSPROXY_PROGRAM
,
400 .nrvers
= ARRAY_SIZE(gssp_version
),
401 .version
= gssp_version
,
402 .stats
= &gssp_stats
,