1 /* $OpenBSD: nfs_srvsubs.c,v 1.2 2024/09/18 05:21:19 jsg Exp $ */ 2 /* $NetBSD: nfs_subs.c,v 1.27.4.3 1996/07/08 20:34:24 jtc Exp $ */ 3 4 /* 5 * Copyright (c) 1989, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Rick Macklem at The University of Guelph. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * @(#)nfs_subs.c 8.8 (Berkeley) 5/22/95 36 */ 37 38 39 /* 40 * These functions support the nfsm_subs.h inline functions and help fiddle 41 * mbuf chains for the nfs op functions. They do things such as creating the 42 * rpc header and copying data between mbuf chains and uio lists. 43 */ 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/mount.h> 47 #include <sys/vnode.h> 48 #include <sys/namei.h> 49 #include <sys/mbuf.h> 50 #include <sys/socket.h> 51 #include <sys/socketvar.h> 52 #include <sys/pool.h> 53 54 #include <nfs/rpcv2.h> 55 #include <nfs/nfsproto.h> 56 #include <nfs/nfs.h> 57 #include <nfs/xdr_subs.h> 58 #include <nfs/nfs_var.h> 59 #include <nfs/nfsm_subs.h> 60 61 #include <netinet/in.h> 62 63 /* Global vars */ 64 extern u_int32_t nfs_false, nfs_true; 65 extern const nfstype nfsv2_type[9]; 66 extern const nfstype nfsv3_type[9]; 67 68 /* 69 * Set up nameidata for a lookup() call and do it 70 */ 71 int 72 nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, 73 struct nfssvc_sock *slp, struct mbuf *nam, struct mbuf **mdp, 74 caddr_t *dposp, struct vnode **retdirp, struct proc *p) 75 { 76 int i, rem; 77 struct mbuf *md; 78 char *fromcp, *tocp; 79 struct vnode *dp; 80 int error, rdonly; 81 struct componentname *cnp = &ndp->ni_cnd; 82 83 *retdirp = NULL; 84 cnp->cn_pnbuf = pool_get(&namei_pool, PR_WAITOK); 85 /* 86 * Copy the name from the mbuf list to ndp->ni_pnbuf 87 * and set the various ndp fields appropriately. 88 */ 89 fromcp = *dposp; 90 tocp = cnp->cn_pnbuf; 91 md = *mdp; 92 rem = mtod(md, caddr_t) + md->m_len - fromcp; 93 for (i = 0; i < len; i++) { 94 while (rem == 0) { 95 md = md->m_next; 96 if (md == NULL) { 97 error = EBADRPC; 98 goto out; 99 } 100 fromcp = mtod(md, caddr_t); 101 rem = md->m_len; 102 } 103 if (*fromcp == '\0' || *fromcp == '/') { 104 error = EACCES; 105 goto out; 106 } 107 *tocp++ = *fromcp++; 108 rem--; 109 } 110 *tocp = '\0'; 111 *mdp = md; 112 *dposp = fromcp; 113 len = nfsm_padlen(len); 114 if (len > 0) { 115 if (rem >= len) 116 *dposp += len; 117 else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) 118 goto out; 119 } 120 ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 121 cnp->cn_nameptr = cnp->cn_pnbuf; 122 /* 123 * Extract and set starting directory. 124 */ 125 error = nfsrv_fhtovp(fhp, 0, &dp, ndp->ni_cnd.cn_cred, slp, 126 nam, &rdonly); 127 if (error) 128 goto out; 129 if (dp->v_type != VDIR) { 130 vrele(dp); 131 error = ENOTDIR; 132 goto out; 133 } 134 vref(dp); 135 *retdirp = dp; 136 ndp->ni_startdir = dp; 137 if (rdonly) 138 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 139 else 140 cnp->cn_flags |= NOCROSSMOUNT; 141 142 /* 143 * And call lookup() to do the real work 144 */ 145 cnp->cn_proc = p; 146 error = vfs_lookup(ndp); 147 if (error) 148 goto out; 149 /* 150 * Check for encountering a symbolic link 151 */ 152 if (cnp->cn_flags & ISSYMLINK) { 153 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 154 vput(ndp->ni_dvp); 155 else 156 vrele(ndp->ni_dvp); 157 vput(ndp->ni_vp); 158 ndp->ni_vp = NULL; 159 error = EINVAL; 160 goto out; 161 } 162 /* 163 * Check for saved name request 164 */ 165 if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 166 cnp->cn_flags |= HASBUF; 167 return (0); 168 } 169 out: 170 pool_put(&namei_pool, cnp->cn_pnbuf); 171 return (error); 172 } 173 174 /* 175 * A fiddled version of m_adj() that ensures null fill to a long 176 * boundary and only trims off the back end 177 */ 178 void 179 nfsm_adj(struct mbuf *mp, int len, int nul) 180 { 181 struct mbuf *m; 182 int count, i; 183 char *cp; 184 185 /* 186 * Trim from tail. Scan the mbuf chain, 187 * calculating its length and finding the last mbuf. 188 * If the adjustment only affects this mbuf, then just 189 * adjust and return. Otherwise, rescan and truncate 190 * after the remaining size. 191 */ 192 count = 0; 193 m = mp; 194 for (;;) { 195 count += m->m_len; 196 if (m->m_next == NULL) 197 break; 198 m = m->m_next; 199 } 200 if (m->m_len > len) { 201 m->m_len -= len; 202 if (nul > 0) { 203 cp = mtod(m, caddr_t)+m->m_len-nul; 204 for (i = 0; i < nul; i++) 205 *cp++ = '\0'; 206 } 207 return; 208 } 209 count -= len; 210 if (count < 0) 211 count = 0; 212 /* 213 * Correct length for chain is "count". 214 * Find the mbuf with last data, adjust its length, 215 * and toss data from remaining mbufs on chain. 216 */ 217 for (m = mp; m; m = m->m_next) { 218 if (m->m_len >= count) { 219 m->m_len = count; 220 if (nul > 0) { 221 cp = mtod(m, caddr_t)+m->m_len-nul; 222 for (i = 0; i < nul; i++) 223 *cp++ = '\0'; 224 } 225 break; 226 } 227 count -= m->m_len; 228 } 229 for (m = m->m_next;m;m = m->m_next) 230 m->m_len = 0; 231 } 232 233 /* 234 * Make these non-inline functions, so that the kernel text size 235 * doesn't get too big... 236 */ 237 void 238 nfsm_srvwcc(struct nfsrv_descript *nfsd, int before_ret, 239 struct vattr *before_vap, int after_ret, struct vattr *after_vap, 240 struct nfsm_info *info) 241 { 242 u_int32_t *tl; 243 244 if (before_ret) { 245 tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED); 246 *tl = nfs_false; 247 } else { 248 tl = nfsm_build(&info->nmi_mb, 7 * NFSX_UNSIGNED); 249 *tl++ = nfs_true; 250 txdr_hyper(before_vap->va_size, tl); 251 tl += 2; 252 txdr_nfsv3time(&(before_vap->va_mtime), tl); 253 tl += 2; 254 txdr_nfsv3time(&(before_vap->va_ctime), tl); 255 } 256 nfsm_srvpostop_attr(nfsd, after_ret, after_vap, info); 257 } 258 259 void 260 nfsm_srvpostop_attr(struct nfsrv_descript *nfsd, int after_ret, 261 struct vattr *after_vap, struct nfsm_info *info) 262 { 263 u_int32_t *tl; 264 struct nfs_fattr *fp; 265 266 if (after_ret) { 267 tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED); 268 *tl = nfs_false; 269 } else { 270 tl = nfsm_build(&info->nmi_mb, NFSX_UNSIGNED + NFSX_V3FATTR); 271 *tl++ = nfs_true; 272 fp = (struct nfs_fattr *)tl; 273 nfsm_srvfattr(nfsd, after_vap, fp); 274 } 275 } 276 277 void 278 nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, 279 struct nfs_fattr *fp) 280 { 281 282 fp->fa_nlink = txdr_unsigned(vap->va_nlink); 283 fp->fa_uid = txdr_unsigned(vap->va_uid); 284 fp->fa_gid = txdr_unsigned(vap->va_gid); 285 if (nfsd->nd_flag & ND_NFSV3) { 286 fp->fa_type = vtonfsv3_type(vap->va_type); 287 fp->fa_mode = vtonfsv3_mode(vap->va_mode); 288 txdr_hyper(vap->va_size, &fp->fa3_size); 289 txdr_hyper(vap->va_bytes, &fp->fa3_used); 290 fp->fa3_rdev.specdata1 = txdr_unsigned(major(vap->va_rdev)); 291 fp->fa3_rdev.specdata2 = txdr_unsigned(minor(vap->va_rdev)); 292 fp->fa3_fsid.nfsuquad[0] = 0; 293 fp->fa3_fsid.nfsuquad[1] = txdr_unsigned(vap->va_fsid); 294 txdr_hyper(vap->va_fileid, &fp->fa3_fileid); 295 txdr_nfsv3time(&vap->va_atime, &fp->fa3_atime); 296 txdr_nfsv3time(&vap->va_mtime, &fp->fa3_mtime); 297 txdr_nfsv3time(&vap->va_ctime, &fp->fa3_ctime); 298 } else { 299 fp->fa_type = vtonfsv2_type(vap->va_type); 300 fp->fa_mode = vtonfsv2_mode(vap->va_type, vap->va_mode); 301 fp->fa2_size = txdr_unsigned(vap->va_size); 302 fp->fa2_blocksize = txdr_unsigned(vap->va_blocksize); 303 if (vap->va_type == VFIFO) 304 fp->fa2_rdev = 0xffffffff; 305 else 306 fp->fa2_rdev = txdr_unsigned(vap->va_rdev); 307 fp->fa2_blocks = txdr_unsigned(vap->va_bytes / NFS_FABLKSIZE); 308 fp->fa2_fsid = txdr_unsigned(vap->va_fsid); 309 fp->fa2_fileid = txdr_unsigned((u_int32_t)vap->va_fileid); 310 txdr_nfsv2time(&vap->va_atime, &fp->fa2_atime); 311 txdr_nfsv2time(&vap->va_mtime, &fp->fa2_mtime); 312 txdr_nfsv2time(&vap->va_ctime, &fp->fa2_ctime); 313 } 314 } 315 316 /* 317 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 318 * - look up fsid in mount list (if not found ret error) 319 * - get vp and export rights by calling VFS_FHTOVP() and VFS_CHECKEXP() 320 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 321 * - if not lockflag unlock it with VOP_UNLOCK() 322 */ 323 int 324 nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, 325 struct ucred *cred, struct nfssvc_sock *slp, struct mbuf *nam, 326 int *rdonlyp) 327 { 328 struct mount *mp; 329 int i; 330 struct ucred *credanon; 331 int error, exflags; 332 struct sockaddr_in *saddr; 333 334 *vpp = NULL; 335 mp = vfs_getvfs(&fhp->fh_fsid); 336 337 if (!mp) 338 return (ESTALE); 339 error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); 340 if (error) 341 return (error); 342 error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp); 343 if (error) 344 return (error); 345 346 saddr = mtod(nam, struct sockaddr_in *); 347 if (saddr->sin_family == AF_INET && 348 (ntohs(saddr->sin_port) >= IPPORT_RESERVED || 349 (slp->ns_so->so_type == SOCK_STREAM && ntohs(saddr->sin_port) == 20))) { 350 vput(*vpp); 351 return (NFSERR_AUTHERR | AUTH_TOOWEAK); 352 } 353 354 /* Check/setup credentials. */ 355 if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 356 cred->cr_uid = credanon->cr_uid; 357 cred->cr_gid = credanon->cr_gid; 358 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS_MAX; i++) 359 cred->cr_groups[i] = credanon->cr_groups[i]; 360 cred->cr_ngroups = i; 361 } 362 if (exflags & MNT_EXRDONLY) 363 *rdonlyp = 1; 364 else 365 *rdonlyp = 0; 366 if (!lockflag) 367 VOP_UNLOCK(*vpp); 368 369 return (0); 370 } 371 372 /* 373 * This function compares two net addresses by family and returns non zero 374 * if they are the same host, or if there is any doubt it returns 0. 375 * The AF_INET family is handled as a special case so that address mbufs 376 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 377 */ 378 int 379 netaddr_match(int family, union nethostaddr *haddr, struct mbuf *nam) 380 { 381 struct sockaddr_in *inetaddr; 382 383 switch (family) { 384 case AF_INET: 385 inetaddr = mtod(nam, struct sockaddr_in *); 386 if (inetaddr->sin_family == AF_INET && 387 inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 388 return (1); 389 break; 390 default: 391 break; 392 } 393 return (0); 394 } 395 396 int 397 nfsm_srvsattr(struct mbuf **mp, struct vattr *va, struct mbuf *mrep, 398 caddr_t *dposp) 399 { 400 struct nfsm_info info; 401 int error = 0; 402 uint32_t *tl; 403 404 info.nmi_md = *mp; 405 info.nmi_dpos = *dposp; 406 info.nmi_mrep = mrep; 407 info.nmi_errorp = &error; 408 409 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 410 if (tl == NULL) 411 return error; 412 if (*tl == nfs_true) { 413 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 414 if (tl == NULL) 415 return error; 416 va->va_mode = nfstov_mode(*tl); 417 } 418 419 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 420 if (tl == NULL) 421 return error; 422 if (*tl == nfs_true) { 423 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 424 if (tl == NULL) 425 return error; 426 va->va_uid = fxdr_unsigned(uid_t, *tl); 427 } 428 429 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 430 if (tl == NULL) 431 return error; 432 if (*tl == nfs_true) { 433 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 434 if (tl == NULL) 435 return error; 436 va->va_gid = fxdr_unsigned(gid_t, *tl); 437 } 438 439 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 440 if (tl == NULL) 441 return error; 442 if (*tl == nfs_true) { 443 tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED); 444 if (tl == NULL) 445 return error; 446 va->va_size = fxdr_hyper(tl); 447 } 448 449 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 450 if (tl == NULL) 451 return error; 452 switch (fxdr_unsigned(int, *tl)) { 453 case NFSV3SATTRTIME_TOCLIENT: 454 va->va_vaflags |= VA_UTIMES_CHANGE; 455 va->va_vaflags &= ~VA_UTIMES_NULL; 456 tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED); 457 if (tl == NULL) 458 return error; 459 fxdr_nfsv3time(tl, &va->va_atime); 460 break; 461 case NFSV3SATTRTIME_TOSERVER: 462 va->va_vaflags |= VA_UTIMES_CHANGE; 463 getnanotime(&va->va_atime); 464 break; 465 } 466 467 tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED); 468 if (tl == NULL) 469 return error; 470 switch (fxdr_unsigned(int, *tl)) { 471 case NFSV3SATTRTIME_TOCLIENT: 472 va->va_vaflags |= VA_UTIMES_CHANGE; 473 va->va_vaflags &= ~VA_UTIMES_NULL; 474 tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED); 475 if (tl == NULL) 476 return error; 477 fxdr_nfsv3time(tl, &va->va_mtime); 478 break; 479 case NFSV3SATTRTIME_TOSERVER: 480 va->va_vaflags |= VA_UTIMES_CHANGE; 481 getnanotime(&va->va_mtime); 482 break; 483 } 484 485 *dposp = info.nmi_dpos; 486 *mp = info.nmi_md; 487 return 0; 488 } 489