diff options
Diffstat (limited to 'fs/nfs/callback.c')
-rw-r--r-- | fs/nfs/callback.c | 97 |
1 files changed, 51 insertions, 46 deletions
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index e17b49e2eabd..e3d294269058 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <linux/completion.h> | 9 | #include <linux/completion.h> |
10 | #include <linux/ip.h> | 10 | #include <linux/ip.h> |
11 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #include <linux/smp_lock.h> | ||
13 | #include <linux/sunrpc/svc.h> | 12 | #include <linux/sunrpc/svc.h> |
14 | #include <linux/sunrpc/svcsock.h> | 13 | #include <linux/sunrpc/svcsock.h> |
15 | #include <linux/nfs_fs.h> | 14 | #include <linux/nfs_fs.h> |
@@ -17,9 +16,7 @@ | |||
17 | #include <linux/freezer.h> | 16 | #include <linux/freezer.h> |
18 | #include <linux/kthread.h> | 17 | #include <linux/kthread.h> |
19 | #include <linux/sunrpc/svcauth_gss.h> | 18 | #include <linux/sunrpc/svcauth_gss.h> |
20 | #if defined(CONFIG_NFS_V4_1) | ||
21 | #include <linux/sunrpc/bc_xprt.h> | 19 | #include <linux/sunrpc/bc_xprt.h> |
22 | #endif | ||
23 | 20 | ||
24 | #include <net/inet_sock.h> | 21 | #include <net/inet_sock.h> |
25 | 22 | ||
@@ -109,7 +106,7 @@ nfs4_callback_up(struct svc_serv *serv) | |||
109 | { | 106 | { |
110 | int ret; | 107 | int ret; |
111 | 108 | ||
112 | ret = svc_create_xprt(serv, "tcp", PF_INET, | 109 | ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET, |
113 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); | 110 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); |
114 | if (ret <= 0) | 111 | if (ret <= 0) |
115 | goto out_err; | 112 | goto out_err; |
@@ -117,7 +114,7 @@ nfs4_callback_up(struct svc_serv *serv) | |||
117 | dprintk("NFS: Callback listener port = %u (af %u)\n", | 114 | dprintk("NFS: Callback listener port = %u (af %u)\n", |
118 | nfs_callback_tcpport, PF_INET); | 115 | nfs_callback_tcpport, PF_INET); |
119 | 116 | ||
120 | ret = svc_create_xprt(serv, "tcp", PF_INET6, | 117 | ret = svc_create_xprt(serv, "tcp", &init_net, PF_INET6, |
121 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); | 118 | nfs_callback_set_tcpport, SVC_SOCK_ANONYMOUS); |
122 | if (ret > 0) { | 119 | if (ret > 0) { |
123 | nfs_callback_tcpport6 = ret; | 120 | nfs_callback_tcpport6 = ret; |
@@ -178,30 +175,38 @@ nfs41_callback_svc(void *vrqstp) | |||
178 | struct svc_rqst * | 175 | struct svc_rqst * |
179 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) | 176 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) |
180 | { | 177 | { |
181 | struct svc_xprt *bc_xprt; | 178 | struct svc_rqst *rqstp; |
182 | struct svc_rqst *rqstp = ERR_PTR(-ENOMEM); | 179 | int ret; |
183 | 180 | ||
184 | dprintk("--> %s\n", __func__); | 181 | /* |
185 | /* Create a svc_sock for the service */ | 182 | * Create an svc_sock for the back channel service that shares the |
186 | bc_xprt = svc_sock_create(serv, xprt->prot); | 183 | * fore channel connection. |
187 | if (!bc_xprt) | 184 | * Returns the input port (0) and sets the svc_serv bc_xprt on success |
185 | */ | ||
186 | ret = svc_create_xprt(serv, "tcp-bc", &init_net, PF_INET, 0, | ||
187 | SVC_SOCK_ANONYMOUS); | ||
188 | if (ret < 0) { | ||
189 | rqstp = ERR_PTR(ret); | ||
188 | goto out; | 190 | goto out; |
191 | } | ||
189 | 192 | ||
190 | /* | 193 | /* |
191 | * Save the svc_serv in the transport so that it can | 194 | * Save the svc_serv in the transport so that it can |
192 | * be referenced when the session backchannel is initialized | 195 | * be referenced when the session backchannel is initialized |
193 | */ | 196 | */ |
194 | serv->bc_xprt = bc_xprt; | ||
195 | xprt->bc_serv = serv; | 197 | xprt->bc_serv = serv; |
196 | 198 | ||
197 | INIT_LIST_HEAD(&serv->sv_cb_list); | 199 | INIT_LIST_HEAD(&serv->sv_cb_list); |
198 | spin_lock_init(&serv->sv_cb_lock); | 200 | spin_lock_init(&serv->sv_cb_lock); |
199 | init_waitqueue_head(&serv->sv_cb_waitq); | 201 | init_waitqueue_head(&serv->sv_cb_waitq); |
200 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); | 202 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); |
201 | if (IS_ERR(rqstp)) | 203 | if (IS_ERR(rqstp)) { |
202 | svc_sock_destroy(bc_xprt); | 204 | svc_xprt_put(serv->sv_bc_xprt); |
205 | serv->sv_bc_xprt = NULL; | ||
206 | } | ||
203 | out: | 207 | out: |
204 | dprintk("--> %s return %p\n", __func__, rqstp); | 208 | dprintk("--> %s return %ld\n", __func__, |
209 | IS_ERR(rqstp) ? PTR_ERR(rqstp) : 0); | ||
205 | return rqstp; | 210 | return rqstp; |
206 | } | 211 | } |
207 | 212 | ||
@@ -323,58 +328,58 @@ void nfs_callback_down(int minorversion) | |||
323 | mutex_unlock(&nfs_callback_mutex); | 328 | mutex_unlock(&nfs_callback_mutex); |
324 | } | 329 | } |
325 | 330 | ||
326 | static int check_gss_callback_principal(struct nfs_client *clp, | 331 | /* Boolean check of RPC_AUTH_GSS principal */ |
327 | struct svc_rqst *rqstp) | 332 | int |
333 | check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) | ||
328 | { | 334 | { |
329 | struct rpc_clnt *r = clp->cl_rpcclient; | 335 | struct rpc_clnt *r = clp->cl_rpcclient; |
330 | char *p = svc_gss_principal(rqstp); | 336 | char *p = svc_gss_principal(rqstp); |
331 | 337 | ||
338 | if (rqstp->rq_authop->flavour != RPC_AUTH_GSS) | ||
339 | return 1; | ||
340 | |||
341 | /* No RPC_AUTH_GSS on NFSv4.1 back channel yet */ | ||
342 | if (clp->cl_minorversion != 0) | ||
343 | return 0; | ||
332 | /* | 344 | /* |
333 | * It might just be a normal user principal, in which case | 345 | * It might just be a normal user principal, in which case |
334 | * userspace won't bother to tell us the name at all. | 346 | * userspace won't bother to tell us the name at all. |
335 | */ | 347 | */ |
336 | if (p == NULL) | 348 | if (p == NULL) |
337 | return SVC_DENIED; | 349 | return 0; |
338 | 350 | ||
339 | /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ | 351 | /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ |
340 | 352 | ||
341 | if (memcmp(p, "nfs@", 4) != 0) | 353 | if (memcmp(p, "nfs@", 4) != 0) |
342 | return SVC_DENIED; | 354 | return 0; |
343 | p += 4; | 355 | p += 4; |
344 | if (strcmp(p, r->cl_server) != 0) | 356 | if (strcmp(p, r->cl_server) != 0) |
345 | return SVC_DENIED; | 357 | return 0; |
346 | return SVC_OK; | 358 | return 1; |
347 | } | 359 | } |
348 | 360 | ||
361 | /* | ||
362 | * pg_authenticate method for nfsv4 callback threads. | ||
363 | * | ||
364 | * The authflavor has been negotiated, so an incorrect flavor is a server | ||
365 | * bug. Drop packets with incorrect authflavor. | ||
366 | * | ||
367 | * All other checking done after NFS decoding where the nfs_client can be | ||
368 | * found in nfs4_callback_compound | ||
369 | */ | ||
349 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) | 370 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) |
350 | { | 371 | { |
351 | struct nfs_client *clp; | ||
352 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); | ||
353 | int ret = SVC_OK; | ||
354 | |||
355 | /* Don't talk to strangers */ | ||
356 | clp = nfs_find_client(svc_addr(rqstp), 4); | ||
357 | if (clp == NULL) | ||
358 | return SVC_DROP; | ||
359 | |||
360 | dprintk("%s: %s NFSv4 callback!\n", __func__, | ||
361 | svc_print_addr(rqstp, buf, sizeof(buf))); | ||
362 | |||
363 | switch (rqstp->rq_authop->flavour) { | 372 | switch (rqstp->rq_authop->flavour) { |
364 | case RPC_AUTH_NULL: | 373 | case RPC_AUTH_NULL: |
365 | if (rqstp->rq_proc != CB_NULL) | 374 | if (rqstp->rq_proc != CB_NULL) |
366 | ret = SVC_DENIED; | 375 | return SVC_DROP; |
367 | break; | 376 | break; |
368 | case RPC_AUTH_UNIX: | 377 | case RPC_AUTH_GSS: |
369 | break; | 378 | /* No RPC_AUTH_GSS support yet in NFSv4.1 */ |
370 | case RPC_AUTH_GSS: | 379 | if (svc_is_backchannel(rqstp)) |
371 | ret = check_gss_callback_principal(clp, rqstp); | 380 | return SVC_DROP; |
372 | break; | ||
373 | default: | ||
374 | ret = SVC_DENIED; | ||
375 | } | 381 | } |
376 | nfs_put_client(clp); | 382 | return SVC_OK; |
377 | return ret; | ||
378 | } | 383 | } |
379 | 384 | ||
380 | /* | 385 | /* |