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.1 2005/09/04 01:29:00 dillon 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 printf("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