aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-05-03 13:59:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-03 13:59:39 -0400
commit1db772216f48978d5146b858586f6178433aad38 (patch)
tree4cb1f7345256c7a89c85b7a6157bbf16b944782e /net/sunrpc
parent86652188f345edec56b0074a65f6db17f16eb359 (diff)
parent676e4ebd5f2c3b4fd1d2bff79b68385c23c5c105 (diff)
Merge branch 'for-3.10' of git://linux-nfs.org/~bfields/linux
Pull nfsd changes from J Bruce Fields: "Highlights include: - Some more DRC cleanup and performance work from Jeff Layton - A gss-proxy upcall from Simo Sorce: currently krb5 mounts to the server using credentials from Active Directory often fail due to limitations of the svcgssd upcall interface. This replacement lifts those limitations. The existing upcall is still supported for backwards compatibility. - More NFSv4.1 support: at this point, if a user with a current client who upgrades from 4.0 to 4.1 should see no regressions. In theory we do everything a 4.1 server is required to do. Patches for a couple minor exceptions are ready for 3.11, and with those and some more testing I'd like to turn 4.1 on by default in 3.11." Fix up semantic conflict as per Stephen Rothwell and linux-next: Commit 030d794bf498 ("SUNRPC: Use gssproxy upcall for server RPCGSS authentication") adds two new users of "PDE(inode)->data", but we're supposed to use "PDE_DATA(inode)" instead since commit d9dda78bad87 ("procfs: new helper - PDE_DATA(inode)"). The old PDE() macro is no longer available since commit c30480b92cf4 ("proc: Make the PROC_I() and PDE() macros internal to procfs") * 'for-3.10' of git://linux-nfs.org/~bfields/linux: (60 commits) NFSD: SECINFO doesn't handle unsupported pseudoflavors correctly NFSD: Simplify GSS flavor encoding in nfsd4_do_encode_secinfo() nfsd: make symbol nfsd_reply_cache_shrinker static svcauth_gss: fix error return code in rsc_parse() nfsd4: don't remap EISDIR errors in rename svcrpc: fix gss-proxy to respect user namespaces SUNRPC: gssp_procedures[] can be static SUNRPC: define {create,destroy}_use_gss_proxy_proc_entry in !PROC case nfsd4: better error return to indicate SSV non-support nfsd: fix EXDEV checking in rename SUNRPC: Use gssproxy upcall for server RPCGSS authentication. SUNRPC: Add RPC based upcall mechanism for RPCGSS auth SUNRPC: conditionally return endtime from import_sec_context SUNRPC: allow disabling idle timeout SUNRPC: attempt AF_LOCAL connect on setup nfsd: Decode and send 64bit time values nfsd4: put_client_renew_locked can be static nfsd4: remove unused macro nfsd4: remove some useless code nfsd4: implement SEQ4_STATUS_RECALLABLE_STATE_REVOKED ...
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/auth_gss/Makefile3
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c7
-rw-r--r--net/sunrpc/auth_gss/gss_mech_switch.c7
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_upcall.c358
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_upcall.h48
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_xdr.c838
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_xdr.h264
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c363
-rw-r--r--net/sunrpc/cache.c4
-rw-r--r--net/sunrpc/clnt.c3
-rw-r--r--net/sunrpc/netns.h6
-rw-r--r--net/sunrpc/xprt.c2
-rw-r--r--net/sunrpc/xprtsock.c3
14 files changed, 1889 insertions, 19 deletions
diff --git a/net/sunrpc/auth_gss/Makefile b/net/sunrpc/auth_gss/Makefile
index 9e4cb59ef9f0..14e9e53e63d5 100644
--- a/net/sunrpc/auth_gss/Makefile
+++ b/net/sunrpc/auth_gss/Makefile
@@ -5,7 +5,8 @@
5obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o 5obj-$(CONFIG_SUNRPC_GSS) += auth_rpcgss.o
6 6
7auth_rpcgss-y := auth_gss.o gss_generic_token.o \ 7auth_rpcgss-y := auth_gss.o gss_generic_token.o \
8 gss_mech_switch.o svcauth_gss.o 8 gss_mech_switch.o svcauth_gss.o \
9 gss_rpc_upcall.o gss_rpc_xdr.o
9 10
10obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o 11obj-$(CONFIG_RPCSEC_GSS_KRB5) += rpcsec_gss_krb5.o
11 12
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 51415b07174e..a764e227fdde 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -238,7 +238,7 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct
238 p = ERR_PTR(-EFAULT); 238 p = ERR_PTR(-EFAULT);
239 goto err; 239 goto err;
240 } 240 }
241 ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx, GFP_NOFS); 241 ret = gss_import_sec_context(p, seclen, gm, &ctx->gc_gss_ctx, NULL, GFP_NOFS);
242 if (ret < 0) { 242 if (ret < 0) {
243 p = ERR_PTR(ret); 243 p = ERR_PTR(ret);
244 goto err; 244 goto err;
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 33255ff889c0..0d3c158ef8fa 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -679,6 +679,7 @@ out_err:
679static int 679static int
680gss_import_sec_context_kerberos(const void *p, size_t len, 680gss_import_sec_context_kerberos(const void *p, size_t len,
681 struct gss_ctx *ctx_id, 681 struct gss_ctx *ctx_id,
682 time_t *endtime,
682 gfp_t gfp_mask) 683 gfp_t gfp_mask)
683{ 684{
684 const void *end = (const void *)((const char *)p + len); 685 const void *end = (const void *)((const char *)p + len);
@@ -694,9 +695,11 @@ gss_import_sec_context_kerberos(const void *p, size_t len,
694 else 695 else
695 ret = gss_import_v2_context(p, end, ctx, gfp_mask); 696 ret = gss_import_v2_context(p, end, ctx, gfp_mask);
696 697
697 if (ret == 0) 698 if (ret == 0) {
698 ctx_id->internal_ctx_id = ctx; 699 ctx_id->internal_ctx_id = ctx;
699 else 700 if (endtime)
701 *endtime = ctx->endtime;
702 } else
700 kfree(ctx); 703 kfree(ctx);
701 704
702 dprintk("RPC: %s: returning %d\n", __func__, ret); 705 dprintk("RPC: %s: returning %d\n", __func__, ret);
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
index 79881d6e68a1..defa9d33925c 100644
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -175,7 +175,7 @@ struct gss_api_mech * gss_mech_get_by_name(const char *name)
175 return gm; 175 return gm;
176} 176}
177 177
178static struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj) 178struct gss_api_mech *gss_mech_get_by_OID(struct rpcsec_gss_oid *obj)
179{ 179{
180 struct gss_api_mech *pos, *gm = NULL; 180 struct gss_api_mech *pos, *gm = NULL;
181 char buf[32]; 181 char buf[32];
@@ -386,14 +386,15 @@ int
386gss_import_sec_context(const void *input_token, size_t bufsize, 386gss_import_sec_context(const void *input_token, size_t bufsize,
387 struct gss_api_mech *mech, 387 struct gss_api_mech *mech,
388 struct gss_ctx **ctx_id, 388 struct gss_ctx **ctx_id,
389 time_t *endtime,
389 gfp_t gfp_mask) 390 gfp_t gfp_mask)
390{ 391{
391 if (!(*ctx_id = kzalloc(sizeof(**ctx_id), gfp_mask))) 392 if (!(*ctx_id = kzalloc(sizeof(**ctx_id), gfp_mask)))
392 return -ENOMEM; 393 return -ENOMEM;
393 (*ctx_id)->mech_type = gss_mech_get(mech); 394 (*ctx_id)->mech_type = gss_mech_get(mech);
394 395
395 return mech->gm_ops 396 return mech->gm_ops->gss_import_sec_context(input_token, bufsize,
396 ->gss_import_sec_context(input_token, bufsize, *ctx_id, gfp_mask); 397 *ctx_id, endtime, gfp_mask);
397} 398}
398 399
399/* gss_get_mic: compute a mic over message and return mic_token. */ 400/* gss_get_mic: compute a mic over message and return mic_token. */
diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.c b/net/sunrpc/auth_gss/gss_rpc_upcall.c
new file mode 100644
index 000000000000..d304f41260f2
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c
@@ -0,0 +1,358 @@
1/*
2 * linux/net/sunrpc/gss_rpc_upcall.c
3 *
4 * Copyright (C) 2012 Simo Sorce <simo@redhat.com>
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 as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
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.
15 *
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.
19 */
20
21#include <linux/types.h>
22#include <linux/un.h>
23
24#include <linux/sunrpc/svcauth.h>
25#include "gss_rpc_upcall.h"
26
27#define GSSPROXY_SOCK_PATHNAME "/var/run/gssproxy.sock"
28
29#define GSSPROXY_PROGRAM (400112u)
30#define GSSPROXY_VERS_1 (1u)
31
32/*
33 * Encoding/Decoding functions
34 */
35
36enum {
37 GSSX_NULL = 0, /* Unused */
38 GSSX_INDICATE_MECHS = 1,
39 GSSX_GET_CALL_CONTEXT = 2,
40 GSSX_IMPORT_AND_CANON_NAME = 3,
41 GSSX_EXPORT_CRED = 4,
42 GSSX_IMPORT_CRED = 5,
43 GSSX_ACQUIRE_CRED = 6,
44 GSSX_STORE_CRED = 7,
45 GSSX_INIT_SEC_CONTEXT = 8,
46 GSSX_ACCEPT_SEC_CONTEXT = 9,
47 GSSX_RELEASE_HANDLE = 10,
48 GSSX_GET_MIC = 11,
49 GSSX_VERIFY = 12,
50 GSSX_WRAP = 13,
51 GSSX_UNWRAP = 14,
52 GSSX_WRAP_SIZE_LIMIT = 15,
53};
54
55#define PROC(proc, name) \
56[GSSX_##proc] = { \
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, \
63 .p_name = #proc, \
64}
65
66static 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),
78 PROC(VERIFY, verify),
79 PROC(WRAP, wrap),
80 PROC(UNWRAP, unwrap),
81 PROC(WRAP_SIZE_LIMIT, wrap_size_limit),
82};
83
84
85
86/*
87 * Common transport functions
88 */
89
90static const struct rpc_program gssp_program;
91
92static int gssp_rpc_create(struct net *net, struct rpc_clnt **_clnt)
93{
94 static const struct sockaddr_un gssp_localaddr = {
95 .sun_family = AF_LOCAL,
96 .sun_path = GSSPROXY_SOCK_PATHNAME,
97 };
98 struct rpc_create_args args = {
99 .net = net,
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,
107 /*
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:
112 */
113 .flags = RPC_CLNT_CREATE_NOPING |
114 RPC_CLNT_CREATE_NO_IDLE_TIMEOUT
115 };
116 struct rpc_clnt *clnt;
117 int result = 0;
118
119 clnt = rpc_create(&args);
120 if (IS_ERR(clnt)) {
121 dprintk("RPC: failed to create AF_LOCAL gssproxy "
122 "client (errno %ld).\n", PTR_ERR(clnt));
123 result = -PTR_ERR(clnt);
124 *_clnt = NULL;
125 goto out;
126 }
127
128 dprintk("RPC: created new gssp local client (gssp_local_clnt: "
129 "%p)\n", clnt);
130 *_clnt = clnt;
131
132out:
133 return result;
134}
135
136void init_gssp_clnt(struct sunrpc_net *sn)
137{
138 mutex_init(&sn->gssp_lock);
139 sn->gssp_clnt = NULL;
140 init_waitqueue_head(&sn->gssp_wq);
141}
142
143int set_gssp_clnt(struct net *net)
144{
145 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
146 struct rpc_clnt *clnt;
147 int ret;
148
149 mutex_lock(&sn->gssp_lock);
150 ret = gssp_rpc_create(net, &clnt);
151 if (!ret) {
152 if (sn->gssp_clnt)
153 rpc_shutdown_client(sn->gssp_clnt);
154 sn->gssp_clnt = clnt;
155 }
156 mutex_unlock(&sn->gssp_lock);
157 wake_up(&sn->gssp_wq);
158 return ret;
159}
160
161void clear_gssp_clnt(struct sunrpc_net *sn)
162{
163 mutex_lock(&sn->gssp_lock);
164 if (sn->gssp_clnt) {
165 rpc_shutdown_client(sn->gssp_clnt);
166 sn->gssp_clnt = NULL;
167 }
168 mutex_unlock(&sn->gssp_lock);
169}
170
171static struct rpc_clnt *get_gssp_clnt(struct sunrpc_net *sn)
172{
173 struct rpc_clnt *clnt;
174
175 mutex_lock(&sn->gssp_lock);
176 clnt = sn->gssp_clnt;
177 if (clnt)
178 atomic_inc(&clnt->cl_count);
179 mutex_unlock(&sn->gssp_lock);
180 return clnt;
181}
182
183static int gssp_call(struct net *net, struct rpc_message *msg)
184{
185 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
186 struct rpc_clnt *clnt;
187 int status;
188
189 clnt = get_gssp_clnt(sn);
190 if (!clnt)
191 return -EIO;
192 status = rpc_call_sync(clnt, msg, 0);
193 if (status < 0) {
194 dprintk("gssp: rpc_call returned error %d\n", -status);
195 switch (status) {
196 case -EPROTONOSUPPORT:
197 status = -EINVAL;
198 break;
199 case -ECONNREFUSED:
200 case -ETIMEDOUT:
201 case -ENOTCONN:
202 status = -EAGAIN;
203 break;
204 case -ERESTARTSYS:
205 if (signalled ())
206 status = -EINTR;
207 break;
208 default:
209 break;
210 }
211 }
212 rpc_release_client(clnt);
213 return status;
214}
215
216
217/*
218 * Public functions
219 */
220
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 + \
225 GSSX_max_oid_sz + \
226 GSSX_max_princ_sz + \
227 sizeof(struct svc_cred))
228
229int gssp_accept_sec_context_upcall(struct net *net,
230 struct gssp_upcall_data *data)
231{
232 struct gssx_ctx ctxh = {
233 .state = data->in_handle
234 };
235 struct gssx_arg_accept_sec_context arg = {
236 .input_token = data->in_token,
237 };
238 struct gssx_ctx rctxh = {
239 /*
240 * pass in the max length we expect for each of these
241 * buffers but let the xdr code kmalloc them:
242 */
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
246 };
247 struct gssx_res_accept_sec_context res = {
248 .context_handle = &rctxh,
249 .output_token = &data->out_token
250 };
251 struct rpc_message msg = {
252 .rpc_proc = &gssp_procedures[GSSX_ACCEPT_SEC_CONTEXT],
253 .rpc_argp = &arg,
254 .rpc_resp = &res,
255 .rpc_cred = NULL, /* FIXME ? */
256 };
257 struct xdr_netobj client_name = { 0 , NULL };
258 int ret;
259
260 if (data->in_handle.len != 0)
261 arg.context_handle = &ctxh;
262 res.output_token->len = GSSX_max_output_token_sz;
263
264 /* use nfs/ for targ_name ? */
265
266 ret = gssp_call(net, &msg);
267
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,
276 data->mech_oid.len);
277 client_name = rctxh.src_name.display_name;
278 }
279
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
284 * option name */
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;
289 }
290 /* whether we use it or not, free data */
291 kfree(value->data);
292 }
293
294 if (res.options.count != 0) {
295 kfree(res.options.data);
296 }
297
298 /* convert to GSS_NT_HOSTBASED_SERVICE form and set into creds */
299 if (data->found_creds && client_name.data != NULL) {
300 char *c;
301
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, '@');
307 if (c) {
308 *c = '\0';
309
310 /* change service-hostname delimiter */
311 c = strchr(data->creds.cr_principal, '/');
312 if (c) *c = '@';
313 }
314 if (!c) {
315 /* not a service principal */
316 kfree(data->creds.cr_principal);
317 data->creds.cr_principal = NULL;
318 }
319 }
320 }
321 kfree(client_name.data);
322
323 return ret;
324}
325
326void gssp_free_upcall_data(struct gssp_upcall_data *data)
327{
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);
333}
334
335/*
336 * Initialization stuff
337 */
338
339static const struct rpc_version gssp_version1 = {
340 .number = GSSPROXY_VERS_1,
341 .nrprocs = ARRAY_SIZE(gssp_procedures),
342 .procs = gssp_procedures,
343};
344
345static const struct rpc_version *gssp_version[] = {
346 NULL,
347 &gssp_version1,
348};
349
350static struct rpc_stat gssp_stats;
351
352static const struct rpc_program gssp_program = {
353 .name = "gssproxy",
354 .number = GSSPROXY_PROGRAM,
355 .nrvers = ARRAY_SIZE(gssp_version),
356 .version = gssp_version,
357 .stats = &gssp_stats,
358};
diff --git a/net/sunrpc/auth_gss/gss_rpc_upcall.h b/net/sunrpc/auth_gss/gss_rpc_upcall.h
new file mode 100644
index 000000000000..1e542aded90a
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_rpc_upcall.h
@@ -0,0 +1,48 @@
1/*
2 * linux/net/sunrpc/gss_rpc_upcall.h
3 *
4 * Copyright (C) 2012 Simo Sorce <simo@redhat.com>
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 as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
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.
15 *
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.
19 */
20
21#ifndef _GSS_RPC_UPCALL_H
22#define _GSS_RPC_UPCALL_H
23
24#include <linux/sunrpc/gss_api.h>
25#include <linux/sunrpc/auth_gss.h>
26#include "gss_rpc_xdr.h"
27#include "../netns.h"
28
29struct gssp_upcall_data {
30 struct xdr_netobj in_handle;
31 struct gssp_in_token in_token;
32 struct xdr_netobj out_handle;
33 struct xdr_netobj out_token;
34 struct rpcsec_gss_oid mech_oid;
35 struct svc_cred creds;
36 int found_creds;
37 int major_status;
38 int minor_status;
39};
40
41int gssp_accept_sec_context_upcall(struct net *net,
42 struct gssp_upcall_data *data);
43void gssp_free_upcall_data(struct gssp_upcall_data *data);
44
45void init_gssp_clnt(struct sunrpc_net *);
46int set_gssp_clnt(struct net *);
47void clear_gssp_clnt(struct sunrpc_net *);
48#endif /* _GSS_RPC_UPCALL_H */
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.c b/net/sunrpc/auth_gss/gss_rpc_xdr.c
new file mode 100644
index 000000000000..5c4c61d527e2
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c
@@ -0,0 +1,838 @@
1/*
2 * GSS Proxy upcall module
3 *
4 * Copyright (C) 2012 Simo Sorce <simo@redhat.com>
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 as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
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.
15 *
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.
19 */
20
21#include <linux/sunrpc/svcauth.h>
22#include "gss_rpc_xdr.h"
23
24static bool gssx_check_pointer(struct xdr_stream *xdr)
25{
26 __be32 *p;
27
28 p = xdr_reserve_space(xdr, 4);
29 if (unlikely(p == NULL))
30 return -ENOSPC;
31 return *p?true:false;
32}
33
34static int gssx_enc_bool(struct xdr_stream *xdr, int v)
35{
36 __be32 *p;
37
38 p = xdr_reserve_space(xdr, 4);
39 if (unlikely(p == NULL))
40 return -ENOSPC;
41 *p = v ? xdr_one : xdr_zero;
42 return 0;
43}
44
45static int gssx_dec_bool(struct xdr_stream *xdr, u32 *v)
46{
47 __be32 *p;
48
49 p = xdr_inline_decode(xdr, 4);
50 if (unlikely(p == NULL))
51 return -ENOSPC;
52 *v = be32_to_cpu(*p);
53 return 0;
54}
55
56static int gssx_enc_buffer(struct xdr_stream *xdr,
57 gssx_buffer *buf)
58{
59 __be32 *p;
60
61 p = xdr_reserve_space(xdr, sizeof(u32) + buf->len);
62 if (!p)
63 return -ENOSPC;
64 xdr_encode_opaque(p, buf->data, buf->len);
65 return 0;
66}
67
68static int gssx_enc_in_token(struct xdr_stream *xdr,
69 struct gssp_in_token *in)
70{
71 __be32 *p;
72
73 p = xdr_reserve_space(xdr, 4);
74 if (!p)
75 return -ENOSPC;
76 *p = cpu_to_be32(in->page_len);
77
78 /* all we need to do is to write pages */
79 xdr_write_pages(xdr, in->pages, in->page_base, in->page_len);
80
81 return 0;
82}
83
84
85static int gssx_dec_buffer(struct xdr_stream *xdr,
86 gssx_buffer *buf)
87{
88 u32 length;
89 __be32 *p;
90
91 p = xdr_inline_decode(xdr, 4);
92 if (unlikely(p == NULL))
93 return -ENOSPC;
94
95 length = be32_to_cpup(p);
96 p = xdr_inline_decode(xdr, length);
97 if (unlikely(p == NULL))
98 return -ENOSPC;
99
100 if (buf->len == 0) {
101 /* we intentionally are not interested in this buffer */
102 return 0;
103 }
104 if (length > buf->len)
105 return -ENOSPC;
106
107 if (!buf->data) {
108 buf->data = kmemdup(p, length, GFP_KERNEL);
109 if (!buf->data)
110 return -ENOMEM;
111 } else {
112 memcpy(buf->data, p, length);
113 }
114 buf->len = length;
115 return 0;
116}
117
118static int gssx_enc_option(struct xdr_stream *xdr,
119 struct gssx_option *opt)
120{
121 int err;
122
123 err = gssx_enc_buffer(xdr, &opt->option);
124 if (err)
125 return err;
126 err = gssx_enc_buffer(xdr, &opt->value);
127 return err;
128}
129
130static int gssx_dec_option(struct xdr_stream *xdr,
131 struct gssx_option *opt)
132{
133 int err;
134
135 err = gssx_dec_buffer(xdr, &opt->option);
136 if (err)
137 return err;
138 err = gssx_dec_buffer(xdr, &opt->value);
139 return err;
140}
141
142static int dummy_enc_opt_array(struct xdr_stream *xdr,
143 struct gssx_option_array *oa)
144{
145 __be32 *p;
146
147 if (oa->count != 0)
148 return -EINVAL;
149
150 p = xdr_reserve_space(xdr, 4);
151 if (!p)
152 return -ENOSPC;
153 *p = 0;
154
155 return 0;
156}
157
158static int dummy_dec_opt_array(struct xdr_stream *xdr,
159 struct gssx_option_array *oa)
160{
161 struct gssx_option dummy;
162 u32 count, i;
163 __be32 *p;
164
165 p = xdr_inline_decode(xdr, 4);
166 if (unlikely(p == NULL))
167 return -ENOSPC;
168 count = be32_to_cpup(p++);
169 memset(&dummy, 0, sizeof(dummy));
170 for (i = 0; i < count; i++) {
171 gssx_dec_option(xdr, &dummy);
172 }
173
174 oa->count = 0;
175 oa->data = NULL;
176 return 0;
177}
178
179static int get_s32(void **p, void *max, s32 *res)
180{
181 void *base = *p;
182 void *next = (void *)((char *)base + sizeof(s32));
183 if (unlikely(next > max || next < base))
184 return -EINVAL;
185 memcpy(res, base, sizeof(s32));
186 *p = next;
187 return 0;
188}
189
190static int gssx_dec_linux_creds(struct xdr_stream *xdr,
191 struct svc_cred *creds)
192{
193 u32 length;
194 __be32 *p;
195 void *q, *end;
196 s32 tmp;
197 int N, i, err;
198
199 p = xdr_inline_decode(xdr, 4);
200 if (unlikely(p == NULL))
201 return -ENOSPC;
202
203 length = be32_to_cpup(p);
204
205 /* FIXME: we do not want to use the scratch buffer for this one
206 * may need to use functions that allows us to access an io vector
207 * directly */
208 p = xdr_inline_decode(xdr, length);
209 if (unlikely(p == NULL))
210 return -ENOSPC;
211
212 q = p;
213 end = q + length;
214
215 /* uid */
216 err = get_s32(&q, end, &tmp);
217 if (err)
218 return err;
219 creds->cr_uid = make_kuid(&init_user_ns, tmp);
220
221 /* gid */
222 err = get_s32(&q, end, &tmp);
223 if (err)
224 return err;
225 creds->cr_gid = make_kgid(&init_user_ns, tmp);
226
227 /* number of additional gid's */
228 err = get_s32(&q, end, &tmp);
229 if (err)
230 return err;
231 N = tmp;
232 creds->cr_group_info = groups_alloc(N);
233 if (creds->cr_group_info == NULL)
234 return -ENOMEM;
235
236 /* gid's */
237 for (i = 0; i < N; i++) {
238 kgid_t kgid;
239 err = get_s32(&q, end, &tmp);
240 if (err)
241 goto out_free_groups;
242 err = -EINVAL;
243 kgid = make_kgid(&init_user_ns, tmp);
244 if (!gid_valid(kgid))
245 goto out_free_groups;
246 GROUP_AT(creds->cr_group_info, i) = kgid;
247 }
248
249 return 0;
250out_free_groups:
251 groups_free(creds->cr_group_info);
252 return err;
253}
254
255static int gssx_dec_option_array(struct xdr_stream *xdr,
256 struct gssx_option_array *oa)
257{
258 struct svc_cred *creds;
259 u32 count, i;
260 __be32 *p;
261 int err;
262
263 p = xdr_inline_decode(xdr, 4);
264 if (unlikely(p == NULL))
265 return -ENOSPC;
266 count = be32_to_cpup(p++);
267 if (count != 0) {
268 /* we recognize only 1 currently: CREDS_VALUE */
269 oa->count = 1;
270
271 oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL);
272 if (!oa->data)
273 return -ENOMEM;
274
275 creds = kmalloc(sizeof(struct svc_cred), GFP_KERNEL);
276 if (!creds) {
277 kfree(oa->data);
278 return -ENOMEM;
279 }
280
281 oa->data[0].option.data = CREDS_VALUE;
282 oa->data[0].option.len = sizeof(CREDS_VALUE);
283 oa->data[0].value.data = (void *)creds;
284 oa->data[0].value.len = 0;
285 }
286 for (i = 0; i < count; i++) {
287 gssx_buffer dummy = { 0, NULL };
288 u32 length;
289
290 /* option buffer */
291 p = xdr_inline_decode(xdr, 4);
292 if (unlikely(p == NULL))
293 return -ENOSPC;
294
295 length = be32_to_cpup(p);
296 p = xdr_inline_decode(xdr, length);
297 if (unlikely(p == NULL))
298 return -ENOSPC;
299
300 if (length == sizeof(CREDS_VALUE) &&
301 memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) {
302 /* We have creds here. parse them */
303 err = gssx_dec_linux_creds(xdr, creds);
304 if (err)
305 return err;
306 oa->data[0].value.len = 1; /* presence */
307 } else {
308 /* consume uninteresting buffer */
309 err = gssx_dec_buffer(xdr, &dummy);
310 if (err)
311 return err;
312 }
313 }
314 return 0;
315}
316
317static int gssx_dec_status(struct xdr_stream *xdr,
318 struct gssx_status *status)
319{
320 __be32 *p;
321 int err;
322
323 /* status->major_status */
324 p = xdr_inline_decode(xdr, 8);
325 if (unlikely(p == NULL))
326 return -ENOSPC;
327 p = xdr_decode_hyper(p, &status->major_status);
328
329 /* status->mech */
330 err = gssx_dec_buffer(xdr, &status->mech);
331 if (err)
332 return err;
333
334 /* status->minor_status */
335 p = xdr_inline_decode(xdr, 8);
336 if (unlikely(p == NULL))
337 return -ENOSPC;
338 p = xdr_decode_hyper(p, &status->minor_status);
339
340 /* status->major_status_string */
341 err = gssx_dec_buffer(xdr, &status->major_status_string);
342 if (err)
343 return err;
344
345 /* status->minor_status_string */
346 err = gssx_dec_buffer(xdr, &status->minor_status_string);
347 if (err)
348 return err;
349
350 /* status->server_ctx */
351 err = gssx_dec_buffer(xdr, &status->server_ctx);
352 if (err)
353 return err;
354
355 /* we assume we have no options for now, so simply consume them */
356 /* status->options */
357 err = dummy_dec_opt_array(xdr, &status->options);
358
359 return err;
360}
361
362static int gssx_enc_call_ctx(struct xdr_stream *xdr,
363 struct gssx_call_ctx *ctx)
364{
365 struct gssx_option opt;
366 __be32 *p;
367 int err;
368
369 /* ctx->locale */
370 err = gssx_enc_buffer(xdr, &ctx->locale);
371 if (err)
372 return err;
373
374 /* ctx->server_ctx */
375 err = gssx_enc_buffer(xdr, &ctx->server_ctx);
376 if (err)
377 return err;
378
379 /* we always want to ask for lucid contexts */
380 /* ctx->options */
381 p = xdr_reserve_space(xdr, 4);
382 *p = cpu_to_be32(2);
383
384 /* we want a lucid_v1 context */
385 opt.option.data = LUCID_OPTION;
386 opt.option.len = sizeof(LUCID_OPTION);
387 opt.value.data = LUCID_VALUE;
388 opt.value.len = sizeof(LUCID_VALUE);
389 err = gssx_enc_option(xdr, &opt);
390
391 /* ..and user creds */
392 opt.option.data = CREDS_OPTION;
393 opt.option.len = sizeof(CREDS_OPTION);
394 opt.value.data = CREDS_VALUE;
395 opt.value.len = sizeof(CREDS_VALUE);
396 err = gssx_enc_option(xdr, &opt);
397
398 return err;
399}
400
401static int gssx_dec_name_attr(struct xdr_stream *xdr,
402 struct gssx_name_attr *attr)
403{
404 int err;
405
406 /* attr->attr */
407 err = gssx_dec_buffer(xdr, &attr->attr);
408 if (err)
409 return err;
410
411 /* attr->value */
412 err = gssx_dec_buffer(xdr, &attr->value);
413 if (err)
414 return err;
415
416 /* attr->extensions */
417 err = dummy_dec_opt_array(xdr, &attr->extensions);
418
419 return err;
420}
421
422static int dummy_enc_nameattr_array(struct xdr_stream *xdr,
423 struct gssx_name_attr_array *naa)
424{
425 __be32 *p;
426
427 if (naa->count != 0)
428 return -EINVAL;
429
430 p = xdr_reserve_space(xdr, 4);
431 if (!p)
432 return -ENOSPC;
433 *p = 0;
434
435 return 0;
436}
437
438static int dummy_dec_nameattr_array(struct xdr_stream *xdr,
439 struct gssx_name_attr_array *naa)
440{
441 struct gssx_name_attr dummy;
442 u32 count, i;
443 __be32 *p;
444
445 p = xdr_inline_decode(xdr, 4);
446 if (unlikely(p == NULL))
447 return -ENOSPC;
448 count = be32_to_cpup(p++);
449 for (i = 0; i < count; i++) {
450 gssx_dec_name_attr(xdr, &dummy);
451 }
452
453 naa->count = 0;
454 naa->data = NULL;
455 return 0;
456}
457
458static struct xdr_netobj zero_netobj = {};
459
460static struct gssx_name_attr_array zero_name_attr_array = {};
461
462static struct gssx_option_array zero_option_array = {};
463
464static int gssx_enc_name(struct xdr_stream *xdr,
465 struct gssx_name *name)
466{
467 int err;
468
469 /* name->display_name */
470 err = gssx_enc_buffer(xdr, &name->display_name);
471 if (err)
472 return err;
473
474 /* name->name_type */
475 err = gssx_enc_buffer(xdr, &zero_netobj);
476 if (err)
477 return err;
478
479 /* name->exported_name */
480 err = gssx_enc_buffer(xdr, &zero_netobj);
481 if (err)
482 return err;
483
484 /* name->exported_composite_name */
485 err = gssx_enc_buffer(xdr, &zero_netobj);
486 if (err)
487 return err;
488
489 /* leave name_attributes empty for now, will add once we have any
490 * to pass up at all */
491 /* name->name_attributes */
492 err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array);
493 if (err)
494 return err;
495
496 /* leave options empty for now, will add once we have any options
497 * to pass up at all */
498 /* name->extensions */
499 err = dummy_enc_opt_array(xdr, &zero_option_array);
500
501 return err;
502}
503
504static int gssx_dec_name(struct xdr_stream *xdr,
505 struct gssx_name *name)
506{
507 struct xdr_netobj dummy_netobj;
508 struct gssx_name_attr_array dummy_name_attr_array;
509 struct gssx_option_array dummy_option_array;
510 int err;
511
512 /* name->display_name */
513 err = gssx_dec_buffer(xdr, &name->display_name);
514 if (err)
515 return err;
516
517 /* name->name_type */
518 err = gssx_dec_buffer(xdr, &dummy_netobj);
519 if (err)
520 return err;
521
522 /* name->exported_name */
523 err = gssx_dec_buffer(xdr, &dummy_netobj);
524 if (err)
525 return err;
526
527 /* name->exported_composite_name */
528 err = gssx_dec_buffer(xdr, &dummy_netobj);
529 if (err)
530 return err;
531
532 /* we assume we have no attributes for now, so simply consume them */
533 /* name->name_attributes */
534 err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array);
535 if (err)
536 return err;
537
538 /* we assume we have no options for now, so simply consume them */
539 /* name->extensions */
540 err = dummy_dec_opt_array(xdr, &dummy_option_array);
541
542 return err;
543}
544
545static int dummy_enc_credel_array(struct xdr_stream *xdr,
546 struct gssx_cred_element_array *cea)
547{
548 __be32 *p;
549
550 if (cea->count != 0)
551 return -EINVAL;
552
553 p = xdr_reserve_space(xdr, 4);
554 if (!p)
555 return -ENOSPC;
556 *p = 0;
557
558 return 0;
559}
560
561static int gssx_enc_cred(struct xdr_stream *xdr,
562 struct gssx_cred *cred)
563{
564 int err;
565
566 /* cred->desired_name */
567 err = gssx_enc_name(xdr, &cred->desired_name);
568 if (err)
569 return err;
570
571 /* cred->elements */
572 err = dummy_enc_credel_array(xdr, &cred->elements);
573
574 /* cred->cred_handle_reference */
575 err = gssx_enc_buffer(xdr, &cred->cred_handle_reference);
576 if (err)
577 return err;
578
579 /* cred->needs_release */
580 err = gssx_enc_bool(xdr, cred->needs_release);
581
582 return err;
583}
584
585static int gssx_enc_ctx(struct xdr_stream *xdr,
586 struct gssx_ctx *ctx)
587{
588 __be32 *p;
589 int err;
590
591 /* ctx->exported_context_token */
592 err = gssx_enc_buffer(xdr, &ctx->exported_context_token);
593 if (err)
594 return err;
595
596 /* ctx->state */
597 err = gssx_enc_buffer(xdr, &ctx->state);
598 if (err)
599 return err;
600
601 /* ctx->need_release */
602 err = gssx_enc_bool(xdr, ctx->need_release);
603 if (err)
604 return err;
605
606 /* ctx->mech */
607 err = gssx_enc_buffer(xdr, &ctx->mech);
608 if (err)
609 return err;
610
611 /* ctx->src_name */
612 err = gssx_enc_name(xdr, &ctx->src_name);
613 if (err)
614 return err;
615
616 /* ctx->targ_name */
617 err = gssx_enc_name(xdr, &ctx->targ_name);
618 if (err)
619 return err;
620
621 /* ctx->lifetime */
622 p = xdr_reserve_space(xdr, 8+8);
623 if (!p)
624 return -ENOSPC;
625 p = xdr_encode_hyper(p, ctx->lifetime);
626
627 /* ctx->ctx_flags */
628 p = xdr_encode_hyper(p, ctx->ctx_flags);
629
630 /* ctx->locally_initiated */
631 err = gssx_enc_bool(xdr, ctx->locally_initiated);
632 if (err)
633 return err;
634
635 /* ctx->open */
636 err = gssx_enc_bool(xdr, ctx->open);
637 if (err)
638 return err;
639
640 /* leave options empty for now, will add once we have any options
641 * to pass up at all */
642 /* ctx->options */
643 err = dummy_enc_opt_array(xdr, &ctx->options);
644
645 return err;
646}
647
648static int gssx_dec_ctx(struct xdr_stream *xdr,
649 struct gssx_ctx *ctx)
650{
651 __be32 *p;
652 int err;
653
654 /* ctx->exported_context_token */
655 err = gssx_dec_buffer(xdr, &ctx->exported_context_token);
656 if (err)
657 return err;
658
659 /* ctx->state */
660 err = gssx_dec_buffer(xdr, &ctx->state);
661 if (err)
662 return err;
663
664 /* ctx->need_release */
665 err = gssx_dec_bool(xdr, &ctx->need_release);
666 if (err)
667 return err;
668
669 /* ctx->mech */
670 err = gssx_dec_buffer(xdr, &ctx->mech);
671 if (err)
672 return err;
673
674 /* ctx->src_name */
675 err = gssx_dec_name(xdr, &ctx->src_name);
676 if (err)
677 return err;
678
679 /* ctx->targ_name */
680 err = gssx_dec_name(xdr, &ctx->targ_name);
681 if (err)
682 return err;
683
684 /* ctx->lifetime */
685 p = xdr_inline_decode(xdr, 8+8);
686 if (unlikely(p == NULL))
687 return -ENOSPC;
688 p = xdr_decode_hyper(p, &ctx->lifetime);
689
690 /* ctx->ctx_flags */
691 p = xdr_decode_hyper(p, &ctx->ctx_flags);
692
693 /* ctx->locally_initiated */
694 err = gssx_dec_bool(xdr, &ctx->locally_initiated);
695 if (err)
696 return err;
697
698 /* ctx->open */
699 err = gssx_dec_bool(xdr, &ctx->open);
700 if (err)
701 return err;
702
703 /* we assume we have no options for now, so simply consume them */
704 /* ctx->options */
705 err = dummy_dec_opt_array(xdr, &ctx->options);
706
707 return err;
708}
709
710static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb)
711{
712 __be32 *p;
713 int err;
714
715 /* cb->initiator_addrtype */
716 p = xdr_reserve_space(xdr, 8);
717 if (!p)
718 return -ENOSPC;
719 p = xdr_encode_hyper(p, cb->initiator_addrtype);
720
721 /* cb->initiator_address */
722 err = gssx_enc_buffer(xdr, &cb->initiator_address);
723 if (err)
724 return err;
725
726 /* cb->acceptor_addrtype */
727 p = xdr_reserve_space(xdr, 8);
728 if (!p)
729 return -ENOSPC;
730 p = xdr_encode_hyper(p, cb->acceptor_addrtype);
731
732 /* cb->acceptor_address */
733 err = gssx_enc_buffer(xdr, &cb->acceptor_address);
734 if (err)
735 return err;
736
737 /* cb->application_data */
738 err = gssx_enc_buffer(xdr, &cb->application_data);
739
740 return err;
741}
742
743void gssx_enc_accept_sec_context(struct rpc_rqst *req,
744 struct xdr_stream *xdr,
745 struct gssx_arg_accept_sec_context *arg)
746{
747 int err;
748
749 err = gssx_enc_call_ctx(xdr, &arg->call_ctx);
750 if (err)
751 goto done;
752
753 /* arg->context_handle */
754 if (arg->context_handle) {
755 err = gssx_enc_ctx(xdr, arg->context_handle);
756 if (err)
757 goto done;
758 } else {
759 err = gssx_enc_bool(xdr, 0);
760 }
761
762 /* arg->cred_handle */
763 if (arg->cred_handle) {
764 err = gssx_enc_cred(xdr, arg->cred_handle);
765 if (err)
766 goto done;
767 } else {
768 err = gssx_enc_bool(xdr, 0);
769 }
770
771 /* arg->input_token */
772 err = gssx_enc_in_token(xdr, &arg->input_token);
773 if (err)
774 goto done;
775
776 /* arg->input_cb */
777 if (arg->input_cb) {
778 err = gssx_enc_cb(xdr, arg->input_cb);
779 if (err)
780 goto done;
781 } else {
782 err = gssx_enc_bool(xdr, 0);
783 }
784
785 err = gssx_enc_bool(xdr, arg->ret_deleg_cred);
786 if (err)
787 goto done;
788
789 /* leave options empty for now, will add once we have any options
790 * to pass up at all */
791 /* arg->options */
792 err = dummy_enc_opt_array(xdr, &arg->options);
793
794done:
795 if (err)
796 dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err);
797}
798
799int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
800 struct xdr_stream *xdr,
801 struct gssx_res_accept_sec_context *res)
802{
803 int err;
804
805 /* res->status */
806 err = gssx_dec_status(xdr, &res->status);
807 if (err)
808 return err;
809
810 /* res->context_handle */
811 if (gssx_check_pointer(xdr)) {
812 err = gssx_dec_ctx(xdr, res->context_handle);
813 if (err)
814 return err;
815 } else {
816 res->context_handle = NULL;
817 }
818
819 /* res->output_token */
820 if (gssx_check_pointer(xdr)) {
821 err = gssx_dec_buffer(xdr, res->output_token);
822 if (err)
823 return err;
824 } else {
825 res->output_token = NULL;
826 }
827
828 /* res->delegated_cred_handle */
829 if (gssx_check_pointer(xdr)) {
830 /* we do not support upcall servers sending this data. */
831 return -EINVAL;
832 }
833
834 /* res->options */
835 err = gssx_dec_option_array(xdr, &res->options);
836
837 return err;
838}
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.h b/net/sunrpc/auth_gss/gss_rpc_xdr.h
new file mode 100644
index 000000000000..1c98b27d870c
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_rpc_xdr.h
@@ -0,0 +1,264 @@
1/*
2 * GSS Proxy upcall module
3 *
4 * Copyright (C) 2012 Simo Sorce <simo@redhat.com>
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 as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
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.
15 *
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.
19 */
20
21#ifndef _LINUX_GSS_RPC_XDR_H
22#define _LINUX_GSS_RPC_XDR_H
23
24#include <linux/sunrpc/xdr.h>
25#include <linux/sunrpc/clnt.h>
26#include <linux/sunrpc/xprtsock.h>
27
28#ifdef RPC_DEBUG
29# define RPCDBG_FACILITY RPCDBG_AUTH
30#endif
31
32#define LUCID_OPTION "exported_context_type"
33#define LUCID_VALUE "linux_lucid_v1"
34#define CREDS_OPTION "exported_creds_type"
35#define CREDS_VALUE "linux_creds_v1"
36
37typedef struct xdr_netobj gssx_buffer;
38typedef struct xdr_netobj utf8string;
39typedef struct xdr_netobj gssx_OID;
40
41enum gssx_cred_usage {
42 GSSX_C_INITIATE = 1,
43 GSSX_C_ACCEPT = 2,
44 GSSX_C_BOTH = 3,
45};
46
47struct gssx_option {
48 gssx_buffer option;
49 gssx_buffer value;
50};
51
52struct gssx_option_array {
53 u32 count;
54 struct gssx_option *data;
55};
56
57struct gssx_status {
58 u64 major_status;
59 gssx_OID mech;
60 u64 minor_status;
61 utf8string major_status_string;
62 utf8string minor_status_string;
63 gssx_buffer server_ctx;
64 struct gssx_option_array options;
65};
66
67struct gssx_call_ctx {
68 utf8string locale;
69 gssx_buffer server_ctx;
70 struct gssx_option_array options;
71};
72
73struct gssx_name_attr {
74 gssx_buffer attr;
75 gssx_buffer value;
76 struct gssx_option_array extensions;
77};
78
79struct gssx_name_attr_array {
80 u32 count;
81 struct gssx_name_attr *data;
82};
83
84struct gssx_name {
85 gssx_buffer display_name;
86};
87typedef struct gssx_name gssx_name;
88
89struct gssx_cred_element {
90 gssx_name MN;
91 gssx_OID mech;
92 u32 cred_usage;
93 u64 initiator_time_rec;
94 u64 acceptor_time_rec;
95 struct gssx_option_array options;
96};
97
98struct gssx_cred_element_array {
99 u32 count;
100 struct gssx_cred_element *data;
101};
102
103struct gssx_cred {
104 gssx_name desired_name;
105 struct gssx_cred_element_array elements;
106 gssx_buffer cred_handle_reference;
107 u32 needs_release;
108};
109
110struct gssx_ctx {
111 gssx_buffer exported_context_token;
112 gssx_buffer state;
113 u32 need_release;
114 gssx_OID mech;
115 gssx_name src_name;
116 gssx_name targ_name;
117 u64 lifetime;
118 u64 ctx_flags;
119 u32 locally_initiated;
120 u32 open;
121 struct gssx_option_array options;
122};
123
124struct gssx_cb {
125 u64 initiator_addrtype;
126 gssx_buffer initiator_address;
127 u64 acceptor_addrtype;
128 gssx_buffer acceptor_address;
129 gssx_buffer application_data;
130};
131
132
133/* This structure is not defined in the protocol.
134 * It is used in the kernel to carry around a big buffer
135 * as a set of pages */
136struct gssp_in_token {
137 struct page **pages; /* Array of contiguous pages */
138 unsigned int page_base; /* Start of page data */
139 unsigned int page_len; /* Length of page data */
140};
141
142struct gssx_arg_accept_sec_context {
143 struct gssx_call_ctx call_ctx;
144 struct gssx_ctx *context_handle;
145 struct gssx_cred *cred_handle;
146 struct gssp_in_token input_token;
147 struct gssx_cb *input_cb;
148 u32 ret_deleg_cred;
149 struct gssx_option_array options;
150};
151
152struct gssx_res_accept_sec_context {
153 struct gssx_status status;
154 struct gssx_ctx *context_handle;
155 gssx_buffer *output_token;
156 /* struct gssx_cred *delegated_cred_handle; not used in kernel */
157 struct gssx_option_array options;
158};
159
160
161
162#define gssx_enc_indicate_mechs NULL
163#define gssx_dec_indicate_mechs NULL
164#define gssx_enc_get_call_context NULL
165#define gssx_dec_get_call_context NULL
166#define gssx_enc_import_and_canon_name NULL
167#define gssx_dec_import_and_canon_name NULL
168#define gssx_enc_export_cred NULL
169#define gssx_dec_export_cred NULL
170#define gssx_enc_import_cred NULL
171#define gssx_dec_import_cred NULL
172#define gssx_enc_acquire_cred NULL
173#define gssx_dec_acquire_cred NULL
174#define gssx_enc_store_cred NULL
175#define gssx_dec_store_cred NULL
176#define gssx_enc_init_sec_context NULL
177#define gssx_dec_init_sec_context NULL
178void gssx_enc_accept_sec_context(struct rpc_rqst *req,
179 struct xdr_stream *xdr,
180 struct gssx_arg_accept_sec_context *args);
181int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
182 struct xdr_stream *xdr,
183 struct gssx_res_accept_sec_context *res);
184#define gssx_enc_release_handle NULL
185#define gssx_dec_release_handle NULL
186#define gssx_enc_get_mic NULL
187#define gssx_dec_get_mic NULL
188#define gssx_enc_verify NULL
189#define gssx_dec_verify NULL
190#define gssx_enc_wrap NULL
191#define gssx_dec_wrap NULL
192#define gssx_enc_unwrap NULL
193#define gssx_dec_unwrap NULL
194#define gssx_enc_wrap_size_limit NULL
195#define gssx_dec_wrap_size_limit NULL
196
197/* non implemented calls are set to 0 size */
198#define GSSX_ARG_indicate_mechs_sz 0
199#define GSSX_RES_indicate_mechs_sz 0
200#define GSSX_ARG_get_call_context_sz 0
201#define GSSX_RES_get_call_context_sz 0
202#define GSSX_ARG_import_and_canon_name_sz 0
203#define GSSX_RES_import_and_canon_name_sz 0
204#define GSSX_ARG_export_cred_sz 0
205#define GSSX_RES_export_cred_sz 0
206#define GSSX_ARG_import_cred_sz 0
207#define GSSX_RES_import_cred_sz 0
208#define GSSX_ARG_acquire_cred_sz 0
209#define GSSX_RES_acquire_cred_sz 0
210#define GSSX_ARG_store_cred_sz 0
211#define GSSX_RES_store_cred_sz 0
212#define GSSX_ARG_init_sec_context_sz 0
213#define GSSX_RES_init_sec_context_sz 0
214
215#define GSSX_default_in_call_ctx_sz (4 + 4 + 4 + \
216 8 + sizeof(LUCID_OPTION) + sizeof(LUCID_VALUE) + \
217 8 + sizeof(CREDS_OPTION) + sizeof(CREDS_VALUE))
218#define GSSX_default_in_ctx_hndl_sz (4 + 4+8 + 4 + 4 + 6*4 + 6*4 + 8 + 8 + \
219 4 + 4 + 4)
220#define GSSX_default_in_cred_sz 4 /* we send in no cred_handle */
221#define GSSX_default_in_token_sz 4 /* does *not* include token data */
222#define GSSX_default_in_cb_sz 4 /* we do not use channel bindings */
223#define GSSX_ARG_accept_sec_context_sz (GSSX_default_in_call_ctx_sz + \
224 GSSX_default_in_ctx_hndl_sz + \
225 GSSX_default_in_cred_sz + \
226 GSSX_default_in_token_sz + \
227 GSSX_default_in_cb_sz + \
228 4 /* no deleg creds boolean */ + \
229 4) /* empty options */
230
231/* somewhat arbitrary numbers but large enough (we ignore some of the data
232 * sent down, but it is part of the protocol so we need enough space to take
233 * it in) */
234#define GSSX_default_status_sz 8 + 24 + 8 + 256 + 256 + 16 + 4
235#define GSSX_max_output_handle_sz 128
236#define GSSX_max_oid_sz 16
237#define GSSX_max_princ_sz 256
238#define GSSX_default_ctx_sz (GSSX_max_output_handle_sz + \
239 16 + 4 + GSSX_max_oid_sz + \
240 2 * GSSX_max_princ_sz + \
241 8 + 8 + 4 + 4 + 4)
242#define GSSX_max_output_token_sz 1024
243#define GSSX_max_creds_sz (4 + 4 + 4 + NGROUPS_MAX * 4)
244#define GSSX_RES_accept_sec_context_sz (GSSX_default_status_sz + \
245 GSSX_default_ctx_sz + \
246 GSSX_max_output_token_sz + \
247 4 + GSSX_max_creds_sz)
248
249#define GSSX_ARG_release_handle_sz 0
250#define GSSX_RES_release_handle_sz 0
251#define GSSX_ARG_get_mic_sz 0
252#define GSSX_RES_get_mic_sz 0
253#define GSSX_ARG_verify_sz 0
254#define GSSX_RES_verify_sz 0
255#define GSSX_ARG_wrap_sz 0
256#define GSSX_RES_wrap_sz 0
257#define GSSX_ARG_unwrap_sz 0
258#define GSSX_RES_unwrap_sz 0
259#define GSSX_ARG_wrap_size_limit_sz 0
260#define GSSX_RES_wrap_size_limit_sz 0
261
262
263
264#endif /* _LINUX_GSS_RPC_XDR_H */
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index c3ba570222dc..871c73c92165 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -48,8 +48,8 @@
48#include <linux/sunrpc/svcauth.h> 48#include <linux/sunrpc/svcauth.h>
49#include <linux/sunrpc/svcauth_gss.h> 49#include <linux/sunrpc/svcauth_gss.h>
50#include <linux/sunrpc/cache.h> 50#include <linux/sunrpc/cache.h>
51#include "gss_rpc_upcall.h"
51 52
52#include "../netns.h"
53 53
54#ifdef RPC_DEBUG 54#ifdef RPC_DEBUG
55# define RPCDBG_FACILITY RPCDBG_AUTH 55# define RPCDBG_FACILITY RPCDBG_AUTH
@@ -497,7 +497,8 @@ static int rsc_parse(struct cache_detail *cd,
497 len = qword_get(&mesg, buf, mlen); 497 len = qword_get(&mesg, buf, mlen);
498 if (len < 0) 498 if (len < 0)
499 goto out; 499 goto out;
500 status = gss_import_sec_context(buf, len, gm, &rsci.mechctx, GFP_KERNEL); 500 status = gss_import_sec_context(buf, len, gm, &rsci.mechctx,
501 NULL, GFP_KERNEL);
501 if (status) 502 if (status)
502 goto out; 503 goto out;
503 504
@@ -505,8 +506,10 @@ static int rsc_parse(struct cache_detail *cd,
505 len = qword_get(&mesg, buf, mlen); 506 len = qword_get(&mesg, buf, mlen);
506 if (len > 0) { 507 if (len > 0) {
507 rsci.cred.cr_principal = kstrdup(buf, GFP_KERNEL); 508 rsci.cred.cr_principal = kstrdup(buf, GFP_KERNEL);
508 if (!rsci.cred.cr_principal) 509 if (!rsci.cred.cr_principal) {
510 status = -ENOMEM;
509 goto out; 511 goto out;
512 }
510 } 513 }
511 514
512 } 515 }
@@ -987,13 +990,10 @@ gss_write_init_verf(struct cache_detail *cd, struct svc_rqst *rqstp,
987} 990}
988 991
989static inline int 992static inline int
990gss_read_verf(struct rpc_gss_wire_cred *gc, 993gss_read_common_verf(struct rpc_gss_wire_cred *gc,
991 struct kvec *argv, __be32 *authp, 994 struct kvec *argv, __be32 *authp,
992 struct xdr_netobj *in_handle, 995 struct xdr_netobj *in_handle)
993 struct xdr_netobj *in_token)
994{ 996{
995 struct xdr_netobj tmpobj;
996
997 /* Read the verifier; should be NULL: */ 997 /* Read the verifier; should be NULL: */
998 *authp = rpc_autherr_badverf; 998 *authp = rpc_autherr_badverf;
999 if (argv->iov_len < 2 * 4) 999 if (argv->iov_len < 2 * 4)
@@ -1009,6 +1009,23 @@ gss_read_verf(struct rpc_gss_wire_cred *gc,
1009 if (dup_netobj(in_handle, &gc->gc_ctx)) 1009 if (dup_netobj(in_handle, &gc->gc_ctx))
1010 return SVC_CLOSE; 1010 return SVC_CLOSE;
1011 *authp = rpc_autherr_badverf; 1011 *authp = rpc_autherr_badverf;
1012
1013 return 0;
1014}
1015
1016static inline int
1017gss_read_verf(struct rpc_gss_wire_cred *gc,
1018 struct kvec *argv, __be32 *authp,
1019 struct xdr_netobj *in_handle,
1020 struct xdr_netobj *in_token)
1021{
1022 struct xdr_netobj tmpobj;
1023 int res;
1024
1025 res = gss_read_common_verf(gc, argv, authp, in_handle);
1026 if (res)
1027 return res;
1028
1012 if (svc_safe_getnetobj(argv, &tmpobj)) { 1029 if (svc_safe_getnetobj(argv, &tmpobj)) {
1013 kfree(in_handle->data); 1030 kfree(in_handle->data);
1014 return SVC_DENIED; 1031 return SVC_DENIED;
@@ -1021,6 +1038,40 @@ gss_read_verf(struct rpc_gss_wire_cred *gc,
1021 return 0; 1038 return 0;
1022} 1039}
1023 1040
1041/* Ok this is really heavily depending on a set of semantics in
1042 * how rqstp is set up by svc_recv and pages laid down by the
1043 * server when reading a request. We are basically guaranteed that
1044 * the token lays all down linearly across a set of pages, starting
1045 * at iov_base in rq_arg.head[0] which happens to be the first of a
1046 * set of pages stored in rq_pages[].
1047 * rq_arg.head[0].iov_base will provide us the page_base to pass
1048 * to the upcall.
1049 */
1050static inline int
1051gss_read_proxy_verf(struct svc_rqst *rqstp,
1052 struct rpc_gss_wire_cred *gc, __be32 *authp,
1053 struct xdr_netobj *in_handle,
1054 struct gssp_in_token *in_token)
1055{
1056 struct kvec *argv = &rqstp->rq_arg.head[0];
1057 u32 inlen;
1058 int res;
1059
1060 res = gss_read_common_verf(gc, argv, authp, in_handle);
1061 if (res)
1062 return res;
1063
1064 inlen = svc_getnl(argv);
1065 if (inlen > (argv->iov_len + rqstp->rq_arg.page_len))
1066 return SVC_DENIED;
1067
1068 in_token->pages = rqstp->rq_pages;
1069 in_token->page_base = (ulong)argv->iov_base & ~PAGE_MASK;
1070 in_token->page_len = inlen;
1071
1072 return 0;
1073}
1074
1024static inline int 1075static inline int
1025gss_write_resv(struct kvec *resv, size_t size_limit, 1076gss_write_resv(struct kvec *resv, size_t size_limit,
1026 struct xdr_netobj *out_handle, struct xdr_netobj *out_token, 1077 struct xdr_netobj *out_handle, struct xdr_netobj *out_token,
@@ -1048,7 +1099,7 @@ gss_write_resv(struct kvec *resv, size_t size_limit,
1048 * the upcall results are available, write the verifier and result. 1099 * the upcall results are available, write the verifier and result.
1049 * Otherwise, drop the request pending an answer to the upcall. 1100 * Otherwise, drop the request pending an answer to the upcall.
1050 */ 1101 */
1051static int svcauth_gss_handle_init(struct svc_rqst *rqstp, 1102static int svcauth_gss_legacy_init(struct svc_rqst *rqstp,
1052 struct rpc_gss_wire_cred *gc, __be32 *authp) 1103 struct rpc_gss_wire_cred *gc, __be32 *authp)
1053{ 1104{
1054 struct kvec *argv = &rqstp->rq_arg.head[0]; 1105 struct kvec *argv = &rqstp->rq_arg.head[0];
@@ -1088,6 +1139,287 @@ out:
1088 return ret; 1139 return ret;
1089} 1140}
1090 1141
1142static int gss_proxy_save_rsc(struct cache_detail *cd,
1143 struct gssp_upcall_data *ud,
1144 uint64_t *handle)
1145{
1146 struct rsc rsci, *rscp = NULL;
1147 static atomic64_t ctxhctr;
1148 long long ctxh;
1149 struct gss_api_mech *gm = NULL;
1150 time_t expiry;
1151 int status = -EINVAL;
1152
1153 memset(&rsci, 0, sizeof(rsci));
1154 /* context handle */
1155 status = -ENOMEM;
1156 /* the handle needs to be just a unique id,
1157 * use a static counter */
1158 ctxh = atomic64_inc_return(&ctxhctr);
1159
1160 /* make a copy for the caller */
1161 *handle = ctxh;
1162
1163 /* make a copy for the rsc cache */
1164 if (dup_to_netobj(&rsci.handle, (char *)handle, sizeof(uint64_t)))
1165 goto out;
1166 rscp = rsc_lookup(cd, &rsci);
1167 if (!rscp)
1168 goto out;
1169
1170 /* creds */
1171 if (!ud->found_creds) {
1172 /* userspace seem buggy, we should always get at least a
1173 * mapping to nobody */
1174 dprintk("RPC: No creds found, marking Negative!\n");
1175 set_bit(CACHE_NEGATIVE, &rsci.h.flags);
1176 } else {
1177
1178 /* steal creds */
1179 rsci.cred = ud->creds;
1180 memset(&ud->creds, 0, sizeof(struct svc_cred));
1181
1182 status = -EOPNOTSUPP;
1183 /* get mech handle from OID */
1184 gm = gss_mech_get_by_OID(&ud->mech_oid);
1185 if (!gm)
1186 goto out;
1187
1188 status = -EINVAL;
1189 /* mech-specific data: */
1190 status = gss_import_sec_context(ud->out_handle.data,
1191 ud->out_handle.len,
1192 gm, &rsci.mechctx,
1193 &expiry, GFP_KERNEL);
1194 if (status)
1195 goto out;
1196 }
1197
1198 rsci.h.expiry_time = expiry;
1199 rscp = rsc_update(cd, &rsci, rscp);
1200 status = 0;
1201out:
1202 gss_mech_put(gm);
1203 rsc_free(&rsci);
1204 if (rscp)
1205 cache_put(&rscp->h, cd);
1206 else
1207 status = -ENOMEM;
1208 return status;
1209}
1210
1211static int svcauth_gss_proxy_init(struct svc_rqst *rqstp,
1212 struct rpc_gss_wire_cred *gc, __be32 *authp)
1213{
1214 struct kvec *resv = &rqstp->rq_res.head[0];
1215 struct xdr_netobj cli_handle;
1216 struct gssp_upcall_data ud;
1217 uint64_t handle;
1218 int status;
1219 int ret;
1220 struct net *net = rqstp->rq_xprt->xpt_net;
1221 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1222
1223 memset(&ud, 0, sizeof(ud));
1224 ret = gss_read_proxy_verf(rqstp, gc, authp,
1225 &ud.in_handle, &ud.in_token);
1226 if (ret)
1227 return ret;
1228
1229 ret = SVC_CLOSE;
1230
1231 /* Perform synchronous upcall to gss-proxy */
1232 status = gssp_accept_sec_context_upcall(net, &ud);
1233 if (status)
1234 goto out;
1235
1236 dprintk("RPC: svcauth_gss: gss major status = %d\n",
1237 ud.major_status);
1238
1239 switch (ud.major_status) {
1240 case GSS_S_CONTINUE_NEEDED:
1241 cli_handle = ud.out_handle;
1242 break;
1243 case GSS_S_COMPLETE:
1244 status = gss_proxy_save_rsc(sn->rsc_cache, &ud, &handle);
1245 if (status)
1246 goto out;
1247 cli_handle.data = (u8 *)&handle;
1248 cli_handle.len = sizeof(handle);
1249 break;
1250 default:
1251 ret = SVC_CLOSE;
1252 goto out;
1253 }
1254
1255 /* Got an answer to the upcall; use it: */
1256 if (gss_write_init_verf(sn->rsc_cache, rqstp,
1257 &cli_handle, &ud.major_status))
1258 goto out;
1259 if (gss_write_resv(resv, PAGE_SIZE,
1260 &cli_handle, &ud.out_token,
1261 ud.major_status, ud.minor_status))
1262 goto out;
1263
1264 ret = SVC_COMPLETE;
1265out:
1266 gssp_free_upcall_data(&ud);
1267 return ret;
1268}
1269
1270DEFINE_SPINLOCK(use_gssp_lock);
1271
1272static bool use_gss_proxy(struct net *net)
1273{
1274 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1275
1276 if (sn->use_gss_proxy != -1)
1277 return sn->use_gss_proxy;
1278 spin_lock(&use_gssp_lock);
1279 /*
1280 * If you wanted gss-proxy, you should have said so before
1281 * starting to accept requests:
1282 */
1283 sn->use_gss_proxy = 0;
1284 spin_unlock(&use_gssp_lock);
1285 return 0;
1286}
1287
1288#ifdef CONFIG_PROC_FS
1289
1290static bool set_gss_proxy(struct net *net, int type)
1291{
1292 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1293 int ret = 0;
1294
1295 WARN_ON_ONCE(type != 0 && type != 1);
1296 spin_lock(&use_gssp_lock);
1297 if (sn->use_gss_proxy == -1 || sn->use_gss_proxy == type)
1298 sn->use_gss_proxy = type;
1299 else
1300 ret = -EBUSY;
1301 spin_unlock(&use_gssp_lock);
1302 wake_up(&sn->gssp_wq);
1303 return ret;
1304}
1305
1306static inline bool gssp_ready(struct sunrpc_net *sn)
1307{
1308 switch (sn->use_gss_proxy) {
1309 case -1:
1310 return false;
1311 case 0:
1312 return true;
1313 case 1:
1314 return sn->gssp_clnt;
1315 }
1316 WARN_ON_ONCE(1);
1317 return false;
1318}
1319
1320static int wait_for_gss_proxy(struct net *net)
1321{
1322 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1323
1324 return wait_event_interruptible(sn->gssp_wq, gssp_ready(sn));
1325}
1326
1327
1328static ssize_t write_gssp(struct file *file, const char __user *buf,
1329 size_t count, loff_t *ppos)
1330{
1331 struct net *net = PDE_DATA(file->f_path.dentry->d_inode);
1332 char tbuf[20];
1333 unsigned long i;
1334 int res;
1335
1336 if (*ppos || count > sizeof(tbuf)-1)
1337 return -EINVAL;
1338 if (copy_from_user(tbuf, buf, count))
1339 return -EFAULT;
1340
1341 tbuf[count] = 0;
1342 res = kstrtoul(tbuf, 0, &i);
1343 if (res)
1344 return res;
1345 if (i != 1)
1346 return -EINVAL;
1347 res = set_gss_proxy(net, 1);
1348 if (res)
1349 return res;
1350 res = set_gssp_clnt(net);
1351 if (res)
1352 return res;
1353 return count;
1354}
1355
1356static ssize_t read_gssp(struct file *file, char __user *buf,
1357 size_t count, loff_t *ppos)
1358{
1359 struct net *net = PDE_DATA(file->f_path.dentry->d_inode);
1360 unsigned long p = *ppos;
1361 char tbuf[10];
1362 size_t len;
1363 int ret;
1364
1365 ret = wait_for_gss_proxy(net);
1366 if (ret)
1367 return ret;
1368
1369 snprintf(tbuf, sizeof(tbuf), "%d\n", use_gss_proxy(net));
1370 len = strlen(tbuf);
1371 if (p >= len)
1372 return 0;
1373 len -= p;
1374 if (len > count)
1375 len = count;
1376 if (copy_to_user(buf, (void *)(tbuf+p), len))
1377 return -EFAULT;
1378 *ppos += len;
1379 return len;
1380}
1381
1382static const struct file_operations use_gss_proxy_ops = {
1383 .open = nonseekable_open,
1384 .write = write_gssp,
1385 .read = read_gssp,
1386};
1387
1388static int create_use_gss_proxy_proc_entry(struct net *net)
1389{
1390 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1391 struct proc_dir_entry **p = &sn->use_gssp_proc;
1392
1393 sn->use_gss_proxy = -1;
1394 *p = proc_create_data("use-gss-proxy", S_IFREG|S_IRUSR|S_IWUSR,
1395 sn->proc_net_rpc,
1396 &use_gss_proxy_ops, net);
1397 if (!*p)
1398 return -ENOMEM;
1399 init_gssp_clnt(sn);
1400 return 0;
1401}
1402
1403static void destroy_use_gss_proxy_proc_entry(struct net *net)
1404{
1405 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
1406
1407 if (sn->use_gssp_proc) {
1408 remove_proc_entry("use-gss-proxy", sn->proc_net_rpc);
1409 clear_gssp_clnt(sn);
1410 }
1411}
1412#else /* CONFIG_PROC_FS */
1413
1414static int create_use_gss_proxy_proc_entry(struct net *net)
1415{
1416 return 0;
1417}
1418
1419static void destroy_use_gss_proxy_proc_entry(struct net *net) {}
1420
1421#endif /* CONFIG_PROC_FS */
1422
1091/* 1423/*
1092 * Accept an rpcsec packet. 1424 * Accept an rpcsec packet.
1093 * If context establishment, punt to user space 1425 * If context establishment, punt to user space
@@ -1154,7 +1486,10 @@ svcauth_gss_accept(struct svc_rqst *rqstp, __be32 *authp)
1154 switch (gc->gc_proc) { 1486 switch (gc->gc_proc) {
1155 case RPC_GSS_PROC_INIT: 1487 case RPC_GSS_PROC_INIT:
1156 case RPC_GSS_PROC_CONTINUE_INIT: 1488 case RPC_GSS_PROC_CONTINUE_INIT:
1157 return svcauth_gss_handle_init(rqstp, gc, authp); 1489 if (use_gss_proxy(SVC_NET(rqstp)))
1490 return svcauth_gss_proxy_init(rqstp, gc, authp);
1491 else
1492 return svcauth_gss_legacy_init(rqstp, gc, authp);
1158 case RPC_GSS_PROC_DATA: 1493 case RPC_GSS_PROC_DATA:
1159 case RPC_GSS_PROC_DESTROY: 1494 case RPC_GSS_PROC_DESTROY:
1160 /* Look up the context, and check the verifier: */ 1495 /* Look up the context, and check the verifier: */
@@ -1531,7 +1866,12 @@ gss_svc_init_net(struct net *net)
1531 rv = rsi_cache_create_net(net); 1866 rv = rsi_cache_create_net(net);
1532 if (rv) 1867 if (rv)
1533 goto out1; 1868 goto out1;
1869 rv = create_use_gss_proxy_proc_entry(net);
1870 if (rv)
1871 goto out2;
1534 return 0; 1872 return 0;
1873out2:
1874 destroy_use_gss_proxy_proc_entry(net);
1535out1: 1875out1:
1536 rsc_cache_destroy_net(net); 1876 rsc_cache_destroy_net(net);
1537 return rv; 1877 return rv;
@@ -1540,6 +1880,7 @@ out1:
1540void 1880void
1541gss_svc_shutdown_net(struct net *net) 1881gss_svc_shutdown_net(struct net *net)
1542{ 1882{
1883 destroy_use_gss_proxy_proc_entry(net);
1543 rsi_cache_destroy_net(net); 1884 rsi_cache_destroy_net(net);
1544 rsc_cache_destroy_net(net); 1885 rsc_cache_destroy_net(net);
1545} 1886}
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c
index f1889be80912..80fe5c86efd1 100644
--- a/net/sunrpc/cache.c
+++ b/net/sunrpc/cache.c
@@ -986,8 +986,10 @@ static int cache_open(struct inode *inode, struct file *filp,
986 nonseekable_open(inode, filp); 986 nonseekable_open(inode, filp);
987 if (filp->f_mode & FMODE_READ) { 987 if (filp->f_mode & FMODE_READ) {
988 rp = kmalloc(sizeof(*rp), GFP_KERNEL); 988 rp = kmalloc(sizeof(*rp), GFP_KERNEL);
989 if (!rp) 989 if (!rp) {
990 module_put(cd->owner);
990 return -ENOMEM; 991 return -ENOMEM;
992 }
991 rp->offset = 0; 993 rp->offset = 0;
992 rp->q.reader = 1; 994 rp->q.reader = 1;
993 atomic_inc(&cd->readers); 995 atomic_inc(&cd->readers);
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index d259fa966927..3f7930f938cc 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -413,6 +413,8 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
413 413
414 if (args->flags & RPC_CLNT_CREATE_INFINITE_SLOTS) 414 if (args->flags & RPC_CLNT_CREATE_INFINITE_SLOTS)
415 xprtargs.flags |= XPRT_CREATE_INFINITE_SLOTS; 415 xprtargs.flags |= XPRT_CREATE_INFINITE_SLOTS;
416 if (args->flags & RPC_CLNT_CREATE_NO_IDLE_TIMEOUT)
417 xprtargs.flags |= XPRT_CREATE_NO_IDLE_TIMEOUT;
416 /* 418 /*
417 * If the caller chooses not to specify a hostname, whip 419 * If the caller chooses not to specify a hostname, whip
418 * up a string representation of the passed-in address. 420 * up a string representation of the passed-in address.
@@ -681,6 +683,7 @@ rpc_release_client(struct rpc_clnt *clnt)
681 if (atomic_dec_and_test(&clnt->cl_count)) 683 if (atomic_dec_and_test(&clnt->cl_count))
682 rpc_free_auth(clnt); 684 rpc_free_auth(clnt);
683} 685}
686EXPORT_SYMBOL_GPL(rpc_release_client);
684 687
685/** 688/**
686 * rpc_bind_new_program - bind a new RPC program to an existing client 689 * rpc_bind_new_program - bind a new RPC program to an existing client
diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h
index ce7bd449173d..7111a4c9113b 100644
--- a/net/sunrpc/netns.h
+++ b/net/sunrpc/netns.h
@@ -23,6 +23,12 @@ struct sunrpc_net {
23 struct rpc_clnt *rpcb_local_clnt4; 23 struct rpc_clnt *rpcb_local_clnt4;
24 spinlock_t rpcb_clnt_lock; 24 spinlock_t rpcb_clnt_lock;
25 unsigned int rpcb_users; 25 unsigned int rpcb_users;
26
27 struct mutex gssp_lock;
28 wait_queue_head_t gssp_wq;
29 struct rpc_clnt *gssp_clnt;
30 int use_gss_proxy;
31 struct proc_dir_entry *use_gssp_proc;
26}; 32};
27 33
28extern int sunrpc_net_id; 34extern int sunrpc_net_id;
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 745fca3cfd36..095363eee764 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1300,6 +1300,8 @@ found:
1300 -PTR_ERR(xprt)); 1300 -PTR_ERR(xprt));
1301 goto out; 1301 goto out;
1302 } 1302 }
1303 if (args->flags & XPRT_CREATE_NO_IDLE_TIMEOUT)
1304 xprt->idle_timeout = 0;
1303 INIT_WORK(&xprt->task_cleanup, xprt_autoclose); 1305 INIT_WORK(&xprt->task_cleanup, xprt_autoclose);
1304 if (xprt_has_timer(xprt)) 1306 if (xprt_has_timer(xprt))
1305 setup_timer(&xprt->timer, xprt_init_autodisconnect, 1307 setup_timer(&xprt->timer, xprt_init_autodisconnect,
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 9c2825827dec..ffd50348a509 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -2655,6 +2655,9 @@ static struct rpc_xprt *xs_setup_local(struct xprt_create *args)
2655 } 2655 }
2656 xprt_set_bound(xprt); 2656 xprt_set_bound(xprt);
2657 xs_format_peer_addresses(xprt, "local", RPCBIND_NETID_LOCAL); 2657 xs_format_peer_addresses(xprt, "local", RPCBIND_NETID_LOCAL);
2658 ret = ERR_PTR(xs_local_setup_socket(transport));
2659 if (ret)
2660 goto out_err;
2658 break; 2661 break;
2659 default: 2662 default:
2660 ret = ERR_PTR(-EAFNOSUPPORT); 2663 ret = ERR_PTR(-EAFNOSUPPORT);