diff options
Diffstat (limited to 'fs/nfs/callback.c')
-rw-r--r-- | fs/nfs/callback.c | 92 |
1 files changed, 49 insertions, 43 deletions
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 93a8b3bd69e3..e3d294269058 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
@@ -16,9 +16,7 @@ | |||
16 | #include <linux/freezer.h> | 16 | #include <linux/freezer.h> |
17 | #include <linux/kthread.h> | 17 | #include <linux/kthread.h> |
18 | #include <linux/sunrpc/svcauth_gss.h> | 18 | #include <linux/sunrpc/svcauth_gss.h> |
19 | #if defined(CONFIG_NFS_V4_1) | ||
20 | #include <linux/sunrpc/bc_xprt.h> | 19 | #include <linux/sunrpc/bc_xprt.h> |
21 | #endif | ||
22 | 20 | ||
23 | #include <net/inet_sock.h> | 21 | #include <net/inet_sock.h> |
24 | 22 | ||
@@ -177,30 +175,38 @@ nfs41_callback_svc(void *vrqstp) | |||
177 | struct svc_rqst * | 175 | struct svc_rqst * |
178 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) | 176 | nfs41_callback_up(struct svc_serv *serv, struct rpc_xprt *xprt) |
179 | { | 177 | { |
180 | struct svc_xprt *bc_xprt; | 178 | struct svc_rqst *rqstp; |
181 | struct svc_rqst *rqstp = ERR_PTR(-ENOMEM); | 179 | int ret; |
182 | 180 | ||
183 | dprintk("--> %s\n", __func__); | 181 | /* |
184 | /* Create a svc_sock for the service */ | 182 | * Create an svc_sock for the back channel service that shares the |
185 | bc_xprt = svc_sock_create(serv, xprt->prot); | 183 | * fore channel connection. |
186 | 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); | ||
187 | goto out; | 190 | goto out; |
191 | } | ||
188 | 192 | ||
189 | /* | 193 | /* |
190 | * Save the svc_serv in the transport so that it can | 194 | * Save the svc_serv in the transport so that it can |
191 | * be referenced when the session backchannel is initialized | 195 | * be referenced when the session backchannel is initialized |
192 | */ | 196 | */ |
193 | serv->bc_xprt = bc_xprt; | ||
194 | xprt->bc_serv = serv; | 197 | xprt->bc_serv = serv; |
195 | 198 | ||
196 | INIT_LIST_HEAD(&serv->sv_cb_list); | 199 | INIT_LIST_HEAD(&serv->sv_cb_list); |
197 | spin_lock_init(&serv->sv_cb_lock); | 200 | spin_lock_init(&serv->sv_cb_lock); |
198 | init_waitqueue_head(&serv->sv_cb_waitq); | 201 | init_waitqueue_head(&serv->sv_cb_waitq); |
199 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); | 202 | rqstp = svc_prepare_thread(serv, &serv->sv_pools[0]); |
200 | if (IS_ERR(rqstp)) | 203 | if (IS_ERR(rqstp)) { |
201 | svc_sock_destroy(bc_xprt); | 204 | svc_xprt_put(serv->sv_bc_xprt); |
205 | serv->sv_bc_xprt = NULL; | ||
206 | } | ||
202 | out: | 207 | out: |
203 | dprintk("--> %s return %p\n", __func__, rqstp); | 208 | dprintk("--> %s return %ld\n", __func__, |
209 | IS_ERR(rqstp) ? PTR_ERR(rqstp) : 0); | ||
204 | return rqstp; | 210 | return rqstp; |
205 | } | 211 | } |
206 | 212 | ||
@@ -322,58 +328,58 @@ void nfs_callback_down(int minorversion) | |||
322 | mutex_unlock(&nfs_callback_mutex); | 328 | mutex_unlock(&nfs_callback_mutex); |
323 | } | 329 | } |
324 | 330 | ||
325 | static int check_gss_callback_principal(struct nfs_client *clp, | 331 | /* Boolean check of RPC_AUTH_GSS principal */ |
326 | struct svc_rqst *rqstp) | 332 | int |
333 | check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) | ||
327 | { | 334 | { |
328 | struct rpc_clnt *r = clp->cl_rpcclient; | 335 | struct rpc_clnt *r = clp->cl_rpcclient; |
329 | char *p = svc_gss_principal(rqstp); | 336 | char *p = svc_gss_principal(rqstp); |
330 | 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; | ||
331 | /* | 344 | /* |
332 | * It might just be a normal user principal, in which case | 345 | * It might just be a normal user principal, in which case |
333 | * userspace won't bother to tell us the name at all. | 346 | * userspace won't bother to tell us the name at all. |
334 | */ | 347 | */ |
335 | if (p == NULL) | 348 | if (p == NULL) |
336 | return SVC_DENIED; | 349 | return 0; |
337 | 350 | ||
338 | /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ | 351 | /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ |
339 | 352 | ||
340 | if (memcmp(p, "nfs@", 4) != 0) | 353 | if (memcmp(p, "nfs@", 4) != 0) |
341 | return SVC_DENIED; | 354 | return 0; |
342 | p += 4; | 355 | p += 4; |
343 | if (strcmp(p, r->cl_server) != 0) | 356 | if (strcmp(p, r->cl_server) != 0) |
344 | return SVC_DENIED; | 357 | return 0; |
345 | return SVC_OK; | 358 | return 1; |
346 | } | 359 | } |
347 | 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 | */ | ||
348 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) | 370 | static int nfs_callback_authenticate(struct svc_rqst *rqstp) |
349 | { | 371 | { |
350 | struct nfs_client *clp; | ||
351 | RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]); | ||
352 | int ret = SVC_OK; | ||
353 | |||
354 | /* Don't talk to strangers */ | ||
355 | clp = nfs_find_client(svc_addr(rqstp), 4); | ||
356 | if (clp == NULL) | ||
357 | return SVC_DROP; | ||
358 | |||
359 | dprintk("%s: %s NFSv4 callback!\n", __func__, | ||
360 | svc_print_addr(rqstp, buf, sizeof(buf))); | ||
361 | |||
362 | switch (rqstp->rq_authop->flavour) { | 372 | switch (rqstp->rq_authop->flavour) { |
363 | case RPC_AUTH_NULL: | 373 | case RPC_AUTH_NULL: |
364 | if (rqstp->rq_proc != CB_NULL) | 374 | if (rqstp->rq_proc != CB_NULL) |
365 | ret = SVC_DENIED; | 375 | return SVC_DROP; |
366 | break; | 376 | break; |
367 | case RPC_AUTH_UNIX: | 377 | case RPC_AUTH_GSS: |
368 | break; | 378 | /* No RPC_AUTH_GSS support yet in NFSv4.1 */ |
369 | case RPC_AUTH_GSS: | 379 | if (svc_is_backchannel(rqstp)) |
370 | ret = check_gss_callback_principal(clp, rqstp); | 380 | return SVC_DROP; |
371 | break; | ||
372 | default: | ||
373 | ret = SVC_DENIED; | ||
374 | } | 381 | } |
375 | nfs_put_client(clp); | 382 | return SVC_OK; |
376 | return ret; | ||
377 | } | 383 | } |
378 | 384 | ||
379 | /* | 385 | /* |