xref: /dragonfly/sys/vfs/nfs/nfs_mountrpc.c (revision b272101acc636ac635f83d03265ef6a44a3ba51a)
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