aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2012-05-25 18:09:55 -0400
committerJ. Bruce Fields <bfields@redhat.com>2013-04-26 11:41:27 -0400
commit1d658336b05f8697d6445834f8867f8ad5e4f735 (patch)
treeea5ee58159824eb8a16044770b2d2afb6c50a863 /net/sunrpc
parent400f26b542e86995662a0cc5483656b7b1f42af6 (diff)
SUNRPC: Add RPC based upcall mechanism for RPCGSS auth
This patch implements a sunrpc client to use the services of the gssproxy userspace daemon. In particular it allows to perform calls in user space using an RPC call instead of custom hand-coded upcall/downcall messages. Currently only accept_sec_context is implemented as that is all is needed for the server case. File server modules like NFS and CIFS can use full gssapi services this way, once init_sec_context is also implemented. For the NFS server case this code allow to lift the limit of max 2k krb5 tickets. This limit is prevents legitimate kerberos deployments from using krb5 authentication with the Linux NFS server as they have normally ticket that are many kilobytes large. It will also allow to lift the limitation on the size of the credential set (uid,gid,gids) passed down from user space for users that have very many groups associated. Currently the downcall mechanism used by rpc.svcgssd is limited to around 2k secondary groups of the 65k allowed by kernel structures. Signed-off-by: Simo Sorce <simo@redhat.com> [bfields: containerization, concurrent upcalls, misc. fixes and cleanup] Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/auth_gss/Makefile3
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_upcall.c355
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_upcall.h47
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_xdr.c832
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_xdr.h264
-rw-r--r--net/sunrpc/clnt.c1
-rw-r--r--net/sunrpc/netns.h3
7 files changed, 1504 insertions, 1 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/gss_rpc_upcall.c b/net/sunrpc/auth_gss/gss_rpc_upcall.c
new file mode 100644
index 000000000000..2d33ddfe74e5
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_rpc_upcall.c
@@ -0,0 +1,355 @@
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
66struct 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}
141
142int set_gssp_clnt(struct net *net)
143{
144 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
145 struct rpc_clnt *clnt;
146 int ret;
147
148 mutex_lock(&sn->gssp_lock);
149 ret = gssp_rpc_create(net, &clnt);
150 if (!ret) {
151 if (sn->gssp_clnt)
152 rpc_shutdown_client(sn->gssp_clnt);
153 sn->gssp_clnt = clnt;
154 }
155 mutex_unlock(&sn->gssp_lock);
156 return ret;
157}
158
159void clear_gssp_clnt(struct sunrpc_net *sn)
160{
161 mutex_lock(&sn->gssp_lock);
162 if (sn->gssp_clnt) {
163 rpc_shutdown_client(sn->gssp_clnt);
164 sn->gssp_clnt = NULL;
165 }
166 mutex_unlock(&sn->gssp_lock);
167}
168
169static struct rpc_clnt *get_gssp_clnt(struct sunrpc_net *sn)
170{
171 struct rpc_clnt *clnt;
172
173 mutex_lock(&sn->gssp_lock);
174 clnt = sn->gssp_clnt;
175 if (clnt)
176 atomic_inc(&clnt->cl_count);
177 mutex_unlock(&sn->gssp_lock);
178 return clnt;
179}
180
181static int gssp_call(struct net *net, struct rpc_message *msg)
182{
183 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
184 struct rpc_clnt *clnt;
185 int status;
186
187 clnt = get_gssp_clnt(sn);
188 if (!clnt)
189 return -EIO;
190 status = rpc_call_sync(clnt, msg, 0);
191 if (status < 0) {
192 dprintk("gssp: rpc_call returned error %d\n", -status);
193 switch (status) {
194 case -EPROTONOSUPPORT:
195 status = -EINVAL;
196 break;
197 case -ECONNREFUSED:
198 case -ETIMEDOUT:
199 case -ENOTCONN:
200 status = -EAGAIN;
201 break;
202 case -ERESTARTSYS:
203 if (signalled ())
204 status = -EINTR;
205 break;
206 default:
207 break;
208 }
209 }
210 rpc_release_client(clnt);
211 return status;
212}
213
214
215/*
216 * Public functions
217 */
218
219/* numbers somewhat arbitrary but large enough for current needs */
220#define GSSX_MAX_OUT_HANDLE 128
221#define GSSX_MAX_MECH_OID 16
222#define GSSX_MAX_SRC_PRINC 256
223#define GSSX_KMEMBUF (GSSX_max_output_handle_sz + \
224 GSSX_max_oid_sz + \
225 GSSX_max_princ_sz + \
226 sizeof(struct svc_cred))
227
228int gssp_accept_sec_context_upcall(struct net *net,
229 struct gssp_upcall_data *data)
230{
231 struct gssx_ctx ctxh = {
232 .state = data->in_handle
233 };
234 struct gssx_arg_accept_sec_context arg = {
235 .input_token = data->in_token,
236 };
237 struct gssx_ctx rctxh = {
238 /*
239 * pass in the max length we expect for each of these
240 * buffers but let the xdr code kmalloc them:
241 */
242 .exported_context_token.len = GSSX_max_output_handle_sz,
243 .mech.len = GSSX_max_oid_sz,
244 .src_name.display_name.len = GSSX_max_princ_sz
245 };
246 struct gssx_res_accept_sec_context res = {
247 .context_handle = &rctxh,
248 .output_token = &data->out_token
249 };
250 struct rpc_message msg = {
251 .rpc_proc = &gssp_procedures[GSSX_ACCEPT_SEC_CONTEXT],
252 .rpc_argp = &arg,
253 .rpc_resp = &res,
254 .rpc_cred = NULL, /* FIXME ? */
255 };
256 struct xdr_netobj client_name = { 0 , NULL };
257 int ret;
258
259 if (data->in_handle.len != 0)
260 arg.context_handle = &ctxh;
261 res.output_token->len = GSSX_max_output_token_sz;
262
263 /* use nfs/ for targ_name ? */
264
265 ret = gssp_call(net, &msg);
266
267 /* we need to fetch all data even in case of error so
268 * that we can free special strctures is they have been allocated */
269 data->major_status = res.status.major_status;
270 data->minor_status = res.status.minor_status;
271 if (res.context_handle) {
272 data->out_handle = rctxh.exported_context_token;
273 data->mech_oid = rctxh.mech;
274 client_name = rctxh.src_name.display_name;
275 }
276
277 if (res.options.count == 1) {
278 gssx_buffer *value = &res.options.data[0].value;
279 /* Currently we only decode CREDS_VALUE, if we add
280 * anything else we'll have to loop and match on the
281 * option name */
282 if (value->len == 1) {
283 /* steal group info from struct svc_cred */
284 data->creds = *(struct svc_cred *)value->data;
285 data->found_creds = 1;
286 }
287 /* whether we use it or not, free data */
288 kfree(value->data);
289 }
290
291 if (res.options.count != 0) {
292 kfree(res.options.data);
293 }
294
295 /* convert to GSS_NT_HOSTBASED_SERVICE form and set into creds */
296 if (data->found_creds && client_name.data != NULL) {
297 char *c;
298
299 data->creds.cr_principal = kstrndup(client_name.data,
300 client_name.len, GFP_KERNEL);
301 if (data->creds.cr_principal) {
302 /* terminate and remove realm part */
303 c = strchr(data->creds.cr_principal, '@');
304 if (c) {
305 *c = '\0';
306
307 /* change service-hostname delimiter */
308 c = strchr(data->creds.cr_principal, '/');
309 if (c) *c = '@';
310 }
311 if (!c) {
312 /* not a service principal */
313 kfree(data->creds.cr_principal);
314 data->creds.cr_principal = NULL;
315 }
316 }
317 }
318 kfree(client_name.data);
319
320 return ret;
321}
322
323void gssp_free_upcall_data(struct gssp_upcall_data *data)
324{
325 kfree(data->in_handle.data);
326 kfree(data->out_handle.data);
327 kfree(data->out_token.data);
328 kfree(data->mech_oid.data);
329 free_svc_cred(&data->creds);
330}
331
332/*
333 * Initialization stuff
334 */
335
336static const struct rpc_version gssp_version1 = {
337 .number = GSSPROXY_VERS_1,
338 .nrprocs = ARRAY_SIZE(gssp_procedures),
339 .procs = gssp_procedures,
340};
341
342static const struct rpc_version *gssp_version[] = {
343 NULL,
344 &gssp_version1,
345};
346
347static struct rpc_stat gssp_stats;
348
349static const struct rpc_program gssp_program = {
350 .name = "gssproxy",
351 .number = GSSPROXY_PROGRAM,
352 .nrvers = ARRAY_SIZE(gssp_version),
353 .version = gssp_version,
354 .stats = &gssp_stats,
355};
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..4c2caaa7e84e
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_rpc_upcall.h
@@ -0,0 +1,47 @@
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/auth_gss.h>
25#include "gss_rpc_xdr.h"
26#include "../netns.h"
27
28struct gssp_upcall_data {
29 struct xdr_netobj in_handle;
30 struct gssp_in_token in_token;
31 struct xdr_netobj out_handle;
32 struct xdr_netobj out_token;
33 struct xdr_netobj mech_oid;
34 struct svc_cred creds;
35 int found_creds;
36 int major_status;
37 int minor_status;
38};
39
40int gssp_accept_sec_context_upcall(struct net *net,
41 struct gssp_upcall_data *data);
42void gssp_free_upcall_data(struct gssp_upcall_data *data);
43
44void init_gssp_clnt(struct sunrpc_net *);
45int set_gssp_clnt(struct net *);
46void clear_gssp_clnt(struct sunrpc_net *);
47#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..d0ccdffa7e54
--- /dev/null
+++ b/net/sunrpc/auth_gss/gss_rpc_xdr.c
@@ -0,0 +1,832 @@
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 = tmp;
220
221 /* gid */
222 err = get_s32(&q, end, &tmp);
223 if (err)
224 return err;
225 creds->cr_gid = 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 err = get_s32(&q, end, &tmp);
239 if (err) {
240 groups_free(creds->cr_group_info);
241 return err;
242 }
243 GROUP_AT(creds->cr_group_info, i) = tmp;
244 }
245
246 return 0;
247}
248
249static int gssx_dec_option_array(struct xdr_stream *xdr,
250 struct gssx_option_array *oa)
251{
252 struct svc_cred *creds;
253 u32 count, i;
254 __be32 *p;
255 int err;
256
257 p = xdr_inline_decode(xdr, 4);
258 if (unlikely(p == NULL))
259 return -ENOSPC;
260 count = be32_to_cpup(p++);
261 if (count != 0) {
262 /* we recognize only 1 currently: CREDS_VALUE */
263 oa->count = 1;
264
265 oa->data = kmalloc(sizeof(struct gssx_option), GFP_KERNEL);
266 if (!oa->data)
267 return -ENOMEM;
268
269 creds = kmalloc(sizeof(struct svc_cred), GFP_KERNEL);
270 if (!creds) {
271 kfree(oa->data);
272 return -ENOMEM;
273 }
274
275 oa->data[0].option.data = CREDS_VALUE;
276 oa->data[0].option.len = sizeof(CREDS_VALUE);
277 oa->data[0].value.data = (void *)creds;
278 oa->data[0].value.len = 0;
279 }
280 for (i = 0; i < count; i++) {
281 gssx_buffer dummy = { 0, NULL };
282 u32 length;
283
284 /* option buffer */
285 p = xdr_inline_decode(xdr, 4);
286 if (unlikely(p == NULL))
287 return -ENOSPC;
288
289 length = be32_to_cpup(p);
290 p = xdr_inline_decode(xdr, length);
291 if (unlikely(p == NULL))
292 return -ENOSPC;
293
294 if (length == sizeof(CREDS_VALUE) &&
295 memcmp(p, CREDS_VALUE, sizeof(CREDS_VALUE)) == 0) {
296 /* We have creds here. parse them */
297 err = gssx_dec_linux_creds(xdr, creds);
298 if (err)
299 return err;
300 oa->data[0].value.len = 1; /* presence */
301 } else {
302 /* consume uninteresting buffer */
303 err = gssx_dec_buffer(xdr, &dummy);
304 if (err)
305 return err;
306 }
307 }
308 return 0;
309}
310
311static int gssx_dec_status(struct xdr_stream *xdr,
312 struct gssx_status *status)
313{
314 __be32 *p;
315 int err;
316
317 /* status->major_status */
318 p = xdr_inline_decode(xdr, 8);
319 if (unlikely(p == NULL))
320 return -ENOSPC;
321 p = xdr_decode_hyper(p, &status->major_status);
322
323 /* status->mech */
324 err = gssx_dec_buffer(xdr, &status->mech);
325 if (err)
326 return err;
327
328 /* status->minor_status */
329 p = xdr_inline_decode(xdr, 8);
330 if (unlikely(p == NULL))
331 return -ENOSPC;
332 p = xdr_decode_hyper(p, &status->minor_status);
333
334 /* status->major_status_string */
335 err = gssx_dec_buffer(xdr, &status->major_status_string);
336 if (err)
337 return err;
338
339 /* status->minor_status_string */
340 err = gssx_dec_buffer(xdr, &status->minor_status_string);
341 if (err)
342 return err;
343
344 /* status->server_ctx */
345 err = gssx_dec_buffer(xdr, &status->server_ctx);
346 if (err)
347 return err;
348
349 /* we assume we have no options for now, so simply consume them */
350 /* status->options */
351 err = dummy_dec_opt_array(xdr, &status->options);
352
353 return err;
354}
355
356static int gssx_enc_call_ctx(struct xdr_stream *xdr,
357 struct gssx_call_ctx *ctx)
358{
359 struct gssx_option opt;
360 __be32 *p;
361 int err;
362
363 /* ctx->locale */
364 err = gssx_enc_buffer(xdr, &ctx->locale);
365 if (err)
366 return err;
367
368 /* ctx->server_ctx */
369 err = gssx_enc_buffer(xdr, &ctx->server_ctx);
370 if (err)
371 return err;
372
373 /* we always want to ask for lucid contexts */
374 /* ctx->options */
375 p = xdr_reserve_space(xdr, 4);
376 *p = cpu_to_be32(2);
377
378 /* we want a lucid_v1 context */
379 opt.option.data = LUCID_OPTION;
380 opt.option.len = sizeof(LUCID_OPTION);
381 opt.value.data = LUCID_VALUE;
382 opt.value.len = sizeof(LUCID_VALUE);
383 err = gssx_enc_option(xdr, &opt);
384
385 /* ..and user creds */
386 opt.option.data = CREDS_OPTION;
387 opt.option.len = sizeof(CREDS_OPTION);
388 opt.value.data = CREDS_VALUE;
389 opt.value.len = sizeof(CREDS_VALUE);
390 err = gssx_enc_option(xdr, &opt);
391
392 return err;
393}
394
395static int gssx_dec_name_attr(struct xdr_stream *xdr,
396 struct gssx_name_attr *attr)
397{
398 int err;
399
400 /* attr->attr */
401 err = gssx_dec_buffer(xdr, &attr->attr);
402 if (err)
403 return err;
404
405 /* attr->value */
406 err = gssx_dec_buffer(xdr, &attr->value);
407 if (err)
408 return err;
409
410 /* attr->extensions */
411 err = dummy_dec_opt_array(xdr, &attr->extensions);
412
413 return err;
414}
415
416static int dummy_enc_nameattr_array(struct xdr_stream *xdr,
417 struct gssx_name_attr_array *naa)
418{
419 __be32 *p;
420
421 if (naa->count != 0)
422 return -EINVAL;
423
424 p = xdr_reserve_space(xdr, 4);
425 if (!p)
426 return -ENOSPC;
427 *p = 0;
428
429 return 0;
430}
431
432static int dummy_dec_nameattr_array(struct xdr_stream *xdr,
433 struct gssx_name_attr_array *naa)
434{
435 struct gssx_name_attr dummy;
436 u32 count, i;
437 __be32 *p;
438
439 p = xdr_inline_decode(xdr, 4);
440 if (unlikely(p == NULL))
441 return -ENOSPC;
442 count = be32_to_cpup(p++);
443 for (i = 0; i < count; i++) {
444 gssx_dec_name_attr(xdr, &dummy);
445 }
446
447 naa->count = 0;
448 naa->data = NULL;
449 return 0;
450}
451
452static struct xdr_netobj zero_netobj = {};
453
454static struct gssx_name_attr_array zero_name_attr_array = {};
455
456static struct gssx_option_array zero_option_array = {};
457
458static int gssx_enc_name(struct xdr_stream *xdr,
459 struct gssx_name *name)
460{
461 int err;
462
463 /* name->display_name */
464 err = gssx_enc_buffer(xdr, &name->display_name);
465 if (err)
466 return err;
467
468 /* name->name_type */
469 err = gssx_enc_buffer(xdr, &zero_netobj);
470 if (err)
471 return err;
472
473 /* name->exported_name */
474 err = gssx_enc_buffer(xdr, &zero_netobj);
475 if (err)
476 return err;
477
478 /* name->exported_composite_name */
479 err = gssx_enc_buffer(xdr, &zero_netobj);
480 if (err)
481 return err;
482
483 /* leave name_attributes empty for now, will add once we have any
484 * to pass up at all */
485 /* name->name_attributes */
486 err = dummy_enc_nameattr_array(xdr, &zero_name_attr_array);
487 if (err)
488 return err;
489
490 /* leave options empty for now, will add once we have any options
491 * to pass up at all */
492 /* name->extensions */
493 err = dummy_enc_opt_array(xdr, &zero_option_array);
494
495 return err;
496}
497
498static int gssx_dec_name(struct xdr_stream *xdr,
499 struct gssx_name *name)
500{
501 struct xdr_netobj dummy_netobj;
502 struct gssx_name_attr_array dummy_name_attr_array;
503 struct gssx_option_array dummy_option_array;
504 int err;
505
506 /* name->display_name */
507 err = gssx_dec_buffer(xdr, &name->display_name);
508 if (err)
509 return err;
510
511 /* name->name_type */
512 err = gssx_dec_buffer(xdr, &dummy_netobj);
513 if (err)
514 return err;
515
516 /* name->exported_name */
517 err = gssx_dec_buffer(xdr, &dummy_netobj);
518 if (err)
519 return err;
520
521 /* name->exported_composite_name */
522 err = gssx_dec_buffer(xdr, &dummy_netobj);
523 if (err)
524 return err;
525
526 /* we assume we have no attributes for now, so simply consume them */
527 /* name->name_attributes */
528 err = dummy_dec_nameattr_array(xdr, &dummy_name_attr_array);
529 if (err)
530 return err;
531
532 /* we assume we have no options for now, so simply consume them */
533 /* name->extensions */
534 err = dummy_dec_opt_array(xdr, &dummy_option_array);
535
536 return err;
537}
538
539static int dummy_enc_credel_array(struct xdr_stream *xdr,
540 struct gssx_cred_element_array *cea)
541{
542 __be32 *p;
543
544 if (cea->count != 0)
545 return -EINVAL;
546
547 p = xdr_reserve_space(xdr, 4);
548 if (!p)
549 return -ENOSPC;
550 *p = 0;
551
552 return 0;
553}
554
555static int gssx_enc_cred(struct xdr_stream *xdr,
556 struct gssx_cred *cred)
557{
558 int err;
559
560 /* cred->desired_name */
561 err = gssx_enc_name(xdr, &cred->desired_name);
562 if (err)
563 return err;
564
565 /* cred->elements */
566 err = dummy_enc_credel_array(xdr, &cred->elements);
567
568 /* cred->cred_handle_reference */
569 err = gssx_enc_buffer(xdr, &cred->cred_handle_reference);
570 if (err)
571 return err;
572
573 /* cred->needs_release */
574 err = gssx_enc_bool(xdr, cred->needs_release);
575
576 return err;
577}
578
579static int gssx_enc_ctx(struct xdr_stream *xdr,
580 struct gssx_ctx *ctx)
581{
582 __be32 *p;
583 int err;
584
585 /* ctx->exported_context_token */
586 err = gssx_enc_buffer(xdr, &ctx->exported_context_token);
587 if (err)
588 return err;
589
590 /* ctx->state */
591 err = gssx_enc_buffer(xdr, &ctx->state);
592 if (err)
593 return err;
594
595 /* ctx->need_release */
596 err = gssx_enc_bool(xdr, ctx->need_release);
597 if (err)
598 return err;
599
600 /* ctx->mech */
601 err = gssx_enc_buffer(xdr, &ctx->mech);
602 if (err)
603 return err;
604
605 /* ctx->src_name */
606 err = gssx_enc_name(xdr, &ctx->src_name);
607 if (err)
608 return err;
609
610 /* ctx->targ_name */
611 err = gssx_enc_name(xdr, &ctx->targ_name);
612 if (err)
613 return err;
614
615 /* ctx->lifetime */
616 p = xdr_reserve_space(xdr, 8+8);
617 if (!p)
618 return -ENOSPC;
619 p = xdr_encode_hyper(p, ctx->lifetime);
620
621 /* ctx->ctx_flags */
622 p = xdr_encode_hyper(p, ctx->ctx_flags);
623
624 /* ctx->locally_initiated */
625 err = gssx_enc_bool(xdr, ctx->locally_initiated);
626 if (err)
627 return err;
628
629 /* ctx->open */
630 err = gssx_enc_bool(xdr, ctx->open);
631 if (err)
632 return err;
633
634 /* leave options empty for now, will add once we have any options
635 * to pass up at all */
636 /* ctx->options */
637 err = dummy_enc_opt_array(xdr, &ctx->options);
638
639 return err;
640}
641
642static int gssx_dec_ctx(struct xdr_stream *xdr,
643 struct gssx_ctx *ctx)
644{
645 __be32 *p;
646 int err;
647
648 /* ctx->exported_context_token */
649 err = gssx_dec_buffer(xdr, &ctx->exported_context_token);
650 if (err)
651 return err;
652
653 /* ctx->state */
654 err = gssx_dec_buffer(xdr, &ctx->state);
655 if (err)
656 return err;
657
658 /* ctx->need_release */
659 err = gssx_dec_bool(xdr, &ctx->need_release);
660 if (err)
661 return err;
662
663 /* ctx->mech */
664 err = gssx_dec_buffer(xdr, &ctx->mech);
665 if (err)
666 return err;
667
668 /* ctx->src_name */
669 err = gssx_dec_name(xdr, &ctx->src_name);
670 if (err)
671 return err;
672
673 /* ctx->targ_name */
674 err = gssx_dec_name(xdr, &ctx->targ_name);
675 if (err)
676 return err;
677
678 /* ctx->lifetime */
679 p = xdr_inline_decode(xdr, 8+8);
680 if (unlikely(p == NULL))
681 return -ENOSPC;
682 p = xdr_decode_hyper(p, &ctx->lifetime);
683
684 /* ctx->ctx_flags */
685 p = xdr_decode_hyper(p, &ctx->ctx_flags);
686
687 /* ctx->locally_initiated */
688 err = gssx_dec_bool(xdr, &ctx->locally_initiated);
689 if (err)
690 return err;
691
692 /* ctx->open */
693 err = gssx_dec_bool(xdr, &ctx->open);
694 if (err)
695 return err;
696
697 /* we assume we have no options for now, so simply consume them */
698 /* ctx->options */
699 err = dummy_dec_opt_array(xdr, &ctx->options);
700
701 return err;
702}
703
704static int gssx_enc_cb(struct xdr_stream *xdr, struct gssx_cb *cb)
705{
706 __be32 *p;
707 int err;
708
709 /* cb->initiator_addrtype */
710 p = xdr_reserve_space(xdr, 8);
711 if (!p)
712 return -ENOSPC;
713 p = xdr_encode_hyper(p, cb->initiator_addrtype);
714
715 /* cb->initiator_address */
716 err = gssx_enc_buffer(xdr, &cb->initiator_address);
717 if (err)
718 return err;
719
720 /* cb->acceptor_addrtype */
721 p = xdr_reserve_space(xdr, 8);
722 if (!p)
723 return -ENOSPC;
724 p = xdr_encode_hyper(p, cb->acceptor_addrtype);
725
726 /* cb->acceptor_address */
727 err = gssx_enc_buffer(xdr, &cb->acceptor_address);
728 if (err)
729 return err;
730
731 /* cb->application_data */
732 err = gssx_enc_buffer(xdr, &cb->application_data);
733
734 return err;
735}
736
737void gssx_enc_accept_sec_context(struct rpc_rqst *req,
738 struct xdr_stream *xdr,
739 struct gssx_arg_accept_sec_context *arg)
740{
741 int err;
742
743 err = gssx_enc_call_ctx(xdr, &arg->call_ctx);
744 if (err)
745 goto done;
746
747 /* arg->context_handle */
748 if (arg->context_handle) {
749 err = gssx_enc_ctx(xdr, arg->context_handle);
750 if (err)
751 goto done;
752 } else {
753 err = gssx_enc_bool(xdr, 0);
754 }
755
756 /* arg->cred_handle */
757 if (arg->cred_handle) {
758 err = gssx_enc_cred(xdr, arg->cred_handle);
759 if (err)
760 goto done;
761 } else {
762 err = gssx_enc_bool(xdr, 0);
763 }
764
765 /* arg->input_token */
766 err = gssx_enc_in_token(xdr, &arg->input_token);
767 if (err)
768 goto done;
769
770 /* arg->input_cb */
771 if (arg->input_cb) {
772 err = gssx_enc_cb(xdr, arg->input_cb);
773 if (err)
774 goto done;
775 } else {
776 err = gssx_enc_bool(xdr, 0);
777 }
778
779 err = gssx_enc_bool(xdr, arg->ret_deleg_cred);
780 if (err)
781 goto done;
782
783 /* leave options empty for now, will add once we have any options
784 * to pass up at all */
785 /* arg->options */
786 err = dummy_enc_opt_array(xdr, &arg->options);
787
788done:
789 if (err)
790 dprintk("RPC: gssx_enc_accept_sec_context: %d\n", err);
791}
792
793int gssx_dec_accept_sec_context(struct rpc_rqst *rqstp,
794 struct xdr_stream *xdr,
795 struct gssx_res_accept_sec_context *res)
796{
797 int err;
798
799 /* res->status */
800 err = gssx_dec_status(xdr, &res->status);
801 if (err)
802 return err;
803
804 /* res->context_handle */
805 if (gssx_check_pointer(xdr)) {
806 err = gssx_dec_ctx(xdr, res->context_handle);
807 if (err)
808 return err;
809 } else {
810 res->context_handle = NULL;
811 }
812
813 /* res->output_token */
814 if (gssx_check_pointer(xdr)) {
815 err = gssx_dec_buffer(xdr, res->output_token);
816 if (err)
817 return err;
818 } else {
819 res->output_token = NULL;
820 }
821
822 /* res->delegated_cred_handle */
823 if (gssx_check_pointer(xdr)) {
824 /* we do not support upcall servers sending this data. */
825 return -EINVAL;
826 }
827
828 /* res->options */
829 err = gssx_dec_option_array(xdr, &res->options);
830
831 return err;
832}
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/clnt.c b/net/sunrpc/clnt.c
index 80cf23241da9..ac74399e8899 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -688,6 +688,7 @@ rpc_release_client(struct rpc_clnt *clnt)
688 if (atomic_dec_and_test(&clnt->cl_count)) 688 if (atomic_dec_and_test(&clnt->cl_count))
689 rpc_free_auth(clnt); 689 rpc_free_auth(clnt);
690} 690}
691EXPORT_SYMBOL_GPL(rpc_release_client);
691 692
692/** 693/**
693 * rpc_bind_new_program - bind a new RPC program to an existing client 694 * 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..e9f8895d70ca 100644
--- a/net/sunrpc/netns.h
+++ b/net/sunrpc/netns.h
@@ -23,6 +23,9 @@ 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 struct rpc_clnt *gssp_clnt;
26}; 29};
27 30
28extern int sunrpc_net_id; 31extern int sunrpc_net_id;