xref: /dragonfly/sys/vfs/nfs/nfs_mountrpc.c (revision 956939d5)
1 /*
2  * Copyright (c) 1995 Gordon Ross, Adam Glass
3  * Copyright (c) 1992 Regents of the University of California.
4  * All rights reserved.
5  *
6  * This software was developed by the Computer Systems Engineering group
7  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
8  * contributed to Berkeley.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Lawrence Berkeley Laboratory and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * nfs/krpc_subr.c
39  * $NetBSD: krpc_subr.c,v 1.10 1995/08/08 20:43:43 gwr Exp $
40  * $FreeBSD: src/sys/nfs/bootp_subr.c,v 1.20.2.9 2003/04/24 16:51:08 ambrisko Exp $
41  * $DragonFly: src/sys/vfs/nfs/nfs_mountrpc.c,v 1.2 2006/12/23 00:41:29 swildner Exp $
42  */
43 /*
44  * Procedures used by NFS_ROOT and BOOTP to do an NFS mount rpc to obtain
45  * the nfs root file handle for a NFS-based root mount point.  This module
46  * is not used by normal operating code because the 'mount' command has a
47  * far more sophisticated implementation.
48  */
49 #include "opt_bootp.h"
50 #include "opt_nfsroot.h"
51 
52 #if defined(BOOTP) || defined(NFS_ROOT)
53 
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #include <sys/kernel.h>
57 #include <sys/sockio.h>
58 #include <sys/proc.h>
59 #include <sys/malloc.h>
60 #include <sys/mount.h>
61 #include <sys/mbuf.h>
62 #include <sys/socket.h>
63 #include <sys/socketvar.h>
64 #include <sys/sysctl.h>
65 #include <sys/uio.h>
66 
67 #include <net/if.h>
68 #include <net/route.h>
69 
70 #include <netinet/in.h>
71 #include <net/if_types.h>
72 #include <net/if_dl.h>
73 
74 #include "rpcv2.h"
75 #include "nfsproto.h"
76 #include "nfs.h"
77 #include "nfsdiskless.h"
78 #include "krpc.h"
79 #include "xdr_subs.h"
80 #include "nfsmountrpc.h"
81 
82 /*
83  * What is the longest we will wait before re-sending a request?
84  * Note this is also the frequency of "RPC timeout" messages.
85  * The re-send loop count sup linearly to this maximum, so the
86  * first complaint will happen after (1+2+3+4+5)=15 seconds.
87  */
88 
89 static int getdec(char **ptr);
90 static char *substr(char *a,char *b);
91 static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len);
92 static int xdr_int_decode(struct mbuf **ptr, int *iptr);
93 
94 void
95 mountopts(struct nfs_args *args, char *p)
96 {
97 	char *tmp;
98 
99 	args->version = NFS_ARGSVERSION;
100 	args->rsize = 8192;
101 	args->wsize = 8192;
102 	args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
103 	args->sotype = SOCK_DGRAM;
104 	if (p == NULL)
105 		return;
106 	if ((tmp = (char *)substr(p, "rsize=")))
107 		args->rsize = getdec(&tmp);
108 	if ((tmp = (char *)substr(p, "wsize=")))
109 		args->wsize = getdec(&tmp);
110 	if ((tmp = (char *)substr(p, "intr")))
111 		args->flags |= NFSMNT_INT;
112 	if ((tmp = (char *)substr(p, "soft")))
113 		args->flags |= NFSMNT_SOFT;
114 	if ((tmp = (char *)substr(p, "noconn")))
115 		args->flags |= NFSMNT_NOCONN;
116 	if ((tmp = (char *)substr(p, "tcp")))
117 		args->sotype = SOCK_STREAM;
118 }
119 
120 /*
121  * RPC: mountd/mount
122  * Given a server pathname, get an NFS file handle.
123  * Also, sets sin->sin_port to the NFS service port.
124  */
125 int
126 md_mount(struct sockaddr_in *mdsin,		/* mountd server address */
127 	 char *path,
128 	 u_char *fhp,
129 	 int *fhsizep,
130 	 struct nfs_args *args,
131 	 struct thread *td)
132 {
133 	struct mbuf *m;
134 	int error;
135 	int authunixok;
136 	int authcount;
137 	int authver;
138 
139 #ifdef BOOTP_NFSV3
140 	/* First try NFS v3 */
141 	/* Get port number for MOUNTD. */
142 	error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
143 			     &mdsin->sin_port, td);
144 	if (error == 0) {
145 		m = xdr_string_encode(path, strlen(path));
146 
147 		/* Do RPC to mountd. */
148 		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
149 				  RPCMNT_MOUNT, &m, NULL, td);
150 	}
151 	if (error == 0) {
152 		args->flags |= NFSMNT_NFSV3;
153 	} else {
154 #endif
155 		/* Fallback to NFS v2 */
156 
157 		/* Get port number for MOUNTD. */
158 		error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
159 				     &mdsin->sin_port, td);
160 		if (error != 0)
161 			return error;
162 
163 		m = xdr_string_encode(path, strlen(path));
164 
165 		/* Do RPC to mountd. */
166 		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
167 				  RPCMNT_MOUNT, &m, NULL, td);
168 		if (error != 0)
169 			return error;	/* message already freed */
170 
171 #ifdef BOOTP_NFSV3
172 	}
173 #endif
174 
175 	if (xdr_int_decode(&m, &error) != 0 || error != 0)
176 		goto bad;
177 
178 	if ((args->flags & NFSMNT_NFSV3) != 0) {
179 		if (xdr_int_decode(&m, fhsizep) != 0 ||
180 		    *fhsizep > NFSX_V3FHMAX ||
181 		    *fhsizep <= 0)
182 			goto bad;
183 	} else
184 		*fhsizep = NFSX_V2FH;
185 
186 	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
187 		goto bad;
188 
189 	if (args->flags & NFSMNT_NFSV3) {
190 		if (xdr_int_decode(&m, &authcount) != 0)
191 			goto bad;
192 		authunixok = 0;
193 		if (authcount < 0 || authcount > 100)
194 			goto bad;
195 		while (authcount > 0) {
196 			if (xdr_int_decode(&m, &authver) != 0)
197 				goto bad;
198 			if (authver == RPCAUTH_UNIX)
199 				authunixok = 1;
200 			authcount--;
201 		}
202 		if (authunixok == 0)
203 			goto bad;
204 	}
205 
206 	/* Set port number for NFS use. */
207 	error = krpc_portmap(mdsin, NFS_PROG,
208 			     (args->flags &
209 			      NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
210 			     &mdsin->sin_port, td);
211 
212 	goto out;
213 
214 bad:
215 	error = EBADRPC;
216 
217 out:
218 	m_freem(m);
219 	return error;
220 }
221 
222 int
223 md_lookup_swap(struct sockaddr_in *mdsin,	/* mountd server address */
224 	       char *path,
225 	       u_char *fhp,
226 	       int *fhsizep,
227 	       struct nfs_args *args,
228 	       struct thread *td)
229 {
230 	struct mbuf *m;
231 	int error;
232 	int size = -1;
233 	int attribs_present;
234 	int status;
235 	union {
236 		u_int32_t v2[17];
237 		u_int32_t v3[21];
238 	} fattribs;
239 
240 	m = m_get(MB_WAIT,MT_DATA);
241 	if (m == NULL)
242 	  	return ENOBUFS;
243 
244 	if ((args->flags & NFSMNT_NFSV3) != 0) {
245 		*mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep);
246 		bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep);
247 		m->m_len = *fhsizep + sizeof(u_int32_t);
248 	} else {
249 		bcopy(fhp, mtod(m, u_char *), NFSX_V2FH);
250 		m->m_len = NFSX_V2FH;
251 	}
252 
253 	m->m_next = xdr_string_encode(path, strlen(path));
254 	if (m->m_next == NULL) {
255 		error = ENOBUFS;
256 		goto out;
257 	}
258 
259 	/* Do RPC to nfsd. */
260 	if ((args->flags & NFSMNT_NFSV3) != 0)
261 		error = krpc_call(mdsin, NFS_PROG, NFS_VER3,
262 				  NFSPROC_LOOKUP, &m, NULL, td);
263 	else
264 		error = krpc_call(mdsin, NFS_PROG, NFS_VER2,
265 				  NFSV2PROC_LOOKUP, &m, NULL, td);
266 	if (error != 0)
267 		return error;	/* message already freed */
268 
269 	if (xdr_int_decode(&m, &status) != 0)
270 		goto bad;
271 	if (status != 0) {
272 		error = ENOENT;
273 		goto out;
274 	}
275 
276 	if ((args->flags & NFSMNT_NFSV3) != 0) {
277 		if (xdr_int_decode(&m, fhsizep) != 0 ||
278 		    *fhsizep > NFSX_V3FHMAX ||
279 		    *fhsizep <= 0)
280 			goto bad;
281 	} else
282 		*fhsizep = NFSX_V2FH;
283 
284 	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
285 		goto bad;
286 
287 	if ((args->flags & NFSMNT_NFSV3) != 0) {
288 		if (xdr_int_decode(&m, &attribs_present) != 0)
289 			goto bad;
290 		if (attribs_present != 0) {
291 			if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3,
292 					      sizeof(u_int32_t) * 21) != 0)
293 				goto bad;
294 			size = fxdr_unsigned(u_int32_t, fattribs.v3[6]);
295 		}
296 	} else {
297 		if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2,
298 				      sizeof(u_int32_t) * 17) != 0)
299 			goto bad;
300 		size = fxdr_unsigned(u_int32_t, fattribs.v2[5]);
301 	}
302 
303 	if (nfsv3_diskless.swap_nblks == 0 && size != -1) {
304 		nfsv3_diskless.swap_nblks = size / 1024;
305 		kprintf("md_lookup_swap: Swap size is %d KB\n",
306 		       nfsv3_diskless.swap_nblks);
307 	}
308 
309 	goto out;
310 
311 bad:
312 	error = EBADRPC;
313 
314 out:
315 	m_freem(m);
316 	return error;
317 }
318 
319 int
320 setfs(struct sockaddr_in *addr, char *path, char *p)
321 {
322 	unsigned int ip;
323 	int val;
324 
325 	ip = 0;
326 	if (((val = getdec(&p)) < 0) || (val > 255))
327 		return 0;
328 	ip = val << 24;
329 	if (*p != '.')
330 		return 0;
331 	p++;
332 	if (((val = getdec(&p)) < 0) || (val > 255))
333 		return 0;
334 	ip |= (val << 16);
335 	if (*p != '.')
336 		return 0;
337 	p++;
338 	if (((val = getdec(&p)) < 0) || (val > 255))
339 		return 0;
340 	ip |= (val << 8);
341 	if (*p != '.')
342 		return 0;
343 	p++;
344 	if (((val = getdec(&p)) < 0) || (val > 255))
345 		return 0;
346 	ip |= val;
347 	if (*p != ':')
348 		return 0;
349 	p++;
350 
351 	addr->sin_addr.s_addr = htonl(ip);
352 	addr->sin_len = sizeof(struct sockaddr_in);
353 	addr->sin_family = AF_INET;
354 
355 	strncpy(path, p, MNAMELEN - 1);
356 	return 1;
357 }
358 
359 static int
360 getdec(char **ptr)
361 {
362 	char *p;
363 	int ret;
364 
365 	p = *ptr;
366 	ret = 0;
367 	if ((*p < '0') || (*p > '9'))
368 		return -1;
369 	while ((*p >= '0') && (*p <= '9')) {
370 		ret = ret * 10 + (*p - '0');
371 		p++;
372 	}
373 	*ptr = p;
374 	return ret;
375 }
376 
377 static char *
378 substr(char *a, char *b)
379 {
380 	char *loc1;
381 	char *loc2;
382 
383         while (*a != '\0') {
384                 loc1 = a;
385                 loc2 = b;
386                 while (*loc1 == *loc2++) {
387                         if (*loc1 == '\0')
388 				return 0;
389                         loc1++;
390                         if (*loc2 == '\0')
391 				return loc1;
392                 }
393 		a++;
394         }
395         return 0;
396 }
397 
398 static int
399 xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len)
400 {
401 	struct mbuf *m;
402 	int alignedlen;
403 
404 	m = *mptr;
405 	alignedlen = ( len + 3 ) & ~3;
406 
407 	if (m->m_len < alignedlen) {
408 		m = m_pullup(m, alignedlen);
409 		if (m == NULL) {
410 			*mptr = NULL;
411 			return EBADRPC;
412 		}
413 	}
414 	bcopy(mtod(m, u_char *), buf, len);
415 	m_adj(m, alignedlen);
416 	*mptr = m;
417 	return 0;
418 }
419 
420 static int
421 xdr_int_decode(struct mbuf **mptr, int *iptr)
422 {
423 	u_int32_t i;
424 	if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0)
425 		return EBADRPC;
426 	*iptr = fxdr_unsigned(u_int32_t, i);
427 	return 0;
428 }
429 
430 #endif	/* BOOTP && NFS_ROOT */
431 
432