xref: /dragonfly/sys/vfs/nfs/nfs_mountrpc.c (revision ed5d5720)
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 extern struct nfsv3_diskless nfsv3_diskless;
90 
91 static int getdec(char **ptr);
92 static char *substr(char *a,char *b);
93 static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len);
94 static int xdr_int_decode(struct mbuf **ptr, int *iptr);
95 
96 void
97 mountopts(struct nfs_args *args, char *p)
98 {
99 	char *tmp;
100 
101 	args->version = NFS_ARGSVERSION;
102 	args->rsize = 8192;
103 	args->wsize = 8192;
104 	args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
105 	args->sotype = SOCK_DGRAM;
106 	if (p == NULL)
107 		return;
108 	if ((tmp = (char *)substr(p, "rsize=")))
109 		args->rsize = getdec(&tmp);
110 	if ((tmp = (char *)substr(p, "wsize=")))
111 		args->wsize = getdec(&tmp);
112 	if ((tmp = (char *)substr(p, "intr")))
113 		args->flags |= NFSMNT_INT;
114 	if ((tmp = (char *)substr(p, "soft")))
115 		args->flags |= NFSMNT_SOFT;
116 	if ((tmp = (char *)substr(p, "noconn")))
117 		args->flags |= NFSMNT_NOCONN;
118 	if ((tmp = (char *)substr(p, "tcp")))
119 		args->sotype = SOCK_STREAM;
120 }
121 
122 /*
123  * RPC: mountd/mount
124  * Given a server pathname, get an NFS file handle.
125  * Also, sets sin->sin_port to the NFS service port.
126  */
127 int
128 md_mount(struct sockaddr_in *mdsin,		/* mountd server address */
129 	 char *path,
130 	 u_char *fhp,
131 	 int *fhsizep,
132 	 struct nfs_args *args,
133 	 struct thread *td)
134 {
135 	struct mbuf *m;
136 	int error;
137 	int authunixok;
138 	int authcount;
139 	int authver;
140 
141 #ifdef BOOTP_NFSV3
142 	/* First try NFS v3 */
143 	/* Get port number for MOUNTD. */
144 	error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
145 			     &mdsin->sin_port, td);
146 	if (error == 0) {
147 		m = xdr_string_encode(path, strlen(path));
148 
149 		/* Do RPC to mountd. */
150 		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
151 				  RPCMNT_MOUNT, &m, NULL, td);
152 	}
153 	if (error == 0) {
154 		args->flags |= NFSMNT_NFSV3;
155 	} else {
156 #endif
157 		/* Fallback to NFS v2 */
158 
159 		/* Get port number for MOUNTD. */
160 		error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
161 				     &mdsin->sin_port, td);
162 		if (error != 0)
163 			return error;
164 
165 		m = xdr_string_encode(path, strlen(path));
166 
167 		/* Do RPC to mountd. */
168 		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
169 				  RPCMNT_MOUNT, &m, NULL, td);
170 		if (error != 0)
171 			return error;	/* message already freed */
172 
173 #ifdef BOOTP_NFSV3
174 	}
175 #endif
176 
177 	if (xdr_int_decode(&m, &error) != 0 || error != 0)
178 		goto bad;
179 
180 	if ((args->flags & NFSMNT_NFSV3) != 0) {
181 		if (xdr_int_decode(&m, fhsizep) != 0 ||
182 		    *fhsizep > NFSX_V3FHMAX ||
183 		    *fhsizep <= 0)
184 			goto bad;
185 	} else
186 		*fhsizep = NFSX_V2FH;
187 
188 	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
189 		goto bad;
190 
191 	if (args->flags & NFSMNT_NFSV3) {
192 		if (xdr_int_decode(&m, &authcount) != 0)
193 			goto bad;
194 		authunixok = 0;
195 		if (authcount < 0 || authcount > 100)
196 			goto bad;
197 		while (authcount > 0) {
198 			if (xdr_int_decode(&m, &authver) != 0)
199 				goto bad;
200 			if (authver == RPCAUTH_UNIX)
201 				authunixok = 1;
202 			authcount--;
203 		}
204 		if (authunixok == 0)
205 			goto bad;
206 	}
207 
208 	/* Set port number for NFS use. */
209 	error = krpc_portmap(mdsin, NFS_PROG,
210 			     (args->flags &
211 			      NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
212 			     &mdsin->sin_port, td);
213 
214 	goto out;
215 
216 bad:
217 	error = EBADRPC;
218 
219 out:
220 	m_freem(m);
221 	return error;
222 }
223 
224 int
225 md_lookup_swap(struct sockaddr_in *mdsin,	/* mountd server address */
226 	       char *path,
227 	       u_char *fhp,
228 	       int *fhsizep,
229 	       struct nfs_args *args,
230 	       struct thread *td)
231 {
232 	struct mbuf *m;
233 	int error;
234 	int size = -1;
235 	int attribs_present;
236 	int status;
237 	union {
238 		u_int32_t v2[17];
239 		u_int32_t v3[21];
240 	} fattribs;
241 
242 	m = m_get(MB_WAIT,MT_DATA);
243 	if (m == NULL)
244 	  	return ENOBUFS;
245 
246 	if ((args->flags & NFSMNT_NFSV3) != 0) {
247 		*mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep);
248 		bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep);
249 		m->m_len = *fhsizep + sizeof(u_int32_t);
250 	} else {
251 		bcopy(fhp, mtod(m, u_char *), NFSX_V2FH);
252 		m->m_len = NFSX_V2FH;
253 	}
254 
255 	m->m_next = xdr_string_encode(path, strlen(path));
256 	if (m->m_next == NULL) {
257 		error = ENOBUFS;
258 		goto out;
259 	}
260 
261 	/* Do RPC to nfsd. */
262 	if ((args->flags & NFSMNT_NFSV3) != 0)
263 		error = krpc_call(mdsin, NFS_PROG, NFS_VER3,
264 				  NFSPROC_LOOKUP, &m, NULL, td);
265 	else
266 		error = krpc_call(mdsin, NFS_PROG, NFS_VER2,
267 				  NFSV2PROC_LOOKUP, &m, NULL, td);
268 	if (error != 0)
269 		return error;	/* message already freed */
270 
271 	if (xdr_int_decode(&m, &status) != 0)
272 		goto bad;
273 	if (status != 0) {
274 		error = ENOENT;
275 		goto out;
276 	}
277 
278 	if ((args->flags & NFSMNT_NFSV3) != 0) {
279 		if (xdr_int_decode(&m, fhsizep) != 0 ||
280 		    *fhsizep > NFSX_V3FHMAX ||
281 		    *fhsizep <= 0)
282 			goto bad;
283 	} else
284 		*fhsizep = NFSX_V2FH;
285 
286 	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
287 		goto bad;
288 
289 	if ((args->flags & NFSMNT_NFSV3) != 0) {
290 		if (xdr_int_decode(&m, &attribs_present) != 0)
291 			goto bad;
292 		if (attribs_present != 0) {
293 			if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3,
294 					      sizeof(u_int32_t) * 21) != 0)
295 				goto bad;
296 			size = fxdr_unsigned(u_int32_t, fattribs.v3[6]);
297 		}
298 	} else {
299 		if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2,
300 				      sizeof(u_int32_t) * 17) != 0)
301 			goto bad;
302 		size = fxdr_unsigned(u_int32_t, fattribs.v2[5]);
303 	}
304 
305 	if (nfsv3_diskless.swap_nblks == 0 && size != -1) {
306 		nfsv3_diskless.swap_nblks = size / 1024;
307 		kprintf("md_lookup_swap: Swap size is %d KB\n",
308 		       nfsv3_diskless.swap_nblks);
309 	}
310 
311 	goto out;
312 
313 bad:
314 	error = EBADRPC;
315 
316 out:
317 	m_freem(m);
318 	return error;
319 }
320 
321 int
322 setfs(struct sockaddr_in *addr, char *path, char *p)
323 {
324 	unsigned int ip;
325 	int val;
326 
327 	ip = 0;
328 	if (((val = getdec(&p)) < 0) || (val > 255))
329 		return 0;
330 	ip = val << 24;
331 	if (*p != '.')
332 		return 0;
333 	p++;
334 	if (((val = getdec(&p)) < 0) || (val > 255))
335 		return 0;
336 	ip |= (val << 16);
337 	if (*p != '.')
338 		return 0;
339 	p++;
340 	if (((val = getdec(&p)) < 0) || (val > 255))
341 		return 0;
342 	ip |= (val << 8);
343 	if (*p != '.')
344 		return 0;
345 	p++;
346 	if (((val = getdec(&p)) < 0) || (val > 255))
347 		return 0;
348 	ip |= val;
349 	if (*p != ':')
350 		return 0;
351 	p++;
352 
353 	addr->sin_addr.s_addr = htonl(ip);
354 	addr->sin_len = sizeof(struct sockaddr_in);
355 	addr->sin_family = AF_INET;
356 
357 	strncpy(path, p, MNAMELEN - 1);
358 	return 1;
359 }
360 
361 static int
362 getdec(char **ptr)
363 {
364 	char *p;
365 	int ret;
366 
367 	p = *ptr;
368 	ret = 0;
369 	if ((*p < '0') || (*p > '9'))
370 		return -1;
371 	while ((*p >= '0') && (*p <= '9')) {
372 		ret = ret * 10 + (*p - '0');
373 		p++;
374 	}
375 	*ptr = p;
376 	return ret;
377 }
378 
379 static char *
380 substr(char *a, char *b)
381 {
382 	char *loc1;
383 	char *loc2;
384 
385         while (*a != '\0') {
386                 loc1 = a;
387                 loc2 = b;
388                 while (*loc1 == *loc2++) {
389                         if (*loc1 == '\0')
390 				return 0;
391                         loc1++;
392                         if (*loc2 == '\0')
393 				return loc1;
394                 }
395 		a++;
396         }
397         return 0;
398 }
399 
400 static int
401 xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len)
402 {
403 	struct mbuf *m;
404 	int alignedlen;
405 
406 	m = *mptr;
407 	alignedlen = ( len + 3 ) & ~3;
408 
409 	if (m->m_len < alignedlen) {
410 		m = m_pullup(m, alignedlen);
411 		if (m == NULL) {
412 			*mptr = NULL;
413 			return EBADRPC;
414 		}
415 	}
416 	bcopy(mtod(m, u_char *), buf, len);
417 	m_adj(m, alignedlen);
418 	*mptr = m;
419 	return 0;
420 }
421 
422 static int
423 xdr_int_decode(struct mbuf **mptr, int *iptr)
424 {
425 	u_int32_t i;
426 	if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0)
427 		return EBADRPC;
428 	*iptr = fxdr_unsigned(u_int32_t, i);
429 	return 0;
430 }
431 
432 #endif	/* BOOTP && NFS_ROOT */
433 
434