1 /* modified from OpenSSH distribution -plb 5/22/2003 */
2 
3 /* This file has be modified from the original OpenBSD source */
4 
5 /*
6  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
7  * unrestricted use provided that this legend is included on all tape
8  * media and as a part of the software program in whole or part.  Users
9  * may copy or modify Sun RPC without charge, but are not authorized
10  * to license or distribute it to anyone else except as part of a product or
11  * program developed by the user.
12  *
13  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
14  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
15  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
16  *
17  * Sun RPC is provided with no support and without any obligation on the
18  * part of Sun Microsystems, Inc. to assist in its use, correction,
19  * modification or enhancement.
20  *
21  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
22  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
23  * OR ANY PART THEREOF.
24  *
25  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
26  * or profits or other special, indirect and consequential damages, even if
27  * Sun has been advised of the possibility of such damages.
28  *
29  * Sun Microsystems, Inc.
30  * 2550 Garcia Avenue
31  * Mountain View, California  94043
32  */
33 
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif /* HAVE_CONFIG_H defined */
37 
38 #if defined(LIBC_SCCS) && !defined(lint)
39 static char *rcsid = "$OpenBSD: bindresvport.c,v 1.13 2000/01/26 03:43:21 deraadt Exp $";
40 #endif /* defined(LIBC_SCCS) && !defined(lint) */
41 
42 /*
43  * Copyright (c) 1987 by Sun Microsystems, Inc.
44  *
45  * Portions Copyright(C) 1996, Jason Downs.  All rights reserved.
46  */
47 
48 #ifdef HAVE_WINSOCK_H
49 #include <winsock.h>
50 #include <process.h>		/* getpid() */
51 #define HAVE_INCLUDES
52 #endif /* HAVE_WINSOCK_H defined */
53 
54 #ifdef HAVE_WINSOCK2_H
55 #include <ws2tcpip.h>
56 #include <process.h>		/* getpid() */
57 #define HAVE_INCLUDES
58 #define HAVE_SOCKADDR_IN6
59 #endif /* HAVE_WINSOCK_H defined */
60 
61 #ifdef OLD_UCX_INCLUDES
62 #include <types.h>
63 #include <socket.h>
64 #include <in.h>
65 #define HAVE_INCLUDES
66 #endif /* OLD_UCX_INCLUDES defined */
67 
68 #ifndef HAVE_INCLUDES
69 #include <sys/types.h>
70 #include <sys/socket.h>
71 #include <netinet/in.h>
72 #endif /* HAVE_INCLUDES not defined */
73 
74 #ifdef HAVE_UNISTD_H
75 #include <unistd.h>
76 #endif /* HAVE_UNISTD_H defined */
77 
78 #include <errno.h>
79 
80 #if !defined(IPPORT_RESERVED) && !defined(__GLIBC__)
81 /*
82  * could be using broken musl libc!
83  * they refuse to identify themselves:
84  * http://wiki.musl-libc.org/wiki/FAQ#Q:_why_is_there_no_MUSL_macro_.3F
85  */
86 #include <netdb.h>
87 #endif
88 
89 #include "h.h"				/* needed? */
90 #include "str.h"			/* bzero() */
91 #include "bindresvport.h"
92 
93 #define STARTPORT 600
94 #define ENDPORT (IPPORT_RESERVED - 1)
95 #define NPORTS	(ENDPORT - STARTPORT + 1)
96 
97 #if !defined(EADDRINUSE) && defined(WSAEADDRINUSE)
98 #define EADDRINUSE WSAEADDRINUSE
99 #endif
100 #if !defined(EPFNOSUPPORT) && defined(WSAEPFNOSUPPORT)
101 #define EPFNOSUPPORT WSAEPFNOSUPPORT
102 #endif
103 
104 /*
105  * Bind a socket to a privileged IP port
106  */
107 int
bindresvport_sa(int sd,struct sockaddr * sa)108 bindresvport_sa(int sd, struct sockaddr *sa) {
109 	int error, af;
110 	struct sockaddr myaddr;
111 	unsigned short *portp;
112 	unsigned short port;
113 	SOCKLEN_T salen;
114 	int i;
115 
116 	if (sa == NULL) {
117 		sa = &myaddr;
118 		bzero((char *)sa, sizeof(myaddr));
119 
120 		if (getsockname(sd, sa, &salen) == -1)
121 			return -1;	/* errno is correctly set */
122 
123 		af = sa->sa_family;
124 		bzero((char *)sa, salen);
125 	} else
126 		af = sa->sa_family;
127 
128 	switch (af) {
129 	case AF_INET:
130 		salen = sizeof(struct sockaddr_in);
131 		portp = &((struct sockaddr_in *)sa)->sin_port;
132 		break;
133 /* Tru64 4.0 defines AF_INET6, but has nothing else! */
134 #ifdef HAVE_SOCKADDR_IN6
135 	case AF_INET6:
136 		salen = sizeof(struct sockaddr_in6);
137 		portp = &((struct sockaddr_in6 *)sa)->sin6_port;
138 		break;
139 #endif /* HAVE_SOCKADDR_IN6 defined */
140 	default:
141 		errno = EPFNOSUPPORT;
142 		return (-1);
143 	}
144 	sa->sa_family = af;
145 
146 	port = ntohs(*portp);
147 	if (port == 0)
148 		port = (getpid() % NPORTS) + STARTPORT;
149 
150 	/* Avoid warning */
151 	error = -1;
152 
153 	for(i = 0; i < NPORTS; i++) {
154 		*portp = htons(port);
155 
156 		error = bind(sd, sa, salen);
157 
158 		/* Terminate on success */
159 		if (error == 0)
160 			break;
161 
162 		/* Terminate on errors, except "address already in use" */
163 		if ((error < 0) && !((errno == EADDRINUSE) || (errno == EINVAL)))
164 			break;
165 
166 		port++;
167 		if (port > ENDPORT)
168 			port = STARTPORT;
169 	}
170 
171 	return (error);
172 }
173 
174 #ifdef NEED_BINDRESVPORT
175 int
bindresvport(int sd,struct sockaddr_in * sin)176 bindresvport(int sd, struct sockaddr_in *sin) {
177 	return bindresvport_sa(sd, (struct sockaddr *)sin);
178 }
179 #endif /* NEED_BINDRESVPORT defined */
180