1 | /* $NetBSD: bindresvport.c,v 1.25 2013/03/11 20:19:28 tron Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 2010, Oracle America, Inc. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions are |
8 | * met: |
9 | * |
10 | * * Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * * Redistributions in binary form must reproduce the above |
13 | * copyright notice, this list of conditions and the following |
14 | * disclaimer in the documentation and/or other materials |
15 | * provided with the distribution. |
16 | * * Neither the name of the "Oracle America, Inc." nor the names of its |
17 | * contributors may be used to endorse or promote products derived |
18 | * from this software without specific prior written permission. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
23 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
24 | * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, |
25 | * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
27 | * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
29 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
30 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
32 | */ |
33 | |
34 | #include <sys/cdefs.h> |
35 | #if defined(LIBC_SCCS) && !defined(lint) |
36 | #if 0 |
37 | static char *sccsid = "@(#)bindresvport.c 1.8 88/02/08 SMI" ; |
38 | static char *sccsid = "@(#)bindresvport.c 2.2 88/07/29 4.0 RPCSRC" ; |
39 | #else |
40 | __RCSID("$NetBSD: bindresvport.c,v 1.25 2013/03/11 20:19:28 tron Exp $" ); |
41 | #endif |
42 | #endif |
43 | |
44 | /* |
45 | * Copyright (c) 1987 by Sun Microsystems, Inc. |
46 | */ |
47 | |
48 | #include "namespace.h" |
49 | |
50 | #include <sys/types.h> |
51 | #include <sys/socket.h> |
52 | |
53 | #include <netinet/in.h> |
54 | |
55 | #include <errno.h> |
56 | #include <string.h> |
57 | #include <unistd.h> |
58 | |
59 | #include <rpc/rpc.h> |
60 | #include "svc_fdset.h" |
61 | |
62 | #ifdef __weak_alias |
63 | __weak_alias(bindresvport,_bindresvport) |
64 | __weak_alias(bindresvport_sa,_bindresvport_sa) |
65 | #endif |
66 | |
67 | /* |
68 | * Bind a socket to a privileged IP port |
69 | */ |
70 | int |
71 | bindresvport(int sd, struct sockaddr_in *brsin) |
72 | { |
73 | return bindresvport_sa(sd, (struct sockaddr *)(void *)brsin); |
74 | } |
75 | |
76 | /* |
77 | * Bind a socket to a privileged IP port |
78 | */ |
79 | int |
80 | bindresvport_sa(int sd, struct sockaddr *sa) |
81 | { |
82 | int error, old; |
83 | struct sockaddr_storage myaddr; |
84 | struct sockaddr_in *brsin; |
85 | #ifdef INET6 |
86 | struct sockaddr_in6 *brsin6; |
87 | #endif |
88 | int proto, portrange, portlow; |
89 | u_int16_t *portp; |
90 | socklen_t salen; |
91 | int af; |
92 | |
93 | if (sa == NULL) { |
94 | salen = sizeof(myaddr); |
95 | sa = (struct sockaddr *)(void *)&myaddr; |
96 | |
97 | if (getsockname(sd, sa, &salen) == -1) |
98 | return -1; /* errno is correctly set */ |
99 | |
100 | af = sa->sa_family; |
101 | memset(sa, 0, salen); |
102 | } else |
103 | af = sa->sa_family; |
104 | |
105 | switch (af) { |
106 | case AF_INET: |
107 | proto = IPPROTO_IP; |
108 | portrange = IP_PORTRANGE; |
109 | portlow = IP_PORTRANGE_LOW; |
110 | brsin = (struct sockaddr_in *)(void *)sa; |
111 | salen = sizeof(struct sockaddr_in); |
112 | portp = &brsin->sin_port; |
113 | break; |
114 | #ifdef INET6 |
115 | case AF_INET6: |
116 | proto = IPPROTO_IPV6; |
117 | portrange = IPV6_PORTRANGE; |
118 | portlow = IPV6_PORTRANGE_LOW; |
119 | brsin6 = (struct sockaddr_in6 *)(void *)sa; |
120 | salen = sizeof(struct sockaddr_in6); |
121 | portp = &brsin6->sin6_port; |
122 | break; |
123 | #endif |
124 | default: |
125 | errno = EPFNOSUPPORT; |
126 | return (-1); |
127 | } |
128 | sa->sa_family = af; |
129 | sa->sa_len = salen; |
130 | |
131 | if (*portp == 0) { |
132 | socklen_t oldlen = sizeof(old); |
133 | |
134 | error = getsockopt(sd, proto, portrange, &old, &oldlen); |
135 | if (error < 0) |
136 | return (error); |
137 | error = setsockopt(sd, proto, portrange, &portlow, |
138 | (socklen_t)sizeof(portlow)); |
139 | if (error < 0) |
140 | return (error); |
141 | } |
142 | |
143 | error = bind(sd, sa, salen); |
144 | |
145 | if (*portp == 0) { |
146 | int saved_errno = errno; |
147 | |
148 | if (error < 0) { |
149 | if (setsockopt(sd, proto, portrange, &old, |
150 | (socklen_t)sizeof(old)) < 0) |
151 | errno = saved_errno; |
152 | return (error); |
153 | } |
154 | |
155 | if (sa != (struct sockaddr *)(void *)&myaddr) { |
156 | /* What did the kernel assign? */ |
157 | if (getsockname(sd, sa, &salen) < 0) |
158 | errno = saved_errno; |
159 | return (error); |
160 | } |
161 | } |
162 | return (error); |
163 | } |
164 | |