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
nfs_mountopts(struct nfs_args * args,char * p)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
md_mount(struct sockaddr_in * mdsin,char * path,u_char * fhp,int * fhsizep,struct nfs_args * args,struct thread * td)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
md_lookup_swap(struct sockaddr_in * mdsin,char * path,u_char * fhp,int * fhsizep,struct nfs_args * args,struct thread * td)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
setfs(struct sockaddr_in * addr,char * path,char * p)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
getdec(char ** ptr)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 *
substr(char * a,char * b)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
xdr_opaque_decode(struct mbuf ** mptr,u_char * buf,int len)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
xdr_int_decode(struct mbuf ** mptr,int * iptr)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