Ejemplo n.º 1
0
int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
		     const char *name, const char *path, struct nfs_sattr *sattr)
{
	int *p, *p0;
	int status;
	int ruid = 0;

	PRINTK("NFS call  symlink %s -> %s\n", name, path);
	if (!(p0 = nfs_rpc_alloc()))
		return -EIO;
retry:
	p = nfs_rpc_header(p0, NFSPROC_SYMLINK, ruid);
	p = xdr_encode_fhandle(p, dir);
	p = xdr_encode_string(p, name);
	p = xdr_encode_string(p, path);
	p = xdr_encode_sattr(p, sattr);
	if ((status = nfs_rpc_call(server, p0, p)) < 0) {
		nfs_rpc_free(p0);
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
		status = NFSERR_IO;
	else if ((status = ntohl(*p++)) == NFS_OK) {
		PRINTK("NFS reply symlink\n");
	}
	else {
		if (!ruid && current->euid == 0 && current->uid != 0) {
			ruid = 1;
			goto retry;
		}
		PRINTK("NFS reply symlink failed = %d\n", status);
	}
	nfs_rpc_free(p0);
	return -nfs_stat_to_errno(status);
}
Ejemplo n.º 2
0
Archivo: xdr4.c Proyecto: 274914765/C
/*
 * Encode a lock as part of an NLM call
 */
static __be32 *
nlm4_encode_lock(__be32 *p, struct nlm_lock *lock)
{
    struct file_lock    *fl = &lock->fl;
    __s64            start, len;

    if (!(p = xdr_encode_string(p, lock->caller))
     || !(p = nlm4_encode_fh(p, &lock->fh))
     || !(p = nlm4_encode_oh(p, &lock->oh)))
        return NULL;

    if (fl->fl_start > NLM4_OFFSET_MAX
     || (fl->fl_end > NLM4_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
        return NULL;

    *p++ = htonl(lock->svid);

    start = loff_t_to_s64(fl->fl_start);
    if (fl->fl_end == OFFSET_MAX)
        len = 0;
    else
        len = loff_t_to_s64(fl->fl_end - fl->fl_start + 1);

    p = xdr_encode_hyper(p, start);
    p = xdr_encode_hyper(p, len);

    return p;
}
Ejemplo n.º 3
0
static int *nfs_rpc_header(int *p, int procedure, int ruid)
{
	int *p1, *p2;
	int i;
	static int xid = 0;
	unsigned char *sys = (unsigned char *) system_utsname.nodename;

	if (xid == 0) {
		xid = CURRENT_TIME;
		xid ^= (sys[3]<<24) | (sys[2]<<16) | (sys[1]<<8) | sys[0];
	}
	*p++ = htonl(++xid);
	*p++ = htonl(RPC_CALL);
	*p++ = htonl(RPC_VERSION);
	*p++ = htonl(NFS_PROGRAM);
	*p++ = htonl(NFS_VERSION);
	*p++ = htonl(procedure);
	*p++ = htonl(RPC_AUTH_UNIX);
	p1 = p++;
	*p++ = htonl(CURRENT_TIME); /* traditional, could be anything */
	p = xdr_encode_string(p, (char *) sys);
	*p++ = htonl(ruid ? current->uid : current->fsuid);
	*p++ = htonl(current->egid);
	p2 = p++;
	for (i = 0; i < 16 && i < NGROUPS && current->groups[i] != NOGROUP; i++)
		*p++ = htonl(current->groups[i]);
	*p2 = htonl(i);
	*p1 = htonl((p - (p1 + 1)) << 2);
	*p++ = htonl(RPC_AUTH_NULL);
	*p++ = htonl(0);
	return p;
}
Ejemplo n.º 4
0
int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
{
	int *p, *p0;
	int status;
	int ruid = 0;

	PRINTK("NFS call  rmdir %s\n", name);
	if (!(p0 = nfs_rpc_alloc(server->wsize)))
		return -EIO;
retry:
	p = nfs_rpc_header(p0, NFSPROC_RMDIR, ruid);
	p = xdr_encode_fhandle(p, dir);
	p = xdr_encode_string(p, name);
	if ((status = nfs_rpc_call(server, p0, p, server->wsize)) < 0) {
		nfs_rpc_free(p0);
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
		status = -errno_NFSERR_IO;
	else if ((status = ntohl(*p++)) == NFS_OK) {
		PRINTK("NFS reply rmdir\n");
		/* status = 0; */
	}
	else {
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
			ruid = 1;
			goto retry;
		}
		PRINTK("NFS reply rmdir failed = %d\n", status);
		status = -nfs_stat_to_errno(status);
	}
	nfs_rpc_free(p0);
	return status;
}
Ejemplo n.º 5
0
int 
mnt_proc_mnt(struct generic_server *server, char *directory, 
	     struct nfs_fh *fhandle) {
  
  int *p, *p0;
  int status;

  DPRINTF(CLUHELP2_LEVEL,("MNT call MNT\n"));
  if (!(p0 = overhead_rpc_alloc(server->rsize)))
    return -EIO;

  p = mnt_rpc_header(p0,MNTPROC_MNT,0);
  p = xdr_encode_string(p,directory);
  if ((status = generic_rpc_call(server, p0, p)) < 0) {
    overhead_rpc_free(p0);
    return status;
  }
  if (!(p = generic_rpc_verify(p0)))
    {status = -1;}
  else {
    status = ntohl(*p++);
	if (status == 0)
	  {
	    xdr_decode_fhandle(p, fhandle);
	    fhandle->server = server;
	    DPRINTF(CLUHELP2_LEVEL,("MNTPROC_MNT call good\n"));
	  }
      }
  DPRINTF(CLUHELP2_LEVEL,("pmap proc getmap status: %d\n",status));
  overhead_rpc_free(p0);
  return(status);
}
Ejemplo n.º 6
0
static int
xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path)
{
	p = xdr_encode_string(p, path);

	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
	return 0;
}
Ejemplo n.º 7
0
static u32 *
xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
{
	char	buffer[20];

	/*
	 * Use the dotted-quad IP address of the remote host as
	 * identifier. Linux statd always looks up the canonical
	 * hostname first for whatever remote hostname it receives,
	 * so this works alright.
	 */
	sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr));
	if (!(p = xdr_encode_string(p, buffer))
	 || !(p = xdr_encode_string(p, system_utsname.nodename)))
		return ERR_PTR(-EIO);
	*p++ = htonl(argp->prog);
	*p++ = htonl(argp->vers);
	*p++ = htonl(argp->proc);

	return p;
}
Ejemplo n.º 8
0
int nfs_proc_rename(struct nfs_server *server,
		    struct nfs_fh *old_dir, const char *old_name,
		    struct nfs_fh *new_dir, const char *new_name)
{
	int *p, *p0;
	int status;
	int ruid = 0;

	PRINTK("NFS call  rename %s -> %s\n", old_name, new_name);
	if (!(p0 = nfs_rpc_alloc()))
		return -EIO;
retry:
	p = nfs_rpc_header(p0, NFSPROC_RENAME, ruid);
	p = xdr_encode_fhandle(p, old_dir);
	p = xdr_encode_string(p, old_name);
	p = xdr_encode_fhandle(p, new_dir);
	p = xdr_encode_string(p, new_name);
	if ((status = nfs_rpc_call(server, p0, p)) < 0) {
		nfs_rpc_free(p0);
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
		status = NFSERR_IO;
	else if ((status = ntohl(*p++)) == NFS_OK) {
		PRINTK("NFS reply rename\n");
	}
	else {
		if (!ruid && current->euid == 0 && current->uid != 0) {
			ruid = 1;
			goto retry;
		}
		PRINTK("NFS reply rename failed = %d\n", status);
	}
	nfs_rpc_free(p0);
	return -nfs_stat_to_errno(status);
}
Ejemplo n.º 9
0
static int
xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
{
	char	buffer[20];
	u32	addr = ntohl(argp->addr);

	dprintk("nsm: xdr_encode_mon(%08x, %d, %d, %d)\n",
			htonl(argp->addr), htonl(argp->proc),
			htonl(argp->vers), htonl(argp->proc));

	/*
	 * Use the dotted-quad IP address of the remote host as
	 * identifier. Linux statd always looks up the canonical
	 * hostname first for whatever remote hostname it receives,
	 * so this works alright.
	 */
	sprintf(buffer, "%d.%d.%d.%d", (addr>>24) & 0xff, (addr>>16) & 0xff,
				 	(addr>>8) & 0xff,  (addr) & 0xff);
	if (!(p = xdr_encode_string(p, buffer))
	 || !(p = xdr_encode_string(p, system_utsname.nodename)))
		return -EIO;
	*p++ = htonl(argp->prog);
	*p++ = htonl(argp->vers);
	*p++ = htonl(argp->proc);

	/* This is the private part. Needed only for SM_MON call */
	if (rqstp->rq_task->tk_proc == SM_MON) {
		*p++ = argp->addr;
		*p++ = 0;
		*p++ = 0;
		*p++ = 0;
	}

	rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
	return 0;
}
Ejemplo n.º 10
0
int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name,
		    struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
	int *p, *p0;
	int status;
	int ruid = 0;

	PRINTK("NFS call  lookup %s\n", name);
#ifdef NFS_PROC_DEBUG
	if (!strcmp(name, "xyzzy"))
		proc_debug = 1 - proc_debug;
#endif
	if (!(p0 = nfs_rpc_alloc(server->rsize)))
		return -EIO;
retry:
	p = nfs_rpc_header(p0, NFSPROC_LOOKUP, ruid);
	p = xdr_encode_fhandle(p, dir);
	p = xdr_encode_string(p, name);
	if ((status = nfs_rpc_call(server, p0, p, server->rsize)) < 0) {
		nfs_rpc_free(p0);
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
		status = -errno_NFSERR_IO;
	else if ((status = ntohl(*p++)) == NFS_OK) {
		p = xdr_decode_fhandle(p, fhandle);
		p = xdr_decode_fattr(p, fattr);
		PRINTK("NFS reply lookup\n");
		/* status = 0; */
	}
	else {
		if (!ruid && current->fsuid == 0 && current->uid != 0) {
			ruid = 1;
			goto retry;
		}
		PRINTK("NFS reply lookup failed = %d\n", status);
		status = -nfs_stat_to_errno(status);
	}
	nfs_rpc_free(p0);
	return status;
}
Ejemplo n.º 11
0
int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
		    const char *name, struct nfs_sattr *sattr,
		    struct nfs_fh *fhandle, struct nfs_fattr *fattr)
{
	int *p, *p0;
	int status;
	int ruid = 0;

	PRINTK("NFS call  create %s\n", name);
	if (!(p0 = nfs_rpc_alloc()))
		return -EIO;
retry:
	p = nfs_rpc_header(p0, NFSPROC_CREATE, ruid);
	p = xdr_encode_fhandle(p, dir);
	p = xdr_encode_string(p, name);
	p = xdr_encode_sattr(p, sattr);
	if ((status = nfs_rpc_call(server, p0, p)) < 0) {
		nfs_rpc_free(p0);
		return status;
	}
	if (!(p = nfs_rpc_verify(p0)))
		status = NFSERR_IO;
	else if ((status = ntohl(*p++)) == NFS_OK) {
		p = xdr_decode_fhandle(p, fhandle);
		p = xdr_decode_fattr(p, fattr);
		PRINTK("NFS reply create\n");
	}
	else {
		if (!ruid && current->euid == 0 && current->uid != 0) {
			ruid = 1;
			goto retry;
		}
		PRINTK("NFS reply create failed = %d\n", status);
	}
	nfs_rpc_free(p0);
	return -nfs_stat_to_errno(status);
}
Ejemplo n.º 12
0
int 
mnt_proc_umnt(struct generic_server *server, const char *dirname) {
  int *p, *p0;
  int status;

  DPRINTF(CLUHELP2_LEVEL,("MNT call UMNT\n"));
  if (!(p0 = overhead_rpc_alloc(server->rsize)))
    return -EIO;

  p = mnt_rpc_header(p0,MNTPROC_UMNT,0);
  p = xdr_encode_string(p,dirname);
  if ((status = generic_rpc_call(server, p0, p)) < 0) {
    overhead_rpc_free(p0);
    return status;
  }
  if (!(p = generic_rpc_verify(p0)))
    {status = 0;}
  else {
    status = 1;
    DPRINTF(CLUHELP2_LEVEL,("MNTPROC_UMNT good\n"));
  }
  overhead_rpc_free(p0);
  return(status);
}
Ejemplo n.º 13
0
/**
 * rpcb_register - set or unset a port registration with the local rpcbind svc
 * @prog: RPC program number to bind
 * @vers: RPC version number to bind
 * @prot: transport protocol to use to make this request
 * @port: port value to register
 * @okay: result code
 *
 * port == 0 means unregister, port != 0 means register.
 *
 * This routine supports only rpcbind version 2.
 */
int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
{
	struct sockaddr_in sin = {
		.sin_family		= AF_INET,
		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
	};
	struct rpcbind_args map = {
		.r_prog		= prog,
		.r_vers		= vers,
		.r_prot		= prot,
		.r_port		= port,
	};
	struct rpc_message msg = {
		.rpc_proc	= &rpcb_procedures2[port ?
					RPCBPROC_SET : RPCBPROC_UNSET],
		.rpc_argp	= &map,
		.rpc_resp	= okay,
	};
	struct rpc_clnt *rpcb_clnt;
	int error = 0;

	dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
			"rpcbind\n", (port ? "" : "un"),
			prog, vers, prot, port);

	rpcb_clnt = rpcb_create("localhost", (struct sockaddr *) &sin,
				sizeof(sin), XPRT_TRANSPORT_UDP, 2, 1);
	if (IS_ERR(rpcb_clnt))
		return PTR_ERR(rpcb_clnt);

	error = rpc_call_sync(rpcb_clnt, &msg, 0);

	rpc_shutdown_client(rpcb_clnt);
	if (error < 0)
		printk(KERN_WARNING "RPC: failed to contact local rpcbind "
				"server (errno %d).\n", -error);
	dprintk("RPC:       registration status %d/%d\n", error, *okay);

	return error;
}

/**
 * rpcb_getport_sync - obtain the port for an RPC service on a given host
 * @sin: address of remote peer
 * @prog: RPC program number to bind
 * @vers: RPC version number to bind
 * @prot: transport protocol to use to make this request
 *
 * Return value is the requested advertised port number,
 * or a negative errno value.
 *
 * Called from outside the RPC client in a synchronous task context.
 * Uses default timeout parameters specified by underlying transport.
 *
 * XXX: Needs to support IPv6
 */
int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot)
{
	struct rpcbind_args map = {
		.r_prog		= prog,
		.r_vers		= vers,
		.r_prot		= prot,
		.r_port		= 0,
	};
	struct rpc_message msg = {
		.rpc_proc	= &rpcb_procedures2[RPCBPROC_GETPORT],
		.rpc_argp	= &map,
		.rpc_resp	= &map.r_port,
	};
	struct rpc_clnt	*rpcb_clnt;
	int status;

	dprintk("RPC:       %s(" NIPQUAD_FMT ", %u, %u, %d)\n",
		__FUNCTION__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot);

	rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin,
				sizeof(*sin), prot, 2, 0);
	if (IS_ERR(rpcb_clnt))
		return PTR_ERR(rpcb_clnt);

	status = rpc_call_sync(rpcb_clnt, &msg, 0);
	rpc_shutdown_client(rpcb_clnt);

	if (status >= 0) {
		if (map.r_port != 0)
			return map.r_port;
		status = -EACCES;
	}
	return status;
}
EXPORT_SYMBOL_GPL(rpcb_getport_sync);

static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbind_args *map, int version)
{
	struct rpc_message msg = {
		.rpc_proc = rpcb_next_version[version].rpc_proc,
		.rpc_argp = map,
		.rpc_resp = &map->r_port,
	};
	struct rpc_task_setup task_setup_data = {
		.rpc_client = rpcb_clnt,
		.rpc_message = &msg,
		.callback_ops = &rpcb_getport_ops,
		.callback_data = map,
		.flags = RPC_TASK_ASYNC,
	};

	return rpc_run_task(&task_setup_data);
}

/**
 * rpcb_getport_async - obtain the port for a given RPC service on a given host
 * @task: task that is waiting for portmapper request
 *
 * This one can be called for an ongoing RPC request, and can be used in
 * an async (rpciod) context.
 */
void rpcb_getport_async(struct rpc_task *task)
{
	struct rpc_clnt *clnt = task->tk_client;
	u32 bind_version;
	struct rpc_xprt *xprt = task->tk_xprt;
	struct rpc_clnt	*rpcb_clnt;
	static struct rpcbind_args *map;
	struct rpc_task	*child;
	struct sockaddr_storage addr;
	struct sockaddr *sap = (struct sockaddr *)&addr;
	size_t salen;
	int status;
	struct rpcb_info *info;

	dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
		task->tk_pid, __FUNCTION__,
		clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot);

	/* Autobind on cloned rpc clients is discouraged */
	BUG_ON(clnt->cl_parent != clnt);

	if (xprt_test_and_set_binding(xprt)) {
		status = -EAGAIN;	/* tell caller to check again */
		dprintk("RPC: %5u %s: waiting for another binder\n",
			task->tk_pid, __FUNCTION__);
		goto bailout_nowake;
	}

	/* Put self on queue before sending rpcbind request, in case
	 * rpcb_getport_done completes before we return from rpc_run_task */
	rpc_sleep_on(&xprt->binding, task, NULL, NULL);

	/* Someone else may have bound if we slept */
	if (xprt_bound(xprt)) {
		status = 0;
		dprintk("RPC: %5u %s: already bound\n",
			task->tk_pid, __FUNCTION__);
		goto bailout_nofree;
	}

	salen = rpc_peeraddr(clnt, sap, sizeof(addr));

	/* Don't ever use rpcbind v2 for AF_INET6 requests */
	switch (sap->sa_family) {
	case AF_INET:
		info = rpcb_next_version;
		break;
	case AF_INET6:
		info = rpcb_next_version6;
		break;
	default:
		status = -EAFNOSUPPORT;
		dprintk("RPC: %5u %s: bad address family\n",
				task->tk_pid, __FUNCTION__);
		goto bailout_nofree;
	}
	if (info[xprt->bind_index].rpc_proc == NULL) {
		xprt->bind_index = 0;
		status = -EPFNOSUPPORT;
		dprintk("RPC: %5u %s: no more getport versions available\n",
			task->tk_pid, __FUNCTION__);
		goto bailout_nofree;
	}
	bind_version = info[xprt->bind_index].rpc_vers;

	dprintk("RPC: %5u %s: trying rpcbind version %u\n",
		task->tk_pid, __FUNCTION__, bind_version);

	rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot,
				bind_version, 0);
	if (IS_ERR(rpcb_clnt)) {
		status = PTR_ERR(rpcb_clnt);
		dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n",
			task->tk_pid, __FUNCTION__, PTR_ERR(rpcb_clnt));
		goto bailout_nofree;
	}

	map = kzalloc(sizeof(struct rpcbind_args), GFP_ATOMIC);
	if (!map) {
		status = -ENOMEM;
		dprintk("RPC: %5u %s: no memory available\n",
			task->tk_pid, __FUNCTION__);
		goto bailout_nofree;
	}
	map->r_prog = clnt->cl_prog;
	map->r_vers = clnt->cl_vers;
	map->r_prot = xprt->prot;
	map->r_port = 0;
	map->r_xprt = xprt_get(xprt);
	map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID);
	map->r_addr = rpc_peeraddr2str(rpcb_clnt, RPC_DISPLAY_UNIVERSAL_ADDR);
	map->r_owner = RPCB_OWNER_STRING;	/* ignored for GETADDR */

	child = rpcb_call_async(rpcb_clnt, map, xprt->bind_index);
	rpc_release_client(rpcb_clnt);
	if (IS_ERR(child)) {
		status = -EIO;
		dprintk("RPC: %5u %s: rpc_run_task failed\n",
			task->tk_pid, __FUNCTION__);
		goto bailout;
	}
	rpc_put_task(child);

	task->tk_xprt->stat.bind_count++;
	return;

bailout:
	kfree(map);
	xprt_put(xprt);
bailout_nofree:
	rpcb_wake_rpcbind_waiters(xprt, status);
bailout_nowake:
	task->tk_status = status;
}
EXPORT_SYMBOL_GPL(rpcb_getport_async);

/*
 * Rpcbind child task calls this callback via tk_exit.
 */
static void rpcb_getport_done(struct rpc_task *child, void *data)
{
	struct rpcbind_args *map = data;
	struct rpc_xprt *xprt = map->r_xprt;
	int status = child->tk_status;

	/* Garbage reply: retry with a lesser rpcbind version */
	if (status == -EIO)
		status = -EPROTONOSUPPORT;

	/* rpcbind server doesn't support this rpcbind protocol version */
	if (status == -EPROTONOSUPPORT)
		xprt->bind_index++;

	if (status < 0) {
		/* rpcbind server not available on remote host? */
		xprt->ops->set_port(xprt, 0);
	} else if (map->r_port == 0) {
		/* Requested RPC service wasn't registered on remote host */
		xprt->ops->set_port(xprt, 0);
		status = -EACCES;
	} else {
		/* Succeeded */
		xprt->ops->set_port(xprt, map->r_port);
		xprt_set_bound(xprt);
		status = 0;
	}

	dprintk("RPC: %5u rpcb_getport_done(status %d, port %u)\n",
			child->tk_pid, status, map->r_port);

	rpcb_wake_rpcbind_waiters(xprt, status);
}

static int rpcb_encode_mapping(struct rpc_rqst *req, __be32 *p,
			       struct rpcbind_args *rpcb)
{
	dprintk("RPC:       rpcb_encode_mapping(%u, %u, %d, %u)\n",
			rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);
	*p++ = htonl(rpcb->r_prog);
	*p++ = htonl(rpcb->r_vers);
	*p++ = htonl(rpcb->r_prot);
	*p++ = htonl(rpcb->r_port);

	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
	return 0;
}

static int rpcb_decode_getport(struct rpc_rqst *req, __be32 *p,
			       unsigned short *portp)
{
	*portp = (unsigned short) ntohl(*p++);
	dprintk("RPC:      rpcb_decode_getport result %u\n",
			*portp);
	return 0;
}

static int rpcb_decode_set(struct rpc_rqst *req, __be32 *p,
			   unsigned int *boolp)
{
	*boolp = (unsigned int) ntohl(*p++);
	dprintk("RPC:      rpcb_decode_set result %u\n",
			*boolp);
	return 0;
}

static int rpcb_encode_getaddr(struct rpc_rqst *req, __be32 *p,
			       struct rpcbind_args *rpcb)
{
	dprintk("RPC:       rpcb_encode_getaddr(%u, %u, %s)\n",
			rpcb->r_prog, rpcb->r_vers, rpcb->r_addr);
	*p++ = htonl(rpcb->r_prog);
	*p++ = htonl(rpcb->r_vers);

	p = xdr_encode_string(p, rpcb->r_netid);
	p = xdr_encode_string(p, rpcb->r_addr);
	p = xdr_encode_string(p, rpcb->r_owner);

	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);

	return 0;
}
Ejemplo n.º 14
0
/* Using the mount protocol, lookup NAME at host HOST.
   Return a node for it or null for an error.  If an
   error occurs, a message is automatically sent to stderr. */
struct node *
mount_root (char *name, char *host)
{
  struct sockaddr_in addr;
  struct hostent *h;
  int *p;
  void *rpcbuf;
  int port;
  error_t err;
  struct node *np;
  short pmapport;

  /* Lookup the portmapper port number */
  if (pmap_service_name)
    {
      struct servent *s;

      /* XXX This will always fail! pmap_service_name will always be "sunrpc"
         What should pmap_service_name really be?  By definition the second
	 argument is either "tcp" or "udp"  Thus, is this backwards
	 (as service_name suggests)?  If so, should it read:
             s = getservbyname (pmap_service_name, "udp");
         or is there something I am missing here?  */
      s = getservbyname ("sunrpc", pmap_service_name);
      if (s)
	pmapport = s->s_port;
      else
	pmapport = htons (pmap_service_number);
    }
  else
    pmapport = htons (pmap_service_number);

  /* Lookup the host */
  h = gethostbyname (host);
  if (!h)
    {
      herror (host);
      return 0;
    }

  addr.sin_family = h->h_addrtype;
  memcpy (&addr.sin_addr, h->h_addr_list[0], h->h_length);
  addr.sin_port = pmapport;

  if (mount_port_override)
    addr.sin_port = htons (mount_port);
  else
    {
      /* Formulate and send a PMAPPROC_GETPORT request
	 to lookup the mount program on the server.  */
      if (connect (main_udp_socket, (struct sockaddr *)&addr,
	           sizeof (struct sockaddr_in)) == -1)
	{
	  error (0, errno, "server mount program");
	  return 0;
	}

      p = pmap_initialize_rpc (PMAPPROC_GETPORT, &rpcbuf);
      if (! p)
	{
	  error (0, errno, "creating rpc packet");
	  return 0;
	}

      *(p++) = htonl (MOUNTPROG);
      *(p++) = htonl (MOUNTVERS);
      *(p++) = htonl (IPPROTO_UDP);
      *(p++) = htonl (0);
      err = conduct_rpc (&rpcbuf, &p);
      if (!err)
	{
	  port = ntohl (*p);
	  p++;
	  addr.sin_port = htons (port);
	}
      else if (mount_port)
	addr.sin_port = htons (mount_port);
      else
	{
	  error (0, err, "portmap of mount");
	  goto error_with_rpcbuf;
	}
      free (rpcbuf);
    }

  /* Now, talking to the mount program, fetch a file handle
     for the root. */
  if (connect (main_udp_socket, (struct sockaddr *) &addr,
	       sizeof (struct sockaddr_in)) == -1)
    {
      error (0, errno, "connect");
      goto error_with_rpcbuf;
    }

  p = mount_initialize_rpc (MOUNTPROC_MNT, &rpcbuf);
  if (! p)
    {
      error (0, errno, "rpc");
      goto error_with_rpcbuf;
    }

  p = xdr_encode_string (p, name);
  err = conduct_rpc (&rpcbuf, &p);
  if (err)
    {
      error (0, err, "%s", name);
      goto error_with_rpcbuf;
    }
  /* XXX Protocol spec says this should be a "unix error code"; we'll
     pretend that an NFS error code is what's meant; the numbers match
     anyhow.  */
  err = nfs_error_trans (htonl (*p));
  p++;
  if (err)
    {
      error (0, err, "%s", name);
      goto error_with_rpcbuf;
    }

  /* Create the node for root */
  xdr_decode_fhandle (p, &np);
  free (rpcbuf);
  pthread_mutex_unlock (&np->lock);

  if (nfs_port_override)
    port = nfs_port;
  else
    {
      /* Send another PMAPPROC_GETPORT request to lookup the nfs server. */
      addr.sin_port = pmapport;
      if (connect (main_udp_socket, (struct sockaddr *) &addr,
	           sizeof (struct sockaddr_in)) == -1)
	{
	  error (0, errno, "connect");
	  return 0;
	}

      p = pmap_initialize_rpc (PMAPPROC_GETPORT, &rpcbuf);
      if (! p)
	{
	  error (0, errno, "rpc");
	  goto error_with_rpcbuf;
	}
      *(p++) = htonl (NFS_PROGRAM);
      *(p++) = htonl (NFS_VERSION);
      *(p++) = htonl (IPPROTO_UDP);
      *(p++) = htonl (0);
      err = conduct_rpc (&rpcbuf, &p);
      if (!err)
	{
	  port = ntohl (*p);
	  p++;
	}
      else if (nfs_port)
	port = nfs_port;
      else
	{
	  error (0, err, "portmap of nfs server");
	  goto error_with_rpcbuf;
	}
      free (rpcbuf);
    }

  addr.sin_port = htons (port);
  if (connect (main_udp_socket, (struct sockaddr *) &addr,
	       sizeof (struct sockaddr_in)) == -1)
    {
      error (0, errno, "connect");
      return 0;
    }

  mounted_hostname = host;
  mounted_nfs_port = port;

  return np;

error_with_rpcbuf:
  free (rpcbuf);

  return 0;
}
Ejemplo n.º 15
0
/*
 * Create NSM client for the local host
 */
static struct rpc_clnt *
nsm_create(void)
{
	struct sockaddr_in	sin = {
		.sin_family	= AF_INET,
		.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
		.sin_port	= 0,
	};
	struct rpc_create_args args = {
		.protocol	= IPPROTO_UDP,
		.address	= (struct sockaddr *)&sin,
		.addrsize	= sizeof(sin),
		.servername	= "localhost",
		.program	= &nsm_program,
		.version	= SM_VERSION,
		.authflavor	= RPC_AUTH_NULL,
		.flags		= (RPC_CLNT_CREATE_ONESHOT),
	};

	return rpc_create(&args);
}

/*
 * XDR functions for NSM.
 */

static __be32 *
xdr_encode_common(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
{
	char	buffer[20], *name;

	/*
	 * Use the dotted-quad IP address of the remote host as
	 * identifier. Linux statd always looks up the canonical
	 * hostname first for whatever remote hostname it receives,
	 * so this works alright.
	 */
	if (nsm_use_hostnames) {
		name = argp->mon_name;
	} else {
		sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr));
		name = buffer;
	}
	if (!(p = xdr_encode_string(p, name))
	 || !(p = xdr_encode_string(p, utsname()->nodename)))
		return ERR_PTR(-EIO);
	*p++ = htonl(argp->prog);
	*p++ = htonl(argp->vers);
	*p++ = htonl(argp->proc);

	return p;
}

static int
xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
{
	p = xdr_encode_common(rqstp, p, argp);
	if (IS_ERR(p))
		return PTR_ERR(p);

	/* Surprise - there may even be room for an IPv6 address now */
	*p++ = argp->addr;
	*p++ = 0;
	*p++ = 0;
	*p++ = 0;
	rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
	return 0;
}