X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/b0d623f7f2ae71ed96e60569f61f9a9a27016e80..ea3f04195ba4a5034c9c8e9b726d4f7ce96f1832:/bsd/nfs/krpc_subr.c diff --git a/bsd/nfs/krpc_subr.c b/bsd/nfs/krpc_subr.c index 8ded0f04b..345762a0b 100644 --- a/bsd/nfs/krpc_subr.c +++ b/bsd/nfs/krpc_subr.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2000-2008 Apple Inc. All rights reserved. + * Copyright (c) 2000-2016 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,12 +22,12 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ /* - * Copyright (c) 1994 Gordon Ross, Adam Glass + * Copyright (c) 1994 Gordon Ross, Adam Glass * Copyright (c) 1992 Regents of the University of California. * All rights reserved. * @@ -65,6 +65,9 @@ * */ +#include +#if CONFIG_NFS_CLIENT + #include #include #include @@ -87,7 +90,7 @@ * Kernel support for Sun RPC * * Used currently for bootstrapping in nfs diskless configurations. - * + * * Note: will not work on variable-sized rpc args/results. * implicit size-limit of an mbuf. */ @@ -97,35 +100,36 @@ */ struct auth_info { - u_int32_t rp_atype; /* auth type */ - u_int32_t rp_alen; /* auth length */ + u_int32_t rp_atype; /* auth type */ + u_int32_t rp_alen; /* auth length */ }; struct rpc_call { - u_int32_t rp_xid; /* request transaction id */ - int32_t rp_direction; /* call direction (0) */ - u_int32_t rp_rpcvers; /* rpc version (2) */ - u_int32_t rp_prog; /* program */ - u_int32_t rp_vers; /* version */ - u_int32_t rp_proc; /* procedure */ - struct auth_info rp_auth; - struct auth_info rp_verf; + u_int32_t rp_xid; /* request transaction id */ + int32_t rp_direction; /* call direction (0) */ + u_int32_t rp_rpcvers; /* rpc version (2) */ + u_int32_t rp_prog; /* program */ + u_int32_t rp_vers; /* version */ + u_int32_t rp_proc; /* procedure */ + struct auth_info rp_auth; + struct auth_info rp_verf; }; struct rpc_reply { - u_int32_t rp_xid; /* request transaction id */ - int32_t rp_direction; /* call direction (1) */ - int32_t rp_astatus; /* accept status (0: accepted) */ + u_int32_t rp_xid; /* request transaction id */ + int32_t rp_direction; /* call direction (1) */ + int32_t rp_astatus; /* accept status (0: accepted) */ union { u_int32_t rpu_errno; struct { struct auth_info rp_auth; - u_int32_t rp_rstatus; + u_int32_t rp_rstatus; } rpu_ok; } rp_u; }; -#define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */ +#define MIN_REPLY_HDR 16 /* xid, dir, astat, errno */ +#define REPLY_SIZE 24 /* xid, dir, astat, rpu_ok */ /* * What is the longest we will wait before re-sending a request? @@ -133,7 +137,7 @@ struct rpc_reply { * The re-send loop count sup linearly to this maximum, so the * first complaint will happen after (1+2+3+4+5)=15 seconds. */ -#define MAX_RESEND_DELAY 5 /* seconds */ +#define MAX_RESEND_DELAY 5 /* seconds */ /* copied over from nfs_boot.c for printf format. could put in .h file... */ #define IP_FORMAT "%d.%d.%d.%d" @@ -146,16 +150,16 @@ struct rpc_reply { * Returns non-zero error on failure. */ int -krpc_portmap(sin, prog, vers, proto, portp) - struct sockaddr_in *sin; /* server address */ - u_int prog, vers, proto; /* host order */ - u_int16_t *portp; /* network order */ +krpc_portmap( + struct sockaddr_in *sin, /* server address */ + u_int prog, u_int vers, u_int proto, /* host order */ + u_int16_t *portp) /* network order */ { struct sdata { - u_int32_t prog; /* call program */ - u_int32_t vers; /* call version */ - u_int32_t proto; /* call protocol */ - u_int32_t port; /* call port (unused) */ + u_int32_t prog; /* call program */ + u_int32_t vers; /* call version */ + u_int32_t proto; /* call protocol */ + u_int32_t port; /* call port (unused) */ } *sdata; struct rdata { u_int16_t pad; @@ -171,8 +175,9 @@ krpc_portmap(sin, prog, vers, proto, portp) } error = mbuf_gethdr(MBUF_WAITOK, MBUF_TYPE_DATA, &m); - if (error) + if (error) { return error; + } mbuf_setlen(m, sizeof(*sdata)); mbuf_pkthdr_setlen(m, sizeof(*sdata)); sdata = mbuf_data(m); @@ -185,17 +190,22 @@ krpc_portmap(sin, prog, vers, proto, portp) sin->sin_port = htons(PMAPPORT); error = krpc_call(sin, SOCK_DGRAM, PMAPPROG, PMAPVERS, PMAPPROC_GETPORT, &m, NULL); - if (error) + if (error) { return error; + } rdata = mbuf_data(m); - *portp = rdata->port; - if (!rdata->port) + if (mbuf_len(m) >= sizeof(*rdata)) { + *portp = rdata->port; + } + + if (mbuf_len(m) < sizeof(*rdata) || !rdata->port) { error = EPROGUNAVAIL; + } mbuf_freem(m); - return (error); + return error; } /* @@ -204,11 +214,11 @@ krpc_portmap(sin, prog, vers, proto, portp) * the address from whence the response came is saved there. */ int -krpc_call(sa, sotype, prog, vers, func, data, from_p) - struct sockaddr_in *sa; - u_int sotype, prog, vers, func; - mbuf_t *data; /* input/output */ - struct sockaddr_in *from_p; /* output */ +krpc_call( + struct sockaddr_in *sa, + u_int sotype, u_int prog, u_int vers, u_int func, + mbuf_t *data, /* input/output */ + struct sockaddr_in *from_p) /* output */ { socket_t so; struct sockaddr_in *sin; @@ -219,14 +229,15 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) size_t len; static u_int32_t xid = ~0xFF; u_int16_t tport; - size_t maxpacket = 1<<16; + size_t maxpacket = 1 << 16; /* * Validate address family. * Sorry, this is INET specific... */ - if (sa->sin_family != AF_INET) - return (EAFNOSUPPORT); + if (sa->sin_family != AF_INET) { + return EAFNOSUPPORT; + } /* Free at end if not null. */ nam = mhead = NULL; @@ -234,8 +245,9 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) /* * Create socket and set its recieve timeout. */ - if ((error = sock_socket(AF_INET, sotype, 0, 0, 0, &so))) + if ((error = sock_socket(AF_INET, sotype, 0, 0, 0, &so))) { goto out1; + } { struct timeval tv; @@ -243,9 +255,9 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) tv.tv_sec = 1; tv.tv_usec = 0; - if ((error = sock_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))) - goto out; - + if ((error = sock_setsockopt(so, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)))) { + goto out; + } } /* @@ -254,8 +266,9 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) if (from_p && (sotype == SOCK_DGRAM)) { int on = 1; - if ((error = sock_setsockopt(so, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)))) + if ((error = sock_setsockopt(so, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)))) { goto out; + } } /* @@ -263,8 +276,9 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) * because some NFS servers refuse requests from * non-reserved (non-privileged) ports. */ - if ((error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_SONAME, &m))) + if ((error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_SONAME, &m))) { goto out; + } sin = mbuf_data(m); bzero(sin, sizeof(*sin)); mbuf_setlen(m, sizeof(*sin)); @@ -277,7 +291,7 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) sin->sin_port = htons(tport); error = sock_bind(so, (struct sockaddr*)sin); } while (error == EADDRINUSE && - tport > IPPORT_RESERVED / 2); + tport > IPPORT_RESERVED / 2); mbuf_freem(m); m = NULL; if (error) { @@ -288,8 +302,9 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) /* * Setup socket address for the server. */ - if ((error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_SONAME, &nam))) + if ((error = mbuf_get(MBUF_WAITOK, MBUF_TYPE_SONAME, &nam))) { goto out; + } sin = mbuf_data(nam); mbuf_setlen(nam, sa->sin_len); bcopy((caddr_t)sa, (caddr_t)sin, sa->sin_len); @@ -299,12 +314,14 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) tv.tv_sec = 60; tv.tv_usec = 0; error = sock_connect(so, mbuf_data(nam), MSG_DONTWAIT); - if (error && (error != EINPROGRESS)) + if (error && (error != EINPROGRESS)) { goto out; + } error = sock_connectwait(so, &tv); if (error) { - if (error == EINPROGRESS) + if (error == EINPROGRESS) { error = ETIMEDOUT; + } printf("krpc_call: error waiting for TCP socket connect: %d\n", error); goto out; } @@ -315,20 +332,25 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) */ m = *data; *data = NULL; -#if DIAGNOSTIC - if ((mbuf_flags(m) & MBUF_PKTHDR) == 0) +#if DIAGNOSTIC + if ((mbuf_flags(m) & MBUF_PKTHDR) == 0) { panic("krpc_call: send data w/o pkthdr"); - if (mbuf_pkthdr_len(m) < mbuf_len(m)) + } + if (mbuf_pkthdr_len(m) < mbuf_len(m)) { panic("krpc_call: pkthdr.len not set"); + } #endif len = sizeof(*call); - if (sotype == SOCK_STREAM) + if (sotype == SOCK_STREAM) { len += 4; /* account for RPC record marker */ + } mhead = m; - if ((error = mbuf_prepend(&mhead, len, MBUF_WAITOK))) + if ((error = mbuf_prepend(&mhead, len, MBUF_WAITOK))) { goto out; - if ((error = mbuf_pkthdr_setrcvif(mhead, NULL))) + } + if ((error = mbuf_pkthdr_setrcvif(mhead, NULL))) { goto out; + } /* * Fill in the RPC header @@ -360,10 +382,11 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) timo = 0; for (;;) { struct msghdr msg; - + /* Send RPC request (or re-send). */ - if ((error = mbuf_copym(mhead, 0, MBUF_COPYALL, MBUF_WAITOK, &m))) + if ((error = mbuf_copym(mhead, 0, MBUF_COPYALL, MBUF_WAITOK, &m))) { goto out; + } bzero(&msg, sizeof(msg)); if (sotype == SOCK_STREAM) { msg.msg_name = NULL; @@ -380,11 +403,12 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) m = NULL; /* Determine new timeout. */ - if (timo < MAX_RESEND_DELAY) + if (timo < MAX_RESEND_DELAY) { timo++; - else - printf("RPC timeout for server " IP_FORMAT "\n", - IP_LIST(&(sin->sin_addr.s_addr))); + } else { + printf("RPC timeout for server " IP_FORMAT "\n", + IP_LIST(&(sin->sin_addr.s_addr))); + } /* * Wait for up to timo seconds for a reply. @@ -393,7 +417,7 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) secs = timo; while (secs > 0) { size_t readlen; - + if (m) { mbuf_freem(m); m = NULL; @@ -407,40 +431,43 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) msg.msg_iov = &aio; msg.msg_iovlen = 1; do { - error = sock_receive(so, &msg, MSG_WAITALL, &readlen); - if ((error == EWOULDBLOCK) && (--maxretries <= 0)) - error = ETIMEDOUT; + error = sock_receive(so, &msg, MSG_WAITALL, &readlen); + if ((error == EWOULDBLOCK) && (--maxretries <= 0)) { + error = ETIMEDOUT; + } } while (error == EWOULDBLOCK); if (!error && readlen < aio.iov_len) { - /* only log a message if we got a partial word */ - if (readlen != 0) - printf("short receive (%ld/%ld) from server " IP_FORMAT "\n", - readlen, sizeof(u_int32_t), IP_LIST(&(sin->sin_addr.s_addr))); - error = EPIPE; + /* only log a message if we got a partial word */ + if (readlen != 0) { + printf("short receive (%ld/%ld) from server " IP_FORMAT "\n", + readlen, sizeof(u_int32_t), IP_LIST(&(sin->sin_addr.s_addr))); + } + error = EPIPE; } - if (error) + if (error) { goto out; + } len = ntohl(len) & ~0x80000000; /* * This is SERIOUS! We are out of sync with the sender * and forcing a disconnect/reconnect is all I can do. */ if (len > maxpacket) { - printf("impossible packet length (%ld) from server " IP_FORMAT "\n", - len, IP_LIST(&(sin->sin_addr.s_addr))); - error = EFBIG; - goto out; + printf("impossible packet length (%ld) from server " IP_FORMAT "\n", + len, IP_LIST(&(sin->sin_addr.s_addr))); + error = EFBIG; + goto out; } - + do { - readlen = len; - error = sock_receivembuf(so, NULL, &m, MSG_WAITALL, &readlen); + readlen = len; + error = sock_receivembuf(so, NULL, &m, MSG_WAITALL, &readlen); } while (error == EWOULDBLOCK); if (!error && (len > readlen)) { - printf("short receive (%ld/%ld) from server " IP_FORMAT "\n", - readlen, len, IP_LIST(&(sin->sin_addr.s_addr))); - error = EPIPE; + printf("short receive (%ld/%ld) from server " IP_FORMAT "\n", + readlen, len, IP_LIST(&(sin->sin_addr.s_addr))); + error = EPIPE; } } else { len = maxpacket; @@ -455,24 +482,29 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) secs--; continue; } - if (error) + if (error) { goto out; + } len = readlen; /* Does the reply contain at least a header? */ - if (len < MIN_REPLY_HDR) + if (len < MIN_REPLY_HDR) { continue; - if (mbuf_len(m) < MIN_REPLY_HDR) + } + if (mbuf_len(m) < MIN_REPLY_HDR) { continue; + } reply = mbuf_data(m); /* Is it the right reply? */ - if (reply->rp_direction != htonl(RPC_REPLY)) + if (reply->rp_direction != htonl(RPC_REPLY)) { continue; + } - if (reply->rp_xid != htonl(xid)) + if (reply->rp_xid != htonl(xid)) { continue; - + } + /* Was RPC accepted? (authorization OK) */ if (reply->rp_astatus != 0) { error = ntohl(reply->rp_u.rpu_errno); @@ -489,8 +521,15 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) goto out; } + + if (mbuf_len(m) < REPLY_SIZE) { + error = RPC_SYSTEM_ERR; + } else { + error = ntohl(reply->rp_u.rpu_ok.rp_rstatus); + } + /* Did the call succeed? */ - if ((error = ntohl(reply->rp_u.rpu_ok.rp_rstatus)) != 0) { + if (error != 0) { printf("rpc status=%d\n", error); /* convert rpc error to errno */ switch (error) { @@ -513,15 +552,14 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) goto out; } - goto gotreply; /* break two levels */ - + goto gotreply; /* break two levels */ } /* while secs */ } /* forever send/receive */ error = ETIMEDOUT; goto out; - gotreply: +gotreply: /* * Pull as much as we can into first mbuf, to make @@ -530,16 +568,19 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) * XXX - Should not rely on making the entire reply * contiguous (fix callers instead). -gwr */ -#if DIAGNOSTIC - if ((mbuf_flags(m) & MBUF_PKTHDR) == 0) +#if DIAGNOSTIC + if ((mbuf_flags(m) & MBUF_PKTHDR) == 0) { panic("krpc_call: received pkt w/o header?"); + } #endif len = mbuf_pkthdr_len(m); - if (sotype == SOCK_STREAM) + if (sotype == SOCK_STREAM) { len -= 4; /* the RPC record marker was read separately */ + } if (mbuf_len(m) < len) { - if ((error = mbuf_pullup(&m, len))) + if ((error = mbuf_pullup(&m, len))) { goto out; + } reply = mbuf_data(m); } @@ -555,10 +596,16 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) /* result */ *data = m; - out: +out: sock_close(so); out1: - if (nam) mbuf_freem(nam); - if (mhead) mbuf_freem(mhead); + if (nam) { + mbuf_freem(nam); + } + if (mhead) { + mbuf_freem(mhead); + } return error; } + +#endif /* CONFIG_NFS_CLIENT */