1 /*
2  * Copyright (c) 2009, Sun Microsystems, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * - Redistributions of source code must retain the above copyright notice,
8  *   this list of conditions and the following disclaimer.
9  * - Redistributions in binary form must reproduce the above copyright notice,
10  *   this list of conditions and the following disclaimer in the documentation
11  *   and/or other materials provided with the distribution.
12  * - Neither the name of Sun Microsystems, Inc. nor the names of its
13  *   contributors may be used to endorse or promote products derived
14  *   from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 //#include <sys/cdefs.h>
30 
31 /*
32  * Copyright (c) 1987 by Sun Microsystems, Inc.
33  *
34  * Portions Copyright(C) 1996, Jason Downs.  All rights reserved.
35  */
36 
37 #include <wintirpc.h>
38 #include <sys/types.h>
39 //#include <sys/socket.h>
40 
41 //#include <netinet/in.h>
42 
43 #include <errno.h>
44 #include <string.h>
45 //#include <unistd.h>
46 
47 #include <rpc/rpc.h>
48 
49 /*
50  * Bind a socket to a privileged IP port
51  */
52 int
53 bindresvport(sd, sin)
54         SOCKET sd;
55         struct sockaddr_in *sin;
56 {
57         return bindresvport_sa(sd, (struct sockaddr *)sin);
58 }
59 
60 #ifdef __linux__
61 
62 #define STARTPORT 600
63 #define LOWPORT 512
64 #define ENDPORT (IPPORT_RESERVED - 1)
65 #define NPORTS  (ENDPORT - STARTPORT + 1)
66 
67 int
68 bindresvport_sa(sd, sa)
69         int sd;
70         struct sockaddr *sa;
71 {
72         int res, af;
73         struct sockaddr_storage myaddr;
74 	struct sockaddr_in *sin;
75 #ifdef INET6
76 	struct sockaddr_in6 *sin6;
77 #endif
78 	u_int16_t *portp;
79 	static u_int16_t port;
80 	static short startport = STARTPORT;
81 	socklen_t salen;
82 	int nports = ENDPORT - startport + 1;
83 	int endport = ENDPORT;
84 	int i;
85 
86         if (sa == NULL) {
87                 salen = sizeof(myaddr);
88                 sa = (struct sockaddr *)&myaddr;
89 
90                 if (getsockname(sd, (struct sockaddr *)&myaddr, &salen) == -1)
91                         return -1;      /* errno is correctly set */
92 
93                 af = myaddr.ss_family;
94         } else
95                 af = sa->sa_family;
96 
97         switch (af) {
98         case AF_INET:
99 		sin = (struct sockaddr_in *)sa;
100                 salen = sizeof(struct sockaddr_in);
101                 port = ntohs(sin->sin_port);
102 		portp = &sin->sin_port;
103 		break;
104 #ifdef INET6
105         case AF_INET6:
106 		sin6 = (struct sockaddr_in6 *)sa;
107                 salen = sizeof(struct sockaddr_in6);
108                 port = ntohs(sin6->sin6_port);
109                 portp = &sin6->sin6_port;
110                 break;
111 #endif
112         default:
113                 errno = EPFNOSUPPORT;
114                 return (-1);
115         }
116         sa->sa_family = af;
117 
118         if (port == 0) {
119                 port = (getpid() % NPORTS) + STARTPORT;
120         }
121         res = -1;
122         errno = EADDRINUSE;
123 		again:
124         for (i = 0; i < nports; ++i) {
125                 *portp = htons(port++);
126                  if (port > endport)
127                         port = startport;
128                 res = bind(sd, sa, salen);
129 		if (res >= 0 || errno != EADDRINUSE)
130 	                break;
131         }
132 	if (i == nports && startport != LOWPORT) {
133 	    startport = LOWPORT;
134 	    endport = STARTPORT - 1;
135 	    nports = STARTPORT - LOWPORT;
136 	    port = LOWPORT + port % (STARTPORT - LOWPORT);
137 	    goto again;
138 	}
139         return (res);
140 }
141 
142 #else
143 /*----------------------
144 #if defined(_WIN32)
145 
146 int
147 bindresvport_sa(SOCKET sd, struct sockaddr *sa)
148 {
149 	fprintf(stderr, "Do-nothing bindresvport_sa!\n");
150 	return 0;
151 }
152 #else
153 -------------------------*/
154 #define IP_PORTRANGE 19
155 #define IP_PORTRANGE_LOW 2
156 
157 /*
158  * Bind a socket to a privileged IP port
159  */
160 int
161 bindresvport_sa(sd, sa)
162 	SOCKET sd;
163 	struct sockaddr *sa;
164 {
165 #ifdef IPV6_PORTRANGE
166 	int old;
167 #endif
168 	int error, af;
169 	struct sockaddr_storage myaddr;
170 	struct sockaddr_in *sin;
171 #ifdef INET6
172 	struct sockaddr_in6 *sin6;
173 #endif
174 	int proto, portrange, portlow;
175 	u_int16_t *portp;
176 	socklen_t salen;
177 #ifdef _WIN32
178 		WSAPROTOCOL_INFO proto_info;
179 		int proto_info_size = sizeof(proto_info);
180 #endif
181 
182 	if (sa == NULL) {
183 		salen = sizeof(myaddr);
184 		sa = (struct sockaddr *)&myaddr;
185 
186 #ifdef _WIN32
187 		memset(sa, 0, salen);
188 		if (error = getsockopt(sd, SOL_SOCKET, SO_PROTOCOL_INFO, (char *)&proto_info, &proto_info_size) == SOCKET_ERROR) {
189 #ifndef __REACTOS__
190 			int sockerr = WSAGetLastError();
191 #endif
192 			return -1;
193 		}
194 		af = proto_info.iAddressFamily;
195 #else
196 		if (getsockname(sd, sa, &salen) == -1)
197 			return -1;	/* errno is correctly set */
198 
199 		af = sa->sa_family;
200 		memset(sa, 0, salen);
201 #endif
202 	} else
203 		af = sa->sa_family;
204 
205 	switch (af) {
206 	case AF_INET:
207 		proto = IPPROTO_IP;
208 		portrange = IP_PORTRANGE;
209 		portlow = IP_PORTRANGE_LOW;
210 		sin = (struct sockaddr_in *)sa;
211 		salen = sizeof(struct sockaddr_in);
212 		portp = &sin->sin_port;
213 		break;
214 #ifdef INET6
215 	case AF_INET6:
216 		proto = IPPROTO_IPV6;
217 #ifdef IPV6_PORTRANGE
218 		portrange = IPV6_PORTRANGE;
219 		portlow = IPV6_PORTRANGE_LOW;
220 #endif
221 		sin6 = (struct sockaddr_in6 *)sa;
222 		salen = sizeof(struct sockaddr_in6);
223 		portp = &sin6->sin6_port;
224 		break;
225 #endif /* INET6 */
226 	default:
227 		errno = WSAEPFNOSUPPORT;
228 		return (-1);
229 	}
230 	sa->sa_family = (ADDRESS_FAMILY) af;
231 
232 #ifdef IPV6_PORTRANGE
233 	if (*portp == 0) {
234 		socklen_t oldlen = sizeof(old);
235 
236 		error = getsockopt(sd, proto, portrange, &old, &oldlen);
237 		if (error < 0)
238 			return (error);
239 
240 		error = setsockopt(sd, proto, portrange, &portlow,
241 		    sizeof(portlow));
242 		if (error < 0)
243 			return (error);
244 	}
245 #endif
246 
247 	error = bind(sd, sa, salen);
248 	if (error) {
249 #ifndef __REACTOS__
250 		int err = WSAGetLastError();
251 #endif
252 	}
253 
254 #ifdef IPV6_PORTRANGE
255 	if (*portp == 0) {
256 		int saved_errno = errno;
257 
258 		if (error < 0) {
259 			if (setsockopt(sd, proto, portrange, &old,
260 			    sizeof(old)) < 0)
261 				errno = saved_errno;
262 			return (error);
263 		}
264 
265 		if (sa != (struct sockaddr *)&myaddr) {
266 			/* Hmm, what did the kernel assign? */
267 			if (getsockname(sd, sa, &salen) < 0)
268 				errno = saved_errno;
269 			return (error);
270 		}
271 	}
272 #endif
273 	return (error);
274 }
275 /*
276 #endif
277 */
278 #endif
279