/*
* In-kernel rpcbind client supporting versions 2, 3, and 4 of the rpcbind
* protocol
*
* Based on RFC 1833: "Binding Protocols for ONC RPC Version 2" and
* RFC 3530: "Network File System (NFS) version 4 Protocol"
*
* Original: Gilles Quillard, Bull Open Source, 2005 <gilles.quillard@bull.net>
* Updated: Chuck Lever, Oracle Corporation, 2007 <chuck.lever@oracle.com>
*
* Descended from net/sunrpc/pmap_clnt.c,
* Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/un.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/nsproxy.h>
#include <net/ipv6.h>
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/xprtsock.h>
#include "netns.h"
#ifdef RPC_DEBUG
# define RPCDBG_FACILITY RPCDBG_BIND
#endif
#define RPCBIND_SOCK_PATHNAME "/var/run/rpcbind.sock"
#define RPCBIND_PROGRAM (100000u)
#define RPCBIND_PORT (111u)
#define RPCBVERS_2 (2u)
#define RPCBVERS_3 (3u)
#define RPCBVERS_4 (4u)
enum {
RPCBPROC_NULL,
RPCBPROC_SET,
RPCBPROC_UNSET,
RPCBPROC_GETPORT,
RPCBPROC_GETADDR = 3, /* alias for GETPORT */
RPCBPROC_DUMP,
RPCBPROC_CALLIT,
RPCBPROC_BCAST = 5, /* alias for CALLIT */
RPCBPROC_GETTIME,
RPCBPROC_UADDR2TADDR,
RPCBPROC_TADDR2UADDR,
RPCBPROC_GETVERSADDR,
RPCBPROC_INDIRECT,
RPCBPROC_GETADDRLIST,
RPCBPROC_GETSTAT,
};
/*
* r_owner
*
* The "owner" is allowed to unset a service in the rpcbind database.
*
* For AF_LOCAL SET/UNSET requests, rpcbind treats this string as a
* UID which it maps to a local user name via a password lookup.
* In all other cases it is ignored.
*
* For SET/UNSET requests, user space provides a value, even for
* network requests, and GETADDR uses an empty string. We follow
* those precedents here.
*/
#define RPCB_OWNER_STRING "0"
#define RPCB_MAXOWNERLEN sizeof(RPCB_OWNER_STRING)
/*
* XDR data type sizes
*/
#define RPCB_program_sz (1)
#define RPCB_version_sz (1)
#define RPCB_protocol_sz (1)
#define RPCB_port_sz (1)
#define RPCB_boolean_sz (1)
#define RPCB_netid_sz (1 + XDR_QUADLEN(RPCBIND_MAXNETIDLEN))
#define RPCB_addr_sz (1 + XDR_QUADLEN(RPCBIND_MAXUADDRLEN))
#define RPCB_ownerstring_sz (1 + XDR_QUADLEN(RPCB_MAXOWNERLEN))
/*
* XDR argument and result sizes
*/
#define RPCB_mappingargs_sz (RPCB_program_sz + RPCB_version_sz + \
RPCB_protocol_sz + RPCB_port_sz)
#define RPCB_getaddrargs_sz (RPCB_program_sz + RPCB_version_sz + \
RPCB_netid_sz + RPCB_addr_sz + \
RPCB_ownerstring_sz)
#define RPCB_getportres_sz RPCB_port_sz
#define RPCB_setres_sz RPCB_boolean_sz
/*
* Note that RFC 1833 does not put any size restrictions on the
* address string returned by the remote rpcbind database.
*/
#define RPCB_getaddrres_sz RPCB_addr_sz
static void rpcb_getport_done(struct rpc_task *, void *);
static void rpcb_map_release(void *data);
static const struct rpc_program rpcb_program;
struct rpcbind_args {
struct rpc_xprt * r_xprt;
u32 r_prog;
u32 r_vers;
u32 r_prot;
unsigned short r_port;
const char * r_netid;
const char * r_addr;
const char * r_owner;
int r_status;
};
static struct rpc_procinfo rpcb_procedures2[];
static struct rpc_procinfo rpcb_procedures3[];
static struct rpc_procinfo rpcb_procedures4[];
struct rpcb_info {
u32 rpc_vers;
struct rpc_procinfo * rpc_proc;
};
static const struct rpcb_info rpcb_next_version[];
static const struct rpcb_info rpcb_next_version6[];
static const struct rpc_call_ops rpcb_getport_ops = {
.rpc_call_done = rpcb_getport_done,
.rpc_release = rpcb_map_release,
};
static void rpcb_wake_rpcbind_waiters(struct rpc_xprt *xprt, int status)
{
xprt_clear_binding(xprt);
rpc_wake_up_status(&xprt->binding, status);
}
static void rpcb_map_release(void *data)
{
struct rpcbind_args *map = data;
rpcb_wake_rpcbind_waiters(map->r_xprt, map->r_status);
xprt_put(map->r_xprt);
kfree(map->r_addr);
kfree(map);
}
static int rpcb_get_local(struct net *net)
{
int cnt;
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
spin_lock(&sn->rpcb_clnt_lock);
if (sn->rpcb_users)
sn->rpcb_users++;
cnt = sn->rpcb_users;
spin_unlock(&sn->rpcb_clnt_lock);
return cnt;
}
void rpcb_put_local(struct net *net)
{
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
struct rpc_clnt *clnt = sn->rpcb_local_clnt;
struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4;