xref: /dflybsd-src/sys/vfs/nfs/nfs_mountrpc.c (revision 35e996c9207cf8bf5993d3a18eadfa5270c1c560)
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   */
42  /*
43   * Procedures used by NFS_ROOT and BOOTP to do an NFS mount rpc to obtain
44   * the nfs root file handle for a NFS-based root mount point.  This module
45   * is not used by normal operating code because the 'mount' command has a
46   * far more sophisticated implementation.
47   */
48  #include "opt_bootp.h"
49  #include "opt_nfsroot.h"
50  
51  #if defined(BOOTP) || defined(NFS_ROOT)
52  
53  #include <sys/param.h>
54  #include <sys/systm.h>
55  #include <sys/kernel.h>
56  #include <sys/sockio.h>
57  #include <sys/proc.h>
58  #include <sys/malloc.h>
59  #include <sys/mount.h>
60  #include <sys/mbuf.h>
61  #include <sys/socket.h>
62  #include <sys/socketvar.h>
63  #include <sys/sysctl.h>
64  #include <sys/uio.h>
65  
66  #include <net/if.h>
67  #include <net/route.h>
68  
69  #include <netinet/in.h>
70  #include <net/if_types.h>
71  #include <net/if_dl.h>
72  
73  #include "rpcv2.h"
74  #include "nfsproto.h"
75  #include "nfs.h"
76  #include "nfsdiskless.h"
77  #include "krpc.h"
78  #include "xdr_subs.h"
79  #include "nfsmountrpc.h"
80  
81  /*
82   * What is the longest we will wait before re-sending a request?
83   * Note this is also the frequency of "RPC timeout" messages.
84   * The re-send loop count sup linearly to this maximum, so the
85   * first complaint will happen after (1+2+3+4+5)=15 seconds.
86   */
87  
88  static int getdec(char **ptr);
89  static char *substr(char *a,char *b);
90  static int xdr_opaque_decode(struct mbuf **ptr, u_char *buf, int len);
91  static int xdr_int_decode(struct mbuf **ptr, int *iptr);
92  
93  void
94  nfs_mountopts(struct nfs_args *args, char *p)
95  {
96  	char *tmp;
97  
98  	args->version = NFS_ARGSVERSION;
99  	args->rsize = 8192;
100  	args->wsize = 8192;
101  	args->flags = NFSMNT_RSIZE | NFSMNT_WSIZE | NFSMNT_RESVPORT;
102  	args->sotype = SOCK_STREAM;
103  	if (p == NULL)
104  		return;
105  	if ((tmp = substr(p, "rsize=")))
106  		args->rsize = getdec(&tmp);
107  	if ((tmp = substr(p, "wsize=")))
108  		args->wsize = getdec(&tmp);
109  	if ((tmp = substr(p, "intr")))
110  		args->flags |= NFSMNT_INT;
111  	if ((tmp = substr(p, "soft")))
112  		args->flags |= NFSMNT_SOFT;
113  	if ((tmp = substr(p, "noconn")))
114  		args->flags |= NFSMNT_NOCONN;
115  	if ((tmp = substr(p, "udp")))
116  		args->sotype = SOCK_DGRAM;
117  }
118  
119  /*
120   * RPC: mountd/mount
121   * Given a server pathname, get an NFS file handle.
122   * Also, sets sin->sin_port to the NFS service port.
123   */
124  int
125  md_mount(struct sockaddr_in *mdsin,		/* mountd server address */
126  	 char *path,
127  	 u_char *fhp,
128  	 int *fhsizep,
129  	 struct nfs_args *args,
130  	 struct thread *td)
131  {
132  	struct mbuf *m;
133  	int error;
134  	int authunixok;
135  	int authcount;
136  	int authver;
137  
138  	/* First try NFS v3 */
139  	/* Get port number for MOUNTD. */
140  	error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER3,
141  			     &mdsin->sin_port, td);
142  	if (error == 0) {
143  		m = xdr_string_encode(path, strlen(path));
144  
145  		/* Do RPC to mountd. */
146  		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER3,
147  				  RPCMNT_MOUNT, &m, NULL, td);
148  	}
149  	if (error == 0) {
150  		args->flags |= NFSMNT_NFSV3;
151  	} else {
152  		/* Fallback to NFS v2 */
153  
154  		/* Get port number for MOUNTD. */
155  		error = krpc_portmap(mdsin, RPCPROG_MNT, RPCMNT_VER1,
156  				     &mdsin->sin_port, td);
157  		if (error != 0)
158  			return error;
159  
160  		m = xdr_string_encode(path, strlen(path));
161  
162  		/* Do RPC to mountd. */
163  		error = krpc_call(mdsin, RPCPROG_MNT, RPCMNT_VER1,
164  				  RPCMNT_MOUNT, &m, NULL, td);
165  		if (error != 0)
166  			return error;	/* message already freed */
167  		args->flags &= ~NFSMNT_NFSV3;
168  	}
169  
170  	if (xdr_int_decode(&m, &error) != 0 || error != 0)
171  		goto bad;
172  
173  	if ((args->flags & NFSMNT_NFSV3) != 0) {
174  		if (xdr_int_decode(&m, fhsizep) != 0 ||
175  		    *fhsizep > NFSX_V3FHMAX ||
176  		    *fhsizep <= 0)
177  			goto bad;
178  	} else
179  		*fhsizep = NFSX_V2FH;
180  
181  	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
182  		goto bad;
183  
184  	if (args->flags & NFSMNT_NFSV3) {
185  		if (xdr_int_decode(&m, &authcount) != 0)
186  			goto bad;
187  		authunixok = 0;
188  		if (authcount < 0 || authcount > 100)
189  			goto bad;
190  		while (authcount > 0) {
191  			if (xdr_int_decode(&m, &authver) != 0)
192  				goto bad;
193  			if (authver == RPCAUTH_UNIX)
194  				authunixok = 1;
195  			authcount--;
196  		}
197  		if (authunixok == 0)
198  			goto bad;
199  	}
200  
201  	/* Set port number for NFS use. */
202  	error = krpc_portmap(mdsin, NFS_PROG,
203  			     (args->flags &
204  			      NFSMNT_NFSV3) ? NFS_VER3 : NFS_VER2,
205  			     &mdsin->sin_port, td);
206  
207  	goto out;
208  
209  bad:
210  	error = EBADRPC;
211  
212  out:
213  	m_freem(m);
214  	return error;
215  }
216  
217  int
218  md_lookup_swap(struct sockaddr_in *mdsin,	/* mountd server address */
219  	       char *path,
220  	       u_char *fhp,
221  	       int *fhsizep,
222  	       struct nfs_args *args,
223  	       struct thread *td)
224  {
225  	struct mbuf *m;
226  	int error;
227  	int size = -1;
228  	int attribs_present;
229  	int status;
230  	union {
231  		u_int32_t v2[17];
232  		u_int32_t v3[21];
233  	} fattribs;
234  
235  	m = m_get(M_WAITOK, MT_DATA);
236  	if ((args->flags & NFSMNT_NFSV3) != 0) {
237  		*mtod(m, u_int32_t *) = txdr_unsigned(*fhsizep);
238  		bcopy(fhp, mtod(m, u_char *) + sizeof(u_int32_t), *fhsizep);
239  		m->m_len = *fhsizep + sizeof(u_int32_t);
240  	} else {
241  		bcopy(fhp, mtod(m, u_char *), NFSX_V2FH);
242  		m->m_len = NFSX_V2FH;
243  	}
244  
245  	m->m_next = xdr_string_encode(path, strlen(path));
246  	if (m->m_next == NULL) {
247  		error = ENOBUFS;
248  		goto out;
249  	}
250  
251  	/* Do RPC to nfsd. */
252  	if ((args->flags & NFSMNT_NFSV3) != 0)
253  		error = krpc_call(mdsin, NFS_PROG, NFS_VER3,
254  				  NFSPROC_LOOKUP, &m, NULL, td);
255  	else
256  		error = krpc_call(mdsin, NFS_PROG, NFS_VER2,
257  				  NFSV2PROC_LOOKUP, &m, NULL, td);
258  	if (error != 0)
259  		return error;	/* message already freed */
260  
261  	if (xdr_int_decode(&m, &status) != 0)
262  		goto bad;
263  	if (status != 0) {
264  		error = ENOENT;
265  		goto out;
266  	}
267  
268  	if ((args->flags & NFSMNT_NFSV3) != 0) {
269  		if (xdr_int_decode(&m, fhsizep) != 0 ||
270  		    *fhsizep > NFSX_V3FHMAX ||
271  		    *fhsizep <= 0)
272  			goto bad;
273  	} else
274  		*fhsizep = NFSX_V2FH;
275  
276  	if (xdr_opaque_decode(&m, fhp, *fhsizep) != 0)
277  		goto bad;
278  
279  	if ((args->flags & NFSMNT_NFSV3) != 0) {
280  		if (xdr_int_decode(&m, &attribs_present) != 0)
281  			goto bad;
282  		if (attribs_present != 0) {
283  			if (xdr_opaque_decode(&m, (u_char *) &fattribs.v3,
284  					      sizeof(u_int32_t) * 21) != 0)
285  				goto bad;
286  			size = fxdr_unsigned(u_int32_t, fattribs.v3[6]);
287  		}
288  	} else {
289  		if (xdr_opaque_decode(&m,(u_char *) &fattribs.v2,
290  				      sizeof(u_int32_t) * 17) != 0)
291  			goto bad;
292  		size = fxdr_unsigned(u_int32_t, fattribs.v2[5]);
293  	}
294  
295  	if (nfsv3_diskless.swap_nblks == 0 && size != -1) {
296  		nfsv3_diskless.swap_nblks = size / 1024;
297  		kprintf("md_lookup_swap: Swap size is %d KB\n",
298  		       nfsv3_diskless.swap_nblks);
299  	}
300  
301  	goto out;
302  
303  bad:
304  	error = EBADRPC;
305  
306  out:
307  	m_freem(m);
308  	return error;
309  }
310  
311  int
312  setfs(struct sockaddr_in *addr, char *path, char *p)
313  {
314  	unsigned int ip;
315  	int val;
316  
317  	ip = 0;
318  	if (((val = getdec(&p)) < 0) || (val > 255))
319  		return 0;
320  	ip = val << 24;
321  	if (*p != '.')
322  		return 0;
323  	p++;
324  	if (((val = getdec(&p)) < 0) || (val > 255))
325  		return 0;
326  	ip |= (val << 16);
327  	if (*p != '.')
328  		return 0;
329  	p++;
330  	if (((val = getdec(&p)) < 0) || (val > 255))
331  		return 0;
332  	ip |= (val << 8);
333  	if (*p != '.')
334  		return 0;
335  	p++;
336  	if (((val = getdec(&p)) < 0) || (val > 255))
337  		return 0;
338  	ip |= val;
339  	if (*p != ':')
340  		return 0;
341  	p++;
342  
343  	addr->sin_addr.s_addr = htonl(ip);
344  	addr->sin_len = sizeof(struct sockaddr_in);
345  	addr->sin_family = AF_INET;
346  
347  	strncpy(path, p, MNAMELEN - 1);
348  	return 1;
349  }
350  
351  static int
352  getdec(char **ptr)
353  {
354  	char *p;
355  	int ret;
356  
357  	p = *ptr;
358  	ret = 0;
359  	if ((*p < '0') || (*p > '9'))
360  		return -1;
361  	while ((*p >= '0') && (*p <= '9')) {
362  		ret = ret * 10 + (*p - '0');
363  		p++;
364  	}
365  	*ptr = p;
366  	return ret;
367  }
368  
369  static char *
370  substr(char *a, char *b)
371  {
372  	char *loc1;
373  	char *loc2;
374  
375          while (*a != '\0') {
376                  loc1 = a;
377                  loc2 = b;
378                  while (*loc1 == *loc2++) {
379                          if (*loc1 == '\0')
380  				return 0;
381                          loc1++;
382                          if (*loc2 == '\0')
383  				return loc1;
384                  }
385  		a++;
386          }
387          return 0;
388  }
389  
390  static int
391  xdr_opaque_decode(struct mbuf **mptr, u_char *buf, int len)
392  {
393  	struct mbuf *m;
394  	int alignedlen;
395  
396  	m = *mptr;
397  	alignedlen = ( len + 3 ) & ~3;
398  
399  	if (m->m_len < alignedlen) {
400  		m = m_pullup(m, alignedlen);
401  		if (m == NULL) {
402  			*mptr = NULL;
403  			return EBADRPC;
404  		}
405  	}
406  	bcopy(mtod(m, u_char *), buf, len);
407  	m_adj(m, alignedlen);
408  	*mptr = m;
409  	return 0;
410  }
411  
412  static int
413  xdr_int_decode(struct mbuf **mptr, int *iptr)
414  {
415  	u_int32_t i;
416  	if (xdr_opaque_decode(mptr, (u_char *) &i, sizeof(u_int32_t)) != 0)
417  		return EBADRPC;
418  	*iptr = fxdr_unsigned(u_int32_t, i);
419  	return 0;
420  }
421  
422  #endif	/* BOOTP && NFS_ROOT */
423  
424