X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/5d5c5d0d5b79ade9a973d55186ffda2638ba2b6e..ea3f04195ba4a5034c9c8e9b726d4f7ce96f1832:/bsd/nfs/krpc_subr.c diff --git a/bsd/nfs/krpc_subr.c b/bsd/nfs/krpc_subr.c index 6917ec031..345762a0b 100644 --- a/bsd/nfs/krpc_subr.c +++ b/bsd/nfs/krpc_subr.c @@ -1,35 +1,33 @@ /* - * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2016 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_OSREFERENCE_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 - * compliance with the License. The rights granted to you under the - * License may not be used to create, or enable the creation or - * redistribution of, 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. + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * Please obtain a copy of the License at - * http://www.opensource.apple.com/apsl/ and read it before using this - * file. + * 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 + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * 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. * - * 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, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * 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_LICENSE_OSREFERENCE_HEADER_END@ + * @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. * @@ -67,6 +65,9 @@ * */ +#include +#if CONFIG_NFS_CLIENT + #include #include #include @@ -78,7 +79,6 @@ #include #include #include -#include #include #include @@ -90,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. */ @@ -100,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? @@ -136,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" @@ -149,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; @@ -174,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); @@ -188,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; } /* @@ -207,28 +214,30 @@ 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; mbuf_t m, nam, mhead; struct rpc_call *call; struct rpc_reply *reply; - int error, timo, secs, len; + int error, timo, secs; + size_t len; static u_int32_t xid = ~0xFF; u_int16_t tport; - int 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; @@ -236,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))) - goto out; + if ((error = sock_socket(AF_INET, sotype, 0, 0, 0, &so))) { + goto out1; + } { struct timeval tv; @@ -245,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; + } } /* @@ -256,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; + } } /* @@ -265,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)); @@ -279,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) { @@ -290,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); @@ -301,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; } @@ -317,27 +332,32 @@ 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 */ if (sotype == SOCK_STREAM) { /* first, fill in RPC record marker */ - u_long *recmark = mbuf_data(mhead); + u_int32_t *recmark = mbuf_data(mhead); *recmark = htonl(0x80000000 | (mbuf_pkthdr_len(mhead) - 4)); call = (struct rpc_call *)(recmark + 1); } else { @@ -362,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; @@ -382,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. @@ -395,54 +417,57 @@ 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; } if (sotype == SOCK_STREAM) { int maxretries = 60; - struct iovec_32 aio; - aio.iov_base = (uintptr_t) &len; - aio.iov_len = sizeof(u_long); + struct iovec aio; + aio.iov_base = &len; + aio.iov_len = sizeof(u_int32_t); bzero(&msg, sizeof(msg)); - msg.msg_iov = (struct iovec *) &aio; + 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 (%d/%d) from server " IP_FORMAT "\n", - readlen, sizeof(u_long), 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 (%d) from server %s\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 > (int)readlen)) { - printf("short receive (%d/%d) from server %s\n", - readlen, len, IP_LIST(&(sin->sin_addr.s_addr))); - error = EPIPE; + 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; } } else { len = maxpacket; @@ -457,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); @@ -491,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) { @@ -515,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 @@ -532,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); } @@ -557,9 +596,16 @@ krpc_call(sa, sotype, prog, vers, func, data, from_p) /* result */ *data = m; - out: - if (nam) mbuf_freem(nam); - if (mhead) mbuf_freem(mhead); +out: sock_close(so); +out1: + if (nam) { + mbuf_freem(nam); + } + if (mhead) { + mbuf_freem(mhead); + } return error; } + +#endif /* CONFIG_NFS_CLIENT */