예제 #1
0
/*
 * RPC: bootparam/getfile
 * Given client name and file "key", get:
 *	server name
 *	server IP address
 *	server pathname
 */
int
bp_getfile(int sockfd, char *key, struct in_addr *serv_addr, char *pathname)
{
	struct {
		n_long	h[RPC_HEADER_WORDS];
		n_long  d[64];
	} sdata;
	struct {
		n_long	h[RPC_HEADER_WORDS];
		n_long  d[128];
	} rdata;
	char serv_name[FNAME_SIZE];
	char *send_tail, *recv_head;
	/* misc... */
	struct iodesc *d;
	int sn_len, path_len, rlen;

	if (!(d = socktodesc(sockfd))) {
		RPC_PRINTF(("bp_getfile: bad socket. %d\n", sockfd));
		return (-1);
	}

	send_tail = (char *)sdata.d;
	recv_head = (char *)rdata.d;

	/*
	 * Build request message.
	 */

	/* client name (hostname) */
	if (xdr_string_encode(&send_tail, hostname, hostnamelen)) {
		RPC_PRINTF(("bp_getfile: bad client\n"));
		return (-1);
	}

	/* key name (root or swap) */
	if (xdr_string_encode(&send_tail, key, strlen(key))) {
		RPC_PRINTF(("bp_getfile: bad key\n"));
		return (-1);
	}

	/* RPC: bootparam/getfile */
	d->myport = htons(--rpc_port);
	d->destip   = bp_server_addr;
	/* rpc_call will set d->destport */

	rlen = rpc_call(d,
		BOOTPARAM_PROG, BOOTPARAM_VERS, BOOTPARAM_GETFILE,
		sdata.d, send_tail - (char *)sdata.d,
		rdata.d, sizeof(rdata.d));
	if (rlen < 4) {
		RPC_PRINTF(("bp_getfile: short reply\n"));
		errno = EBADRPC;
		return (-1);
	}
	recv_head = (char *)rdata.d;

	/*
	 * Parse result message.
	 */

	/* server name */
	sn_len = FNAME_SIZE-1;
	if (xdr_string_decode(&recv_head, serv_name, &sn_len)) {
		RPC_PRINTF(("bp_getfile: bad server name\n"));
		return (-1);
	}

	/* server IP address (mountd/NFS) */
	if (xdr_inaddr_decode(&recv_head, serv_addr)) {
		RPC_PRINTF(("bp_getfile: bad server addr\n"));
		return (-1);
	}

	/* server pathname */
	path_len = MAXPATHLEN-1;
	if (xdr_string_decode(&recv_head, pathname, &path_len)) {
		RPC_PRINTF(("bp_getfile: bad server path\n"));
		return (-1);
	}

	/* success */
	return(0);
}
예제 #2
0
/*
 * RPC: mountd/mount
 * Given a server pathname, get an NFS file handle.
 * Also, sets sin->sin_port to the NFS service port.
 */
int
md_mount(struct sockaddr_in *mdsin,		/* mountd server address */
	 char *path,
	 u_char *fhp,
	 int *fhsizep,
	 struct nfs_args *args,
	 struct thread *td)
{
	struct mbuf *m;
	int error;
	int authunixok;
	int authcount;
	int authver;
	
	/* First try NFS v3 */
	/* Get port number for MOUNTD. */
	error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
			     &mdsin->sin_port, td);
	if (error == 0) {
		m = xdr_string_encode(path, strlen(path));
		
		/* Do RPC to mountd. */
		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
				  RPCMNT_MOUNT, &m, NULL, td);
	}
	if (error == 0) {
		args->flags |= NFSMNT_NFSV3;
	} else {
		/* Fallback to NFS v2 */
		
		/* Get port number for MOUNTD. */
		error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
				     &mdsin->sin_port, td);
		if (error != 0)
			return error;
		
		m = xdr_string_encode(path, strlen(path));
		
		/* Do RPC to mountd. */
		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
				  RPCMNT_MOUNT, &m, NULL, td);
		if (error != 0)
			return error;	/* message already freed */
		args->flags &= ~NFSMNT_NFSV3;
	}

	if (xdr_int_decode(&m, &error) != 0 || error != 0)
		goto bad;
	
	if ((args->flags & NFSMNT_NFSV3) != 0) {
		if (xdr_int_decode(&m, fhsizep) != 0 ||
		    *fhsizep > NFSX_V3FHMAX ||
		    *fhsizep <= 0)
			goto bad;
	} else
		*fhsizep = NFSX_V2FH;

	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
		goto bad;

	if (args->flags & NFSMNT_NFSV3) {
		if (xdr_int_decode(&m, &authcount) != 0)
			goto bad;
		authunixok = 0;
		if (authcount < 0 || authcount > 100)
			goto bad;
		while (authcount > 0) {
			if (xdr_int_decode(&m, &authver) != 0)
				goto bad;
			if (authver == RPCAUTH_UNIX)
				authunixok = 1;
			authcount--;
		}
		if (authunixok == 0)
			goto bad;
	}
	  
	/* Set port number for NFS use. */
	error = krpc_portmap(mdsin, NFS_PROG,
			     (args->flags &
			      NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
			     &mdsin->sin_port, td);
	
	goto out;
	
bad:
	error = EBADRPC;
	
out:
	m_freem(m);
	return error;
}
예제 #3
0
/*
 * RPC: mountd/mount
 * Given a server pathname, get an NFS file handle.
 * Also, sets sin->sin_port to the NFS service port.
 *
 * mdsin   mountd server address
 */
static int
md_mount(struct sockaddr_in *mdsin, char *path,
	 struct nfs_args *argp, struct lwp *lwp)
{
	/* The RPC structures */
	struct rdata {
		u_int32_t errno;
		union {
			u_int8_t  v2fh[NFSX_V2FH];
			struct {
				u_int32_t fhlen;
				u_int8_t  fh[1];
			} v3fh;
		} fh;
	} *rdata;
	struct mbuf *m;
	u_int8_t *fh;
	int minlen, error;
	int mntver;

	mntver = (argp->flags & NFSMNT_NFSV3) ? 3 : 2;
	do {
		/*
		 * Get port number for MOUNTD.
		 */
		error = krpc_portmap(mdsin, RPCPROG_MNT, mntver,
		                    IPPROTO_UDP, &mdsin->sin_port, lwp);
		if (error)
			continue;

		/* This mbuf is consumed by krpc_call. */
		m = xdr_string_encode(path, strlen(path));
		if (m == NULL)
			return ENOMEM;

		/* Do RPC to mountd. */
		error = krpc_call(mdsin, RPCPROG_MNT, mntver,
		                  RPCMNT_MOUNT, &m, NULL, lwp);
		if (error != EPROGMISMATCH)
			break;
		/* Try lower version of mountd. */
	} while (--mntver >= 1);
	if (error) {
		printf("nfs_boot: mountd error=%d\n", error);
		return error;
	}
	if (mntver != 3)
		argp->flags &= ~NFSMNT_NFSV3;

	/* The reply might have only the errno. */
	if (m->m_len < 4)
		goto bad;
	/* Have at least errno, so check that. */
	rdata = mtod(m, struct rdata *);
	error = fxdr_unsigned(u_int32_t, rdata->errno);
	if (error)
		goto out;

	/* Have errno==0, so the fh must be there. */
	if (mntver == 3) {
		argp->fhsize   = fxdr_unsigned(u_int32_t, rdata->fh.v3fh.fhlen);
		if (argp->fhsize > NFSX_V3FHMAX)
			goto bad;
		minlen = 2 * sizeof(u_int32_t) + argp->fhsize;
	} else {
		argp->fhsize   = NFSX_V2FH;
		minlen = sizeof(u_int32_t) + argp->fhsize;
	}

	if (m->m_len < minlen) {
		m = m_pullup(m, minlen);
		if (m == NULL)
			return(EBADRPC);
		rdata = mtod(m, struct rdata *);
	}