| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: rcmd.c,v 1.65 2007/01/03 11:46:22 ws Exp $ */ | | 1 | /* $NetBSD: rcmd.c,v 1.66 2011/05/31 06:49:26 christos Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1983, 1993, 1994 | | 4 | * Copyright (c) 1983, 1993, 1994 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * Redistribution and use in source and binary forms, with or without | | 7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions | | 8 | * modification, are permitted provided that the following conditions |
9 | * are met: | | 9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright | | 10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. | | 11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright | | 12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the | | 13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. | | 14 | * documentation and/or other materials provided with the distribution. |
| @@ -24,27 +24,27 @@ | | | @@ -24,27 +24,27 @@ |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | | 26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | | 27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | | 28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. | | 29 | * SUCH DAMAGE. |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | #include <sys/cdefs.h> | | 32 | #include <sys/cdefs.h> |
33 | #if defined(LIBC_SCCS) && !defined(lint) | | 33 | #if defined(LIBC_SCCS) && !defined(lint) |
34 | #if 0 | | 34 | #if 0 |
35 | static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94"; | | 35 | static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94"; |
36 | #else | | 36 | #else |
37 | __RCSID("$NetBSD: rcmd.c,v 1.65 2007/01/03 11:46:22 ws Exp $"); | | 37 | __RCSID("$NetBSD: rcmd.c,v 1.66 2011/05/31 06:49:26 christos Exp $"); |
38 | #endif | | 38 | #endif |
39 | #endif /* LIBC_SCCS and not lint */ | | 39 | #endif /* LIBC_SCCS and not lint */ |
40 | | | 40 | |
41 | #ifdef _LIBC | | 41 | #ifdef _LIBC |
42 | #include "namespace.h" | | 42 | #include "namespace.h" |
43 | #endif | | 43 | #endif |
44 | #include <sys/param.h> | | 44 | #include <sys/param.h> |
45 | #include <sys/socket.h> | | 45 | #include <sys/socket.h> |
46 | #include <sys/stat.h> | | 46 | #include <sys/stat.h> |
47 | #include <sys/poll.h> | | 47 | #include <sys/poll.h> |
48 | #include <sys/wait.h> | | 48 | #include <sys/wait.h> |
49 | | | 49 | |
50 | #include <netinet/in.h> | | 50 | #include <netinet/in.h> |
| @@ -60,165 +60,146 @@ __RCSID("$NetBSD: rcmd.c,v 1.65 2007/01/ | | | @@ -60,165 +60,146 @@ __RCSID("$NetBSD: rcmd.c,v 1.65 2007/01/ |
60 | #include <grp.h> | | 60 | #include <grp.h> |
61 | #include <netdb.h> | | 61 | #include <netdb.h> |
62 | #include <paths.h> | | 62 | #include <paths.h> |
63 | #include <pwd.h> | | 63 | #include <pwd.h> |
64 | #include <signal.h> | | 64 | #include <signal.h> |
65 | #include <stdio.h> | | 65 | #include <stdio.h> |
66 | #include <stdlib.h> | | 66 | #include <stdlib.h> |
67 | #include <string.h> | | 67 | #include <string.h> |
68 | #include <syslog.h> | | 68 | #include <syslog.h> |
69 | #include <unistd.h> | | 69 | #include <unistd.h> |
70 | | | 70 | |
71 | #include "pathnames.h" | | 71 | #include "pathnames.h" |
72 | | | 72 | |
73 | int orcmd __P((char **, u_int, const char *, const char *, const char *, | | 73 | int orcmd(char **, u_int, const char *, const char *, const char *, int *); |
74 | int *)); | | 74 | int orcmd_af(char **, u_int, const char *, const char *, const char *, |
75 | int orcmd_af __P((char **, u_int, const char *, const char *, const char *, | | 75 | int *, int); |
76 | int *, int)); | | 76 | int __ivaliduser(FILE *, u_int32_t, const char *, const char *); |
77 | int __ivaliduser __P((FILE *, u_int32_t, const char *, const char *)); | | 77 | int __ivaliduser_sa(FILE *, const struct sockaddr *, socklen_t, |
78 | int __ivaliduser_sa __P((FILE *, const struct sockaddr *, socklen_t, | | 78 | const char *, const char *); |
79 | const char *, const char *)); | | 79 | static int rshrcmd(int, char **, u_int32_t, const char *, |
80 | static int rshrcmd __P((char **, u_int32_t, const char *, const char *, | | 80 | const char *, const char *, int *, const char *); |
81 | const char *, int *, const char *)); | | 81 | static int resrcmd(struct addrinfo *, char **, u_int32_t, const char *, |
82 | static int resrcmd __P((struct addrinfo *, char **, u_int32_t, const char *, | | 82 | const char *, const char *, int *); |
83 | const char *, const char *, int *)); | | 83 | static int __icheckhost(const struct sockaddr *, socklen_t, |
84 | static int __icheckhost __P((const struct sockaddr *, socklen_t, | | 84 | const char *); |
85 | const char *)); | | 85 | static char *__gethostloop(const struct sockaddr *, socklen_t); |
86 | static char *__gethostloop __P((const struct sockaddr *, socklen_t)); | | | |
87 | | | 86 | |
88 | int | | 87 | int |
89 | rcmd(ahost, rport, locuser, remuser, cmd, fd2p) | | 88 | rcmd(char **ahost, int rport, const char *locuser, const char *remuser, |
90 | char **ahost; | | 89 | const char *cmd, int *fd2p) |
91 | u_short rport; | | | |
92 | const char *locuser, *remuser, *cmd; | | | |
93 | int *fd2p; | | | |
94 | { | | 90 | { |
95 | | | 91 | |
96 | return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET); | | 92 | return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET); |
97 | } | | 93 | } |
98 | | | 94 | |
99 | int | | 95 | int |
100 | rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af) | | 96 | rcmd_af(char **ahost, int rport, const char *locuser, const char *remuser, |
101 | char **ahost; | | 97 | const char *cmd, int *fd2p, int af) |
102 | u_short rport; | | | |
103 | const char *locuser, *remuser, *cmd; | | | |
104 | int *fd2p; | | | |
105 | int af; | | | |
106 | { | | 98 | { |
107 | static char hbuf[MAXHOSTNAMELEN]; | | 99 | static char hbuf[MAXHOSTNAMELEN]; |
108 | char pbuf[NI_MAXSERV]; | | 100 | char pbuf[NI_MAXSERV]; |
109 | struct addrinfo hints, *res; | | 101 | struct addrinfo hints, *res; |
110 | int error; | | 102 | int error; |
111 | struct servent *sp; | | 103 | struct servent *sp; |
112 | | | 104 | |
113 | _DIAGASSERT(ahost != NULL); | | 105 | _DIAGASSERT(ahost != NULL); |
114 | _DIAGASSERT(locuser != NULL); | | 106 | _DIAGASSERT(locuser != NULL); |
115 | _DIAGASSERT(remuser != NULL); | | 107 | _DIAGASSERT(remuser != NULL); |
116 | _DIAGASSERT(cmd != NULL); | | 108 | _DIAGASSERT(cmd != NULL); |
117 | /* fd2p may be NULL */ | | 109 | /* fd2p may be NULL */ |
118 | | | 110 | |
119 | snprintf(pbuf, sizeof(pbuf), "%u", ntohs(rport)); | | 111 | snprintf(pbuf, sizeof(pbuf), "%u", ntohs(rport)); |
120 | memset(&hints, 0, sizeof(hints)); | | 112 | memset(&hints, 0, sizeof(hints)); |
121 | hints.ai_family = af; | | 113 | hints.ai_family = af; |
122 | hints.ai_socktype = SOCK_STREAM; | | 114 | hints.ai_socktype = SOCK_STREAM; |
123 | hints.ai_flags = AI_CANONNAME; | | 115 | hints.ai_flags = AI_CANONNAME; |
124 | error = getaddrinfo(*ahost, pbuf, &hints, &res); | | 116 | error = getaddrinfo(*ahost, pbuf, &hints, &res); |
125 | if (error) { | | 117 | if (error) { |
126 | warnx("%s: %s", *ahost, gai_strerror(error)); /*XXX*/ | | 118 | warnx("%s: %s", *ahost, gai_strerror(error)); /*XXX*/ |
127 | return (-1); | | 119 | return -1; |
128 | } | | 120 | } |
129 | if (res->ai_canonname) { | | 121 | if (res->ai_canonname) { |
130 | /* | | 122 | /* |
131 | * Canonicalise hostname. | | 123 | * Canonicalise hostname. |
132 | * XXX: Should we really do this? | | 124 | * XXX: Should we really do this? |
133 | */ | | 125 | */ |
134 | strlcpy(hbuf, res->ai_canonname, sizeof(hbuf)); | | 126 | strlcpy(hbuf, res->ai_canonname, sizeof(hbuf)); |
135 | *ahost = hbuf; | | 127 | *ahost = hbuf; |
136 | } | | 128 | } |
137 | | | 129 | |
138 | /* | | 130 | /* |
139 | * Check if rport is the same as the shell port, and that the fd2p. If | | 131 | * Check if rport is the same as the shell port, and that the fd2p. If |
140 | * it is not, the program isn't expecting 'rsh' and so we can't use the | | 132 | * it is not, the program isn't expecting 'rsh' and so we can't use the |
141 | * RCMD_CMD environment. | | 133 | * RCMD_CMD environment. |
142 | */ | | 134 | */ |
143 | sp = getservbyname("shell", "tcp"); | | 135 | sp = getservbyname("shell", "tcp"); |
144 | if (sp != NULL && sp->s_port == rport) | | 136 | if (sp != NULL && sp->s_port == rport) |
145 | error = rshrcmd(ahost, (u_int32_t)rport, | | 137 | error = rshrcmd(af, ahost, (u_int32_t)rport, |
146 | locuser, remuser, cmd, fd2p, getenv("RCMD_CMD")); | | 138 | locuser, remuser, cmd, fd2p, getenv("RCMD_CMD")); |
147 | else | | 139 | else |
148 | error = resrcmd(res, ahost, (u_int32_t)rport, | | 140 | error = resrcmd(res, ahost, (u_int32_t)rport, |
149 | locuser, remuser, cmd, fd2p); | | 141 | locuser, remuser, cmd, fd2p); |
150 | freeaddrinfo(res); | | 142 | freeaddrinfo(res); |
151 | return (error); | | 143 | return error; |
152 | } | | 144 | } |
153 | | | 145 | |
154 | /* this is simply a wrapper around hprcmd() that handles ahost first */ | | 146 | /* this is simply a wrapper around hprcmd() that handles ahost first */ |
155 | int | | 147 | int |
156 | orcmd(ahost, rport, locuser, remuser, cmd, fd2p) | | 148 | orcmd(char **ahost, u_int rport, const char *locuser, const char *remuser, |
157 | char **ahost; | | 149 | const char *cmd, int *fd2p) |
158 | u_int rport; | | | |
159 | const char *locuser, *remuser, *cmd; | | | |
160 | int *fd2p; | | | |
161 | { | | 150 | { |
162 | return orcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET); | | 151 | return orcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET); |
163 | } | | 152 | } |
164 | | | 153 | |
165 | int | | 154 | int |
166 | orcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af) | | 155 | orcmd_af(char **ahost, u_int rport, const char *locuser, const char *remuser, |
167 | char **ahost; | | 156 | const char *cmd, int *fd2p, int af) |
168 | u_int rport; | | | |
169 | const char *locuser, *remuser, *cmd; | | | |
170 | int *fd2p; | | | |
171 | int af; | | | |
172 | { | | 157 | { |
173 | static char hbuf[MAXHOSTNAMELEN]; | | 158 | static char hbuf[MAXHOSTNAMELEN]; |
174 | char pbuf[NI_MAXSERV]; | | 159 | char pbuf[NI_MAXSERV]; |
175 | struct addrinfo hints, *res; | | 160 | struct addrinfo hints, *res; |
176 | int error; | | 161 | int error; |
177 | | | 162 | |
178 | _DIAGASSERT(ahost != NULL); | | 163 | _DIAGASSERT(ahost != NULL); |
179 | _DIAGASSERT(locuser != NULL); | | 164 | _DIAGASSERT(locuser != NULL); |
180 | _DIAGASSERT(remuser != NULL); | | 165 | _DIAGASSERT(remuser != NULL); |
181 | _DIAGASSERT(cmd != NULL); | | 166 | _DIAGASSERT(cmd != NULL); |
182 | /* fd2p may be NULL */ | | 167 | /* fd2p may be NULL */ |
183 | | | 168 | |
184 | snprintf(pbuf, sizeof(pbuf), "%u", ntohs(rport)); | | 169 | snprintf(pbuf, sizeof(pbuf), "%u", ntohs(rport)); |
185 | memset(&hints, 0, sizeof(hints)); | | 170 | memset(&hints, 0, sizeof(hints)); |
186 | hints.ai_family = af; | | 171 | hints.ai_family = af; |
187 | hints.ai_socktype = SOCK_STREAM; | | 172 | hints.ai_socktype = SOCK_STREAM; |
188 | hints.ai_flags = AI_CANONNAME; | | 173 | hints.ai_flags = AI_CANONNAME; |
189 | error = getaddrinfo(*ahost, pbuf, &hints, &res); | | 174 | error = getaddrinfo(*ahost, pbuf, &hints, &res); |
190 | if (error) { | | 175 | if (error) { |
191 | warnx("%s: %s", *ahost, gai_strerror(error)); /*XXX*/ | | 176 | warnx("%s: %s", *ahost, gai_strerror(error)); /*XXX*/ |
192 | return (-1); | | 177 | return -1; |
193 | } | | 178 | } |
194 | if (res->ai_canonname) { | | 179 | if (res->ai_canonname) { |
195 | strlcpy(hbuf, res->ai_canonname, sizeof(hbuf)); | | 180 | strlcpy(hbuf, res->ai_canonname, sizeof(hbuf)); |
196 | *ahost = hbuf; | | 181 | *ahost = hbuf; |
197 | } | | 182 | } |
198 | | | 183 | |
199 | error = resrcmd(res, ahost, rport, locuser, remuser, cmd, fd2p); | | 184 | error = resrcmd(res, ahost, rport, locuser, remuser, cmd, fd2p); |
200 | freeaddrinfo(res); | | 185 | freeaddrinfo(res); |
201 | return (error); | | 186 | return error; |
202 | } | | 187 | } |
203 | | | 188 | |
204 | /*ARGSUSED*/ | | 189 | /*ARGSUSED*/ |
205 | static int | | 190 | static int |
206 | resrcmd(res, ahost, rport, locuser, remuser, cmd, fd2p) | | 191 | resrcmd(struct addrinfo *res, char **ahost, u_int32_t rport, |
207 | struct addrinfo *res; | | 192 | const char *locuser, const char *remuser, const char *cmd, int *fd2p) |
208 | char **ahost; | | | |
209 | u_int32_t rport; | | | |
210 | const char *locuser, *remuser, *cmd; | | | |
211 | int *fd2p; | | | |
212 | { | | 193 | { |
213 | struct addrinfo *r; | | 194 | struct addrinfo *r; |
214 | struct sockaddr_storage from; | | 195 | struct sockaddr_storage from; |
215 | struct pollfd reads[2]; | | 196 | struct pollfd reads[2]; |
216 | sigset_t nmask, omask; | | 197 | sigset_t nmask, omask; |
217 | pid_t pid; | | 198 | pid_t pid; |
218 | int s, lport, timo; | | 199 | int s, lport, timo; |
219 | int pollr; | | 200 | int pollr; |
220 | char c; | | 201 | char c; |
221 | int refused; | | 202 | int refused; |
222 | | | 203 | |
223 | _DIAGASSERT(res != NULL); | | 204 | _DIAGASSERT(res != NULL); |
224 | _DIAGASSERT(ahost != NULL); | | 205 | _DIAGASSERT(ahost != NULL); |
| @@ -236,27 +217,27 @@ resrcmd(res, ahost, rport, locuser, remu | | | @@ -236,27 +217,27 @@ resrcmd(res, ahost, rport, locuser, remu |
236 | return -1; | | 217 | return -1; |
237 | for (timo = 1, lport = IPPORT_RESERVED - 1;;) { | | 218 | for (timo = 1, lport = IPPORT_RESERVED - 1;;) { |
238 | s = rresvport_af(&lport, r->ai_family); | | 219 | s = rresvport_af(&lport, r->ai_family); |
239 | if (s < 0) { | | 220 | if (s < 0) { |
240 | if (errno == EAGAIN) | | 221 | if (errno == EAGAIN) |
241 | warnx("rcmd: socket: All ports in use"); | | 222 | warnx("rcmd: socket: All ports in use"); |
242 | else | | 223 | else |
243 | warn("rcmd: socket"); | | 224 | warn("rcmd: socket"); |
244 | if (r->ai_next) { | | 225 | if (r->ai_next) { |
245 | r = r->ai_next; | | 226 | r = r->ai_next; |
246 | continue; | | 227 | continue; |
247 | } else { | | 228 | } else { |
248 | (void)sigprocmask(SIG_SETMASK, &omask, NULL); | | 229 | (void)sigprocmask(SIG_SETMASK, &omask, NULL); |
249 | return (-1); | | 230 | return -1; |
250 | } | | 231 | } |
251 | } | | 232 | } |
252 | fcntl(s, F_SETOWN, pid); | | 233 | fcntl(s, F_SETOWN, pid); |
253 | if (connect(s, r->ai_addr, r->ai_addrlen) >= 0) | | 234 | if (connect(s, r->ai_addr, r->ai_addrlen) >= 0) |
254 | break; | | 235 | break; |
255 | (void)close(s); | | 236 | (void)close(s); |
256 | if (errno == EADDRINUSE) { | | 237 | if (errno == EADDRINUSE) { |
257 | lport--; | | 238 | lport--; |
258 | continue; | | 239 | continue; |
259 | } else if (errno == ECONNREFUSED) | | 240 | } else if (errno == ECONNREFUSED) |
260 | refused++; | | 241 | refused++; |
261 | if (r->ai_next) { | | 242 | if (r->ai_next) { |
262 | int oerrno = errno; | | 243 | int oerrno = errno; |
| @@ -277,27 +258,27 @@ resrcmd(res, ahost, rport, locuser, remu | | | @@ -277,27 +258,27 @@ resrcmd(res, ahost, rport, locuser, remu |
277 | (void)fprintf(stderr, "Trying %s...\n", hbuf); | | 258 | (void)fprintf(stderr, "Trying %s...\n", hbuf); |
278 | continue; | | 259 | continue; |
279 | } | | 260 | } |
280 | if (refused && timo <= 16) { | | 261 | if (refused && timo <= 16) { |
281 | (void)sleep((unsigned int)timo); | | 262 | (void)sleep((unsigned int)timo); |
282 | timo *= 2; | | 263 | timo *= 2; |
283 | r = res; | | 264 | r = res; |
284 | refused = 0; | | 265 | refused = 0; |
285 | continue; | | 266 | continue; |
286 | } | | 267 | } |
287 | (void)fprintf(stderr, "%s: %s\n", res->ai_canonname, | | 268 | (void)fprintf(stderr, "%s: %s\n", res->ai_canonname, |
288 | strerror(errno)); | | 269 | strerror(errno)); |
289 | (void)sigprocmask(SIG_SETMASK, &omask, NULL); | | 270 | (void)sigprocmask(SIG_SETMASK, &omask, NULL); |
290 | return (-1); | | 271 | return -1; |
291 | } | | 272 | } |
292 | lport--; | | 273 | lport--; |
293 | if (fd2p == 0) { | | 274 | if (fd2p == 0) { |
294 | write(s, "", 1); | | 275 | write(s, "", 1); |
295 | lport = 0; | | 276 | lport = 0; |
296 | } else { | | 277 | } else { |
297 | char num[8]; | | 278 | char num[8]; |
298 | int s2 = rresvport_af(&lport, r->ai_family), s3; | | 279 | int s2 = rresvport_af(&lport, r->ai_family), s3; |
299 | socklen_t len = sizeof(from); | | 280 | socklen_t len = sizeof(from); |
300 | | | 281 | |
301 | if (s2 < 0) | | 282 | if (s2 < 0) |
302 | goto bad; | | 283 | goto bad; |
303 | listen(s2, 1); | | 284 | listen(s2, 1); |
| @@ -308,395 +289,398 @@ resrcmd(res, ahost, rport, locuser, remu | | | @@ -308,395 +289,398 @@ resrcmd(res, ahost, rport, locuser, remu |
308 | (void)close(s2); | | 289 | (void)close(s2); |
309 | goto bad; | | 290 | goto bad; |
310 | } | | 291 | } |
311 | reads[0].fd = s; | | 292 | reads[0].fd = s; |
312 | reads[0].events = POLLIN; | | 293 | reads[0].events = POLLIN; |
313 | reads[1].fd = s2; | | 294 | reads[1].fd = s2; |
314 | reads[1].events = POLLIN; | | 295 | reads[1].events = POLLIN; |
315 | errno = 0; | | 296 | errno = 0; |
316 | pollr = poll(reads, 2, INFTIM); | | 297 | pollr = poll(reads, 2, INFTIM); |
317 | if (pollr < 1 || (reads[1].revents & POLLIN) == 0) { | | 298 | if (pollr < 1 || (reads[1].revents & POLLIN) == 0) { |
318 | if (errno != 0) | | 299 | if (errno != 0) |
319 | warn("poll: setting up stderr"); | | 300 | warn("poll: setting up stderr"); |
320 | else | | 301 | else |
321 | warnx("poll: protocol failure in circuit setup"); | | 302 | warnx( |
| | | 303 | "poll: protocol failure in circuit setup"); |
322 | (void)close(s2); | | 304 | (void)close(s2); |
323 | goto bad; | | 305 | goto bad; |
324 | } | | 306 | } |
325 | s3 = accept(s2, (struct sockaddr *)(void *)&from, &len); | | 307 | s3 = accept(s2, (struct sockaddr *)(void *)&from, &len); |
326 | (void)close(s2); | | 308 | (void)close(s2); |
327 | if (s3 < 0) { | | 309 | if (s3 < 0) { |
328 | warn("rcmd: accept"); | | 310 | warn("rcmd: accept"); |
329 | lport = 0; | | 311 | lport = 0; |
330 | goto bad; | | 312 | goto bad; |
331 | } | | 313 | } |
332 | *fd2p = s3; | | 314 | *fd2p = s3; |
333 | switch (((struct sockaddr *)(void *)&from)->sa_family) { | | 315 | switch (((struct sockaddr *)(void *)&from)->sa_family) { |
334 | case AF_INET: | | 316 | case AF_INET: |
335 | #ifdef INET6 | | 317 | #ifdef INET6 |
336 | case AF_INET6: | | 318 | case AF_INET6: |
337 | #endif | | 319 | #endif |
338 | if (getnameinfo((struct sockaddr *)(void *)&from, len, | | 320 | if (getnameinfo((struct sockaddr *)(void *)&from, len, |
339 | NULL, 0, num, sizeof(num), NI_NUMERICSERV) != 0 || | | 321 | NULL, 0, num, sizeof(num), NI_NUMERICSERV) != 0 || |
340 | (atoi(num) >= IPPORT_RESERVED || | | 322 | (atoi(num) >= IPPORT_RESERVED || |
341 | atoi(num) < IPPORT_RESERVED / 2)) { | | 323 | atoi(num) < IPPORT_RESERVED / 2)) { |
342 | warnx("rcmd: protocol failure in circuit setup."); | | 324 | warnx( |
| | | 325 | "rcmd: protocol failure in circuit setup."); |
343 | goto bad2; | | 326 | goto bad2; |
344 | } | | 327 | } |
345 | break; | | 328 | break; |
346 | default: | | 329 | default: |
347 | break; | | 330 | break; |
348 | } | | 331 | } |
349 | } | | 332 | } |
350 | | | 333 | |
351 | (void)write(s, locuser, strlen(locuser)+1); | | 334 | (void)write(s, locuser, strlen(locuser)+1); |
352 | (void)write(s, remuser, strlen(remuser)+1); | | 335 | (void)write(s, remuser, strlen(remuser)+1); |
353 | (void)write(s, cmd, strlen(cmd)+1); | | 336 | (void)write(s, cmd, strlen(cmd)+1); |
354 | if (read(s, &c, 1) != 1) { | | 337 | if (read(s, &c, 1) != 1) { |
355 | warn("%s", *ahost); | | 338 | warn("%s", *ahost); |
356 | goto bad2; | | 339 | goto bad2; |
357 | } | | 340 | } |
358 | if (c != 0) { | | 341 | if (c != 0) { |
359 | while (read(s, &c, 1) == 1) { | | 342 | while (read(s, &c, 1) == 1) { |
360 | (void)write(STDERR_FILENO, &c, 1); | | 343 | (void)write(STDERR_FILENO, &c, 1); |
361 | if (c == '\n') | | 344 | if (c == '\n') |
362 | break; | | 345 | break; |
363 | } | | 346 | } |
364 | goto bad2; | | 347 | goto bad2; |
365 | } | | 348 | } |
366 | (void)sigprocmask(SIG_SETMASK, &omask, NULL); | | 349 | (void)sigprocmask(SIG_SETMASK, &omask, NULL); |
367 | return (s); | | 350 | return s; |
368 | bad2: | | 351 | bad2: |
369 | if (lport) | | 352 | if (lport) |
370 | (void)close(*fd2p); | | 353 | (void)close(*fd2p); |
371 | bad: | | 354 | bad: |
372 | (void)close(s); | | 355 | (void)close(s); |
373 | (void)sigprocmask(SIG_SETMASK, &omask, NULL); | | 356 | (void)sigprocmask(SIG_SETMASK, &omask, NULL); |
374 | return (-1); | | 357 | return -1; |
375 | } | | 358 | } |
376 | | | 359 | |
377 | /* | | 360 | /* |
378 | * based on code written by Chris Siebenmann <cks@utcc.utoronto.ca> | | 361 | * based on code written by Chris Siebenmann <cks@utcc.utoronto.ca> |
379 | */ | | 362 | */ |
380 | /* ARGSUSED */ | | 363 | /* ARGSUSED */ |
381 | static int | | 364 | static int |
382 | rshrcmd(ahost, rport, locuser, remuser, cmd, fd2p, rshcmd) | | 365 | rshrcmd(int af, char **ahost, u_int32_t rport, const char *locuser, |
383 | char **ahost; | | 366 | const char *remuser, const char *cmd, int *fd2p, const char *rshcmd) |
384 | u_int32_t rport; | | | |
385 | const char *locuser, *remuser, *cmd; | | | |
386 | int *fd2p; | | | |
387 | const char *rshcmd; | | | |
388 | { | | 367 | { |
389 | pid_t pid; | | 368 | pid_t pid; |
390 | int sp[2], ep[2]; | | 369 | int sp[2], ep[2]; |
391 | char *p; | | 370 | char *p; |
392 | struct passwd *pw, pwres; | | 371 | struct passwd *pw, pwres; |
393 | char pwbuf[1024]; | | 372 | char pwbuf[1024]; |
394 | | | 373 | |
395 | _DIAGASSERT(ahost != NULL); | | 374 | _DIAGASSERT(ahost != NULL); |
396 | _DIAGASSERT(locuser != NULL); | | 375 | _DIAGASSERT(locuser != NULL); |
397 | _DIAGASSERT(remuser != NULL); | | 376 | _DIAGASSERT(remuser != NULL); |
398 | _DIAGASSERT(cmd != NULL); | | 377 | _DIAGASSERT(cmd != NULL); |
399 | /* fd2p may be NULL */ | | 378 | /* fd2p may be NULL */ |
400 | | | 379 | |
401 | /* What rsh/shell to use. */ | | 380 | /* What rsh/shell to use. */ |
402 | if (rshcmd == NULL) | | 381 | if (rshcmd == NULL) |
403 | rshcmd = _PATH_BIN_RCMD; | | 382 | rshcmd = _PATH_BIN_RCMD; |
404 | | | 383 | |
405 | /* locuser must exist on this host. */ | | 384 | /* locuser must exist on this host. */ |
406 | if (getpwnam_r(locuser, &pwres, pwbuf, sizeof(pwbuf), &pw) != 0 || | | 385 | if (getpwnam_r(locuser, &pwres, pwbuf, sizeof(pwbuf), &pw) != 0 || |
407 | pw == NULL) { | | 386 | pw == NULL) { |
408 | warnx("rshrcmd: unknown user: %s", locuser); | | 387 | warnx("%s: unknown user: %s", __func__, locuser); |
409 | return(-1); | | 388 | return -1; |
410 | } | | 389 | } |
411 | | | 390 | |
412 | /* get a socketpair we'll use for stdin and stdout. */ | | 391 | /* get a socketpair we'll use for stdin and stdout. */ |
413 | if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sp) < 0) { | | 392 | if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sp) < 0) { |
414 | warn("rshrcmd: socketpair"); | | 393 | warn("%s: socketpair", __func__); |
415 | return (-1); | | 394 | return -1; |
416 | } | | 395 | } |
417 | /* we will use this for the fd2 pointer */ | | 396 | /* we will use this for the fd2 pointer */ |
418 | if (fd2p) { | | 397 | if (fd2p) { |
419 | if (socketpair(AF_LOCAL, SOCK_STREAM, 0, ep) < 0) { | | 398 | if (socketpair(AF_LOCAL, SOCK_STREAM, 0, ep) < 0) { |
420 | warn("rshrcmd: socketpair"); | | 399 | warn("%s: socketpair", __func__); |
421 | return (-1); | | 400 | return -1; |
422 | } | | 401 | } |
423 | *fd2p = ep[0]; | | 402 | *fd2p = ep[0]; |
424 | } | | 403 | } |
425 | | | 404 | |
426 | pid = fork(); | | 405 | pid = fork(); |
427 | if (pid < 0) { | | 406 | if (pid < 0) { |
428 | warn("rshrcmd: fork"); | | 407 | warn("%s: fork", __func__); |
429 | return (-1); | | 408 | return -1; |
430 | } | | 409 | } |
431 | if (pid == 0) { | | 410 | if (pid == 0) { |
432 | /* | | 411 | /* |
433 | * child | | 412 | * child |
434 | * - we use sp[1] to be stdin/stdout, and close sp[0] | | 413 | * - we use sp[1] to be stdin/stdout, and close sp[0] |
435 | * - with fd2p, we use ep[1] for stderr, and close ep[0] | | 414 | * - with fd2p, we use ep[1] for stderr, and close ep[0] |
436 | */ | | 415 | */ |
437 | (void)close(sp[0]); | | 416 | (void)close(sp[0]); |
438 | if (dup2(sp[1], 0) < 0 || dup2(0, 1) < 0) { | | 417 | if (dup2(sp[1], 0) < 0 || dup2(0, 1) < 0) { |
439 | warn("rshrcmd: dup2"); | | 418 | warn("%s: dup2", __func__); |
440 | _exit(1); | | 419 | _exit(1); |
441 | } | | 420 | } |
442 | (void)close(sp[1]); | | 421 | (void)close(sp[1]); |
443 | if (fd2p) { | | 422 | if (fd2p) { |
444 | if (dup2(ep[1], 2) < 0) { | | 423 | if (dup2(ep[1], 2) < 0) { |
445 | warn("rshrcmd: dup2"); | | 424 | warn("%s: dup2", __func__); |
446 | _exit(1); | | 425 | _exit(1); |
447 | } | | 426 | } |
448 | (void)close(ep[0]); | | 427 | (void)close(ep[0]); |
449 | (void)close(ep[1]); | | 428 | (void)close(ep[1]); |
450 | } else if (dup2(0, 2) < 0) { | | 429 | } else if (dup2(0, 2) < 0) { |
451 | warn("rshrcmd: dup2"); | | 430 | warn("%s: dup2", __func__); |
452 | _exit(1); | | 431 | _exit(1); |
453 | } | | 432 | } |
454 | /* fork again to lose parent. */ | | 433 | /* fork again to lose parent. */ |
455 | pid = fork(); | | 434 | pid = fork(); |
456 | if (pid < 0) { | | 435 | if (pid < 0) { |
457 | warn("rshrcmd: second fork"); | | 436 | warn("%s: second fork", __func__); |
458 | _exit(1); | | 437 | _exit(1); |
459 | } | | 438 | } |
460 | if (pid > 0) | | 439 | if (pid > 0) |
461 | _exit(0); | | 440 | _exit(0); |
462 | | | 441 | |
463 | /* Orphan. Become local user for rshprog. */ | | 442 | /* Orphan. Become local user for rshprog. */ |
464 | if (setuid(pw->pw_uid)) { | | 443 | if (setuid(pw->pw_uid)) { |
465 | warn("rshrcmd: setuid(%lu)", (u_long)pw->pw_uid); | | 444 | warn("%s: setuid(%lu)", __func__, (u_long)pw->pw_uid); |
466 | _exit(1); | | 445 | _exit(1); |
467 | } | | 446 | } |
468 | | | 447 | |
469 | /* | | 448 | /* |
470 | * If we are rcmd'ing to "localhost" as the same user as we are, | | 449 | * If we are rcmd'ing to "localhost" as the same user as we |
471 | * then avoid running remote shell for efficiency. | | 450 | * are, then avoid running remote shell for efficiency. |
472 | */ | | 451 | */ |
473 | if (strcmp(*ahost, "localhost") == 0 && | | 452 | if (strcmp(*ahost, "localhost") == 0 && |
474 | strcmp(locuser, remuser) == 0) { | | 453 | strcmp(locuser, remuser) == 0) { |
475 | if (pw->pw_shell[0] == '\0') | | 454 | if (pw->pw_shell[0] == '\0') |
476 | rshcmd = _PATH_BSHELL; | | 455 | rshcmd = _PATH_BSHELL; |
477 | else | | 456 | else |
478 | rshcmd = pw->pw_shell; | | 457 | rshcmd = pw->pw_shell; |
479 | p = strrchr(rshcmd, '/'); | | 458 | p = strrchr(rshcmd, '/'); |
480 | execlp(rshcmd, p ? p + 1 : rshcmd, "-c", cmd, NULL); | | 459 | execlp(rshcmd, p ? p + 1 : rshcmd, "-c", cmd, NULL); |
481 | } else { | | 460 | } else { |
482 | p = strrchr(rshcmd, '/'); | | 461 | const char *program; |
483 | execlp(rshcmd, p ? p + 1 : rshcmd, *ahost, "-l", | | 462 | program = strrchr(rshcmd, '/'); |
484 | remuser, cmd, NULL); | | 463 | program = program ? program + 1 : rshcmd; |
| | | 464 | switch (af) { |
| | | 465 | case AF_INET: |
| | | 466 | execlp(rshcmd, program, "-4", "-l", remuser, |
| | | 467 | *ahost, cmd, NULL); |
| | | 468 | break; |
| | | 469 | |
| | | 470 | case AF_INET6: |
| | | 471 | execlp(rshcmd, program, "-6", "-l", remuser, |
| | | 472 | *ahost, cmd, NULL); |
| | | 473 | break; |
| | | 474 | |
| | | 475 | default: |
| | | 476 | /* typically AF_UNSPEC, plus whatever */ |
| | | 477 | execlp(rshcmd, program, "-l", remuser, |
| | | 478 | *ahost, cmd, NULL); |
| | | 479 | break; |
| | | 480 | } |
485 | } | | 481 | } |
486 | warn("rshrcmd: exec %s", rshcmd); | | 482 | warn("%s: exec %s", __func__, rshcmd); |
487 | _exit(1); | | 483 | _exit(1); |
488 | } | | 484 | } |
489 | /* Parent */ | | 485 | /* Parent */ |
490 | (void)close(sp[1]); | | 486 | (void)close(sp[1]); |
491 | if (fd2p) | | 487 | if (fd2p) |
492 | (void)close(ep[1]); | | 488 | (void)close(ep[1]); |
493 | | | 489 | |
494 | (void)waitpid(pid, NULL, 0); | | 490 | (void)waitpid(pid, NULL, 0); |
495 | return (sp[0]); | | 491 | return sp[0]; |
496 | } | | 492 | } |
497 | | | 493 | |
498 | int | | 494 | int |
499 | rresvport(alport) | | 495 | rresvport(int *alport) |
500 | int *alport; | | | |
501 | { | | 496 | { |
502 | | | 497 | |
503 | _DIAGASSERT(alport != NULL); | | 498 | _DIAGASSERT(alport != NULL); |
504 | | | 499 | |
505 | return rresvport_af(alport, AF_INET); | | 500 | return rresvport_af(alport, AF_INET); |
506 | } | | 501 | } |
507 | | | 502 | |
508 | int | | 503 | int |
509 | rresvport_af(alport, family) | | 504 | rresvport_af(int *alport, int family) |
510 | int *alport; | | | |
511 | int family; | | | |
512 | { | | 505 | { |
513 | struct sockaddr_storage ss; | | 506 | struct sockaddr_storage ss; |
514 | struct sockaddr *sa; | | 507 | struct sockaddr *sa; |
515 | int salen; | | 508 | socklen_t salen; |
516 | int s; | | 509 | int s; |
517 | u_int16_t *portp; | | 510 | u_int16_t *portp; |
518 | | | 511 | |
519 | _DIAGASSERT(alport != NULL); | | 512 | _DIAGASSERT(alport != NULL); |
520 | | | 513 | |
521 | memset(&ss, 0, sizeof(ss)); | | 514 | memset(&ss, 0, sizeof(ss)); |
522 | sa = (struct sockaddr *)(void *)&ss; | | 515 | sa = (struct sockaddr *)(void *)&ss; |
523 | switch (family) { | | 516 | switch (family) { |
524 | case AF_INET: | | 517 | case AF_INET: |
525 | #ifdef BSD4_4 | | 518 | #ifdef BSD4_4 |
526 | sa->sa_len = | | 519 | sa->sa_len = |
527 | #endif | | 520 | #endif |
528 | salen = sizeof(struct sockaddr_in); | | 521 | salen = sizeof(struct sockaddr_in); |
529 | portp = &((struct sockaddr_in *)(void *)sa)->sin_port; | | 522 | portp = &((struct sockaddr_in *)(void *)sa)->sin_port; |
530 | break; | | 523 | break; |
531 | #ifdef INET6 | | 524 | #ifdef INET6 |
532 | case AF_INET6: | | 525 | case AF_INET6: |
533 | #ifdef BSD4_4 | | 526 | #ifdef BSD4_4 |
534 | sa->sa_len = | | 527 | sa->sa_len = |
535 | #endif | | 528 | #endif |
536 | salen = sizeof(struct sockaddr_in6); | | 529 | salen = sizeof(struct sockaddr_in6); |
537 | portp = &((struct sockaddr_in6 *)(void *)sa)->sin6_port; | | 530 | portp = &((struct sockaddr_in6 *)(void *)sa)->sin6_port; |
538 | break; | | 531 | break; |
539 | #endif | | 532 | #endif |
540 | default: | | 533 | default: |
541 | errno = EAFNOSUPPORT; | | 534 | errno = EAFNOSUPPORT; |
542 | return (-1); | | 535 | return -1; |
543 | } | | 536 | } |
544 | sa->sa_family = family; | | 537 | sa->sa_family = family; |
545 | s = socket(family, SOCK_STREAM, 0); | | 538 | s = socket(family, SOCK_STREAM, 0); |
546 | if (s < 0) | | 539 | if (s < 0) |
547 | return (-1); | | 540 | return -1; |
548 | #ifdef BSD4_4 | | 541 | #ifdef BSD4_4 |
549 | switch (family) { | | 542 | switch (family) { |
550 | case AF_INET: | | 543 | case AF_INET: |
551 | case AF_INET6: | | 544 | case AF_INET6: |
552 | *portp = 0; | | 545 | *portp = 0; |
553 | if (bindresvport(s, (struct sockaddr_in *)(void *)sa) < 0) { | | 546 | if (bindresvport(s, (struct sockaddr_in *)(void *)sa) < 0) { |
554 | int sverr = errno; | | 547 | int sverr = errno; |
555 | | | 548 | |
556 | (void)close(s); | | 549 | (void)close(s); |
557 | errno = sverr; | | 550 | errno = sverr; |
558 | return (-1); | | 551 | return -1; |
559 | } | | 552 | } |
560 | *alport = (int)ntohs(*portp); | | 553 | *alport = (int)ntohs(*portp); |
561 | return (s); | | 554 | return s; |
562 | default: | | 555 | default: |
563 | /* is it necessary to try keep code for other AFs? */ | | 556 | /* is it necessary to try keep code for other AFs? */ |
564 | break; | | 557 | break; |
565 | } | | 558 | } |
566 | #endif | | 559 | #endif |
567 | for (;;) { | | 560 | for (;;) { |
568 | *portp = htons((u_short)*alport); | | 561 | *portp = htons((u_short)*alport); |
569 | if (bind(s, sa, (socklen_t)salen) >= 0) | | 562 | if (bind(s, sa, salen) >= 0) |
570 | return (s); | | 563 | return s; |
571 | if (errno != EADDRINUSE) { | | 564 | if (errno != EADDRINUSE) { |
572 | (void)close(s); | | 565 | (void)close(s); |
573 | return (-1); | | 566 | return -1; |
574 | } | | 567 | } |
575 | (*alport)--; | | 568 | (*alport)--; |
576 | if (*alport == IPPORT_RESERVED/2) { | | 569 | if (*alport == IPPORT_RESERVED/2) { |
577 | (void)close(s); | | 570 | (void)close(s); |
578 | errno = EAGAIN; /* close */ | | 571 | errno = EAGAIN; /* close */ |
579 | return (-1); | | 572 | return -1; |
580 | } | | 573 | } |
581 | } | | 574 | } |
582 | } | | 575 | } |
583 | | | 576 | |
584 | int __check_rhosts_file = 1; | | 577 | int __check_rhosts_file = 1; |
585 | const char *__rcmd_errstr; | | 578 | const char *__rcmd_errstr; |
586 | | | 579 | |
587 | int | | 580 | int |
588 | ruserok(rhost, superuser, ruser, luser) | | 581 | ruserok(const char *rhost, int superuser, const char *ruser, const char *luser) |
589 | const char *rhost, *ruser, *luser; | | | |
590 | int superuser; | | | |
591 | { | | 582 | { |
592 | struct addrinfo hints, *res, *r; | | 583 | struct addrinfo hints, *res, *r; |
593 | int error; | | 584 | int error; |
594 | | | 585 | |
595 | _DIAGASSERT(rhost != NULL); | | 586 | _DIAGASSERT(rhost != NULL); |
596 | _DIAGASSERT(ruser != NULL); | | 587 | _DIAGASSERT(ruser != NULL); |
597 | _DIAGASSERT(luser != NULL); | | 588 | _DIAGASSERT(luser != NULL); |
598 | | | 589 | |
599 | memset(&hints, 0, sizeof(hints)); | | 590 | memset(&hints, 0, sizeof(hints)); |
600 | hints.ai_family = PF_UNSPEC; | | 591 | hints.ai_family = PF_UNSPEC; |
601 | hints.ai_socktype = SOCK_DGRAM; /*dummy*/ | | 592 | hints.ai_socktype = SOCK_DGRAM; /*dummy*/ |
602 | error = getaddrinfo(rhost, "0", &hints, &res); | | 593 | error = getaddrinfo(rhost, "0", &hints, &res); |
603 | if (error) | | 594 | if (error) |
604 | return (-1); | | 595 | return -1; |
605 | | | 596 | |
606 | for (r = res; r; r = r->ai_next) { | | 597 | for (r = res; r; r = r->ai_next) { |
607 | if (iruserok_sa(r->ai_addr, (int)r->ai_addrlen, superuser, | | 598 | if (iruserok_sa(r->ai_addr, (int)r->ai_addrlen, superuser, |
608 | ruser, luser) == 0) { | | 599 | ruser, luser) == 0) { |
609 | freeaddrinfo(res); | | 600 | freeaddrinfo(res); |
610 | return (0); | | 601 | return 0; |
611 | } | | 602 | } |
612 | } | | 603 | } |
613 | freeaddrinfo(res); | | 604 | freeaddrinfo(res); |
614 | return (-1); | | 605 | return -1; |
615 | } | | 606 | } |
616 | | | 607 | |
617 | /* | | 608 | /* |
618 | * New .rhosts strategy: We are passed an ip address. We spin through | | 609 | * New .rhosts strategy: We are passed an ip address. We spin through |
619 | * hosts.equiv and .rhosts looking for a match. When the .rhosts only | | 610 | * hosts.equiv and .rhosts looking for a match. When the .rhosts only |
620 | * has ip addresses, we don't have to trust a nameserver. When it | | 611 | * has ip addresses, we don't have to trust a nameserver. When it |
621 | * contains hostnames, we spin through the list of addresses the nameserver | | 612 | * contains hostnames, we spin through the list of addresses the nameserver |
622 | * gives us and look for a match. | | 613 | * gives us and look for a match. |
623 | * | | 614 | * |
624 | * Returns 0 if ok, -1 if not ok. | | 615 | * Returns 0 if ok, -1 if not ok. |
625 | */ | | 616 | */ |
626 | int | | 617 | int |
627 | iruserok(raddr, superuser, ruser, luser) | | 618 | iruserok(u_int32_t raddr, int superuser, const char *ruser, const char *luser) |
628 | u_int32_t raddr; | | | |
629 | int superuser; | | | |
630 | const char *ruser, *luser; | | | |
631 | { | | 619 | { |
632 | struct sockaddr_in irsin; | | 620 | struct sockaddr_in irsin; |
633 | | | 621 | |
634 | memset(&irsin, 0, sizeof(irsin)); | | 622 | memset(&irsin, 0, sizeof(irsin)); |
635 | irsin.sin_family = AF_INET; | | 623 | irsin.sin_family = AF_INET; |
636 | #ifdef BSD4_4 | | 624 | #ifdef BSD4_4 |
637 | irsin.sin_len = sizeof(struct sockaddr_in); | | 625 | irsin.sin_len = sizeof(irsin); |
638 | #endif | | 626 | #endif |
639 | memcpy(&irsin.sin_addr, &raddr, sizeof(irsin.sin_addr)); | | 627 | memcpy(&irsin.sin_addr, &raddr, sizeof(irsin.sin_addr)); |
640 | return iruserok_sa(&irsin, sizeof(struct sockaddr_in), superuser, ruser, | | 628 | return iruserok_sa(&irsin, sizeof(irsin), superuser, ruser, luser); |
641 | luser); | | | |
642 | } | | 629 | } |
643 | | | 630 | |
644 | /* | | 631 | /* |
645 | * 2nd and 3rd arguments are typed like this, to avoid dependency between | | 632 | * 2nd and 3rd arguments are typed like this, to avoid dependency between |
646 | * unistd.h and sys/socket.h. There's no better way. | | 633 | * unistd.h and sys/socket.h. There's no better way. |
647 | */ | | 634 | */ |
648 | int | | 635 | int |
649 | iruserok_sa(raddr, rlen, superuser, ruser, luser) | | 636 | iruserok_sa(const void *raddr, int rlen, int superuser, const char *ruser, |
650 | const void *raddr; | | 637 | const char *luser) |
651 | int rlen; | | | |
652 | int superuser; | | | |
653 | const char *ruser, *luser; | | | |
654 | { | | 638 | { |
655 | const struct sockaddr *sa; | | 639 | const struct sockaddr *sa; |
656 | struct stat sbuf; | | 640 | struct stat sbuf; |
657 | struct passwd *pwd, pwres; | | 641 | struct passwd *pwd, pwres; |
658 | FILE *hostf; | | 642 | FILE *hostf; |
659 | uid_t uid; | | 643 | uid_t uid; |
660 | gid_t gid; | | 644 | gid_t gid; |
661 | int isvaliduser; | | 645 | int isvaliduser; |
662 | char pbuf[MAXPATHLEN]; | | 646 | char pbuf[MAXPATHLEN]; |
663 | char pwbuf[1024]; | | 647 | char pwbuf[1024]; |
664 | | | 648 | |
665 | _DIAGASSERT(raddr != NULL); | | 649 | _DIAGASSERT(raddr != NULL); |
666 | _DIAGASSERT(ruser != NULL); | | 650 | _DIAGASSERT(ruser != NULL); |
667 | _DIAGASSERT(luser != NULL); | | 651 | _DIAGASSERT(luser != NULL); |
668 | | | 652 | |
669 | sa = raddr; | | 653 | sa = raddr; |
670 | | | 654 | |
671 | __rcmd_errstr = NULL; | | 655 | __rcmd_errstr = NULL; |
672 | | | 656 | |
673 | hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); | | 657 | hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); |
674 | | | 658 | |
675 | if (hostf) { | | 659 | if (hostf) { |
676 | if (__ivaliduser_sa(hostf, sa, (socklen_t)rlen, luser, | | 660 | if (__ivaliduser_sa(hostf, sa, (socklen_t)rlen, luser, |
677 | ruser) == 0) { | | 661 | ruser) == 0) { |
678 | (void)fclose(hostf); | | 662 | (void)fclose(hostf); |
679 | return (0); | | 663 | return 0; |
680 | } | | 664 | } |
681 | (void)fclose(hostf); | | 665 | (void)fclose(hostf); |
682 | } | | 666 | } |
683 | | | 667 | |
684 | isvaliduser = -1; | | 668 | isvaliduser = -1; |
685 | if (__check_rhosts_file || superuser) { | | 669 | if (__check_rhosts_file || superuser) { |
686 | | | 670 | |
687 | if (getpwnam_r(luser, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 | | 671 | if (getpwnam_r(luser, &pwres, pwbuf, sizeof(pwbuf), &pwd) != 0 |
688 | || pwd == NULL) | | 672 | || pwd == NULL) |
689 | return (-1); | | 673 | return -1; |
690 | (void)strlcpy(pbuf, pwd->pw_dir, sizeof(pbuf)); | | 674 | (void)strlcpy(pbuf, pwd->pw_dir, sizeof(pbuf)); |
691 | (void)strlcat(pbuf, "/.rhosts", sizeof(pbuf)); | | 675 | (void)strlcat(pbuf, "/.rhosts", sizeof(pbuf)); |
692 | | | 676 | |
693 | /* | | 677 | /* |
694 | * Change effective uid while opening and reading .rhosts. | | 678 | * Change effective uid while opening and reading .rhosts. |
695 | * If root and reading an NFS mounted file system, can't | | 679 | * If root and reading an NFS mounted file system, can't |
696 | * read files that are protected read/write owner only. | | 680 | * read files that are protected read/write owner only. |
697 | */ | | 681 | */ |
698 | uid = geteuid(); | | 682 | uid = geteuid(); |
699 | gid = getegid(); | | 683 | gid = getegid(); |
700 | (void)setegid(pwd->pw_gid); | | 684 | (void)setegid(pwd->pw_gid); |
701 | initgroups(pwd->pw_name, pwd->pw_gid); | | 685 | initgroups(pwd->pw_name, pwd->pw_gid); |
702 | (void)seteuid(pwd->pw_uid); | | 686 | (void)seteuid(pwd->pw_uid); |
| @@ -720,68 +704,63 @@ iruserok_sa(raddr, rlen, superuser, ruse | | | @@ -720,68 +704,63 @@ iruserok_sa(raddr, rlen, superuser, ruse |
720 | __rcmd_errstr = | | 704 | __rcmd_errstr = |
721 | ".rhosts writable by other than owner"; | | 705 | ".rhosts writable by other than owner"; |
722 | else | | 706 | else |
723 | isvaliduser = | | 707 | isvaliduser = |
724 | __ivaliduser_sa(hostf, sa, (socklen_t)rlen, | | 708 | __ivaliduser_sa(hostf, sa, (socklen_t)rlen, |
725 | luser, ruser); | | 709 | luser, ruser); |
726 | | | 710 | |
727 | (void)fclose(hostf); | | 711 | (void)fclose(hostf); |
728 | } | | 712 | } |
729 | (void)seteuid(uid); | | 713 | (void)seteuid(uid); |
730 | (void)setegid(gid); | | 714 | (void)setegid(gid); |
731 | | | 715 | |
732 | } | | 716 | } |
733 | return (isvaliduser); | | 717 | return isvaliduser; |
734 | } | | 718 | } |
735 | | | 719 | |
736 | /* | | 720 | /* |
737 | * XXX | | 721 | * XXX |
738 | * Don't make static, used by lpd(8). We will be able to change the function | | 722 | * Don't make static, used by lpd(8). We will be able to change the function |
739 | * into static function, when we bump libc major #. | | 723 | * into static function, when we bump libc major #. |
740 | * | | 724 | * |
741 | * Returns 0 if ok, -1 if not ok. | | 725 | * Returns 0 if ok, -1 if not ok. |
742 | */ | | 726 | */ |
743 | #ifdef notdef /*_LIBC*/ | | 727 | #ifdef notdef /*_LIBC*/ |
744 | static | | 728 | static |
745 | #endif | | 729 | #endif |
746 | int | | 730 | int |
747 | __ivaliduser(hostf, raddr, luser, ruser) | | 731 | __ivaliduser(FILE *hostf, u_int32_t raddr, const char *luser, |
748 | FILE *hostf; | | 732 | const char *ruser) |
749 | u_int32_t raddr; | | | |
750 | const char *luser, *ruser; | | | |
751 | { | | 733 | { |
752 | struct sockaddr_in ivusin; | | 734 | struct sockaddr_in ivusin; |
753 | | | 735 | |
754 | memset(&ivusin, 0, sizeof(ivusin)); | | 736 | memset(&ivusin, 0, sizeof(ivusin)); |
755 | ivusin.sin_family = AF_INET; | | 737 | ivusin.sin_family = AF_INET; |
756 | #ifdef BSD4_4 | | 738 | #ifdef BSD4_4 |
757 | ivusin.sin_len = sizeof(struct sockaddr_in); | | 739 | ivusin.sin_len = sizeof(ivusin); |
758 | #endif | | 740 | #endif |
759 | memcpy(&ivusin.sin_addr, &raddr, sizeof(ivusin.sin_addr)); | | 741 | memcpy(&ivusin.sin_addr, &raddr, sizeof(ivusin.sin_addr)); |
760 | return __ivaliduser_sa(hostf, (struct sockaddr *)(void *)&ivusin, | | 742 | return __ivaliduser_sa(hostf, (struct sockaddr *)(void *)&ivusin, |
761 | sizeof(struct sockaddr_in), luser, ruser); | | 743 | sizeof(ivusin), luser, ruser); |
762 | } | | 744 | } |
763 | | | 745 | |
764 | #ifdef notdef /*_LIBC*/ | | 746 | #ifdef notdef /*_LIBC*/ |
765 | static | | 747 | static |
766 | #endif | | 748 | #endif |
767 | int | | 749 | int |
768 | __ivaliduser_sa(hostf, raddr, salen, luser, ruser) | | 750 | __ivaliduser_sa(FILE *hostf, const struct sockaddr *raddr, socklen_t salen, |
769 | FILE *hostf; | | 751 | const char *luser, const char *ruser) |
770 | const struct sockaddr *raddr; | | | |
771 | socklen_t salen; | | | |
772 | const char *luser, *ruser; | | | |
773 | { | | 752 | { |
774 | register char *user, *p; | | 753 | char *user, *p; |
775 | int ch; | | 754 | int ch; |
776 | char buf[MAXHOSTNAMELEN + 128]; /* host + login */ | | 755 | char buf[MAXHOSTNAMELEN + 128]; /* host + login */ |
777 | const char *auser, *ahost; | | 756 | const char *auser, *ahost; |
778 | int hostok, userok; | | 757 | int hostok, userok; |
779 | char *rhost = NULL; | | 758 | char *rhost = NULL; |
780 | int firsttime = 1; | | 759 | int firsttime = 1; |
781 | char domain[MAXHOSTNAMELEN]; | | 760 | char domain[MAXHOSTNAMELEN]; |
782 | | | 761 | |
783 | getdomainname(domain, sizeof(domain)); | | 762 | getdomainname(domain, sizeof(domain)); |
784 | | | 763 | |
785 | _DIAGASSERT(hostf != NULL); | | 764 | _DIAGASSERT(hostf != NULL); |
786 | _DIAGASSERT(luser != NULL); | | 765 | _DIAGASSERT(luser != NULL); |
787 | _DIAGASSERT(ruser != NULL); | | 766 | _DIAGASSERT(ruser != NULL); |
| @@ -848,27 +827,28 @@ __ivaliduser_sa(hostf, raddr, salen, lus | | | @@ -848,27 +827,28 @@ __ivaliduser_sa(hostf, raddr, salen, lus |
848 | case '@': | | 827 | case '@': |
849 | if (firsttime) { | | 828 | if (firsttime) { |
850 | rhost = __gethostloop(raddr, salen); | | 829 | rhost = __gethostloop(raddr, salen); |
851 | firsttime = 0; | | 830 | firsttime = 0; |
852 | } | | 831 | } |
853 | if (rhost) | | 832 | if (rhost) |
854 | hostok = -innetgr(&ahost[2], rhost, | | 833 | hostok = -innetgr(&ahost[2], rhost, |
855 | NULL, domain); | | 834 | NULL, domain); |
856 | else | | 835 | else |
857 | hostok = 0; | | 836 | hostok = 0; |
858 | break; | | 837 | break; |
859 | | | 838 | |
860 | default: | | 839 | default: |
861 | hostok = -__icheckhost(raddr, salen, &ahost[1]); | | 840 | hostok = |
| | | 841 | -__icheckhost(raddr, salen, &ahost[1]); |
862 | break; | | 842 | break; |
863 | } | | 843 | } |
864 | else | | 844 | else |
865 | hostok = __icheckhost(raddr, salen, ahost); | | 845 | hostok = __icheckhost(raddr, salen, ahost); |
866 | | | 846 | |
867 | | | 847 | |
868 | if (auser[0] == '+') | | 848 | if (auser[0] == '+') |
869 | switch (auser[1]) { | | 849 | switch (auser[1]) { |
870 | case '\0': | | 850 | case '\0': |
871 | userok = 1; | | 851 | userok = 1; |
872 | break; | | 852 | break; |
873 | | | 853 | |
874 | case '@': | | 854 | case '@': |
| @@ -908,118 +888,111 @@ __ivaliduser_sa(hostf, raddr, salen, lus | | | @@ -908,118 +888,111 @@ __ivaliduser_sa(hostf, raddr, salen, lus |
908 | return -1; | | 888 | return -1; |
909 | | | 889 | |
910 | /* Check if we got a valid pair */ | | 890 | /* Check if we got a valid pair */ |
911 | if (hostok == 1 && userok == 1) | | 891 | if (hostok == 1 && userok == 1) |
912 | return 0; | | 892 | return 0; |
913 | } | | 893 | } |
914 | return -1; | | 894 | return -1; |
915 | } | | 895 | } |
916 | | | 896 | |
917 | /* | | 897 | /* |
918 | * Returns "true" if match, 0 if no match. | | 898 | * Returns "true" if match, 0 if no match. |
919 | */ | | 899 | */ |
920 | static int | | 900 | static int |
921 | __icheckhost(raddr, salen, lhost) | | 901 | __icheckhost(const struct sockaddr *raddr, socklen_t salen, const char *lhost) |
922 | const struct sockaddr *raddr; | | | |
923 | socklen_t salen; | | | |
924 | const char *lhost; | | | |
925 | { | | 902 | { |
926 | struct addrinfo hints, *res, *r; | | 903 | struct addrinfo hints, *res, *r; |
927 | char h1[NI_MAXHOST], h2[NI_MAXHOST]; | | 904 | char h1[NI_MAXHOST], h2[NI_MAXHOST]; |
928 | int error; | | 905 | int error; |
929 | const int niflags = NI_NUMERICHOST; | | 906 | const int niflags = NI_NUMERICHOST; |
930 | | | 907 | |
931 | _DIAGASSERT(raddr != NULL); | | 908 | _DIAGASSERT(raddr != NULL); |
932 | _DIAGASSERT(lhost != NULL); | | 909 | _DIAGASSERT(lhost != NULL); |
933 | | | 910 | |
934 | h1[0] = '\0'; | | 911 | h1[0] = '\0'; |
935 | if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0, | | 912 | if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0, niflags) != 0) |
936 | niflags) != 0) | | 913 | return 0; |
937 | return (0); | | | |
938 | | | 914 | |
939 | /* Resolve laddr into sockaddr */ | | 915 | /* Resolve laddr into sockaddr */ |
940 | memset(&hints, 0, sizeof(hints)); | | 916 | memset(&hints, 0, sizeof(hints)); |
941 | hints.ai_family = raddr->sa_family; | | 917 | hints.ai_family = raddr->sa_family; |
942 | hints.ai_socktype = SOCK_DGRAM; /*dummy*/ | | 918 | hints.ai_socktype = SOCK_DGRAM; /*dummy*/ |
943 | res = NULL; | | 919 | res = NULL; |
944 | error = getaddrinfo(lhost, "0", &hints, &res); | | 920 | error = getaddrinfo(lhost, "0", &hints, &res); |
945 | if (error) | | 921 | if (error) |
946 | return (0); | | 922 | return 0; |
947 | | | 923 | |
948 | /* | | 924 | /* |
949 | * Try string comparisons between raddr and laddr. | | 925 | * Try string comparisons between raddr and laddr. |
950 | */ | | 926 | */ |
951 | for (r = res; r; r = r->ai_next) { | | 927 | for (r = res; r; r = r->ai_next) { |
952 | h2[0] = '\0'; | | 928 | h2[0] = '\0'; |
953 | if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2), | | 929 | if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2), |
954 | NULL, 0, niflags) != 0) | | 930 | NULL, 0, niflags) != 0) |
955 | continue; | | 931 | continue; |
956 | if (strcmp(h1, h2) == 0) { | | 932 | if (strcmp(h1, h2) == 0) { |
957 | freeaddrinfo(res); | | 933 | freeaddrinfo(res); |
958 | return (1); | | 934 | return 1; |
959 | } | | 935 | } |
960 | } | | 936 | } |
961 | | | 937 | |
962 | /* No match. */ | | 938 | /* No match. */ |
963 | freeaddrinfo(res); | | 939 | freeaddrinfo(res); |
964 | return (0); | | 940 | return 0; |
965 | } | | 941 | } |
966 | | | 942 | |
967 | /* | | 943 | /* |
968 | * Return the hostname associated with the supplied address. | | 944 | * Return the hostname associated with the supplied address. |
969 | * Do a reverse lookup as well for security. If a loop cannot | | 945 | * Do a reverse lookup as well for security. If a loop cannot |
970 | * be found, pack the numeric IP address into the string. | | 946 | * be found, pack the numeric IP address into the string. |
971 | */ | | 947 | */ |
972 | static char * | | 948 | static char * |
973 | __gethostloop(raddr, salen) | | 949 | __gethostloop(const struct sockaddr *raddr, socklen_t salen) |
974 | const struct sockaddr *raddr; | | | |
975 | socklen_t salen; | | | |
976 | { | | 950 | { |
977 | static char remotehost[NI_MAXHOST]; | | 951 | static char remotehost[NI_MAXHOST]; |
978 | char h1[NI_MAXHOST], h2[NI_MAXHOST]; | | 952 | char h1[NI_MAXHOST], h2[NI_MAXHOST]; |
979 | struct addrinfo hints, *res, *r; | | 953 | struct addrinfo hints, *res, *r; |
980 | int error; | | 954 | int error; |
981 | const int niflags = NI_NUMERICHOST; | | 955 | const int niflags = NI_NUMERICHOST; |
982 | | | 956 | |
983 | _DIAGASSERT(raddr != NULL); | | 957 | _DIAGASSERT(raddr != NULL); |
984 | | | 958 | |
985 | h1[0] = remotehost[0] = '\0'; | | 959 | h1[0] = remotehost[0] = '\0'; |
986 | if (getnameinfo(raddr, salen, remotehost, sizeof(remotehost), | | 960 | if (getnameinfo(raddr, salen, remotehost, sizeof(remotehost), |
987 | NULL, 0, NI_NAMEREQD) != 0) | | 961 | NULL, 0, NI_NAMEREQD) != 0) |
988 | return (NULL); | | 962 | return NULL; |
989 | if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0, | | 963 | if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0, niflags) != 0) |
990 | niflags) != 0) | | 964 | return NULL; |
991 | return (NULL); | | | |
992 | | | 965 | |
993 | /* | | 966 | /* |
994 | * Look up the name and check that the supplied | | 967 | * Look up the name and check that the supplied |
995 | * address is in the list | | 968 | * address is in the list |
996 | */ | | 969 | */ |
997 | memset(&hints, 0, sizeof(hints)); | | 970 | memset(&hints, 0, sizeof(hints)); |
998 | hints.ai_family = raddr->sa_family; | | 971 | hints.ai_family = raddr->sa_family; |
999 | hints.ai_socktype = SOCK_DGRAM; /*dummy*/ | | 972 | hints.ai_socktype = SOCK_DGRAM; /*dummy*/ |
1000 | hints.ai_flags = AI_CANONNAME; | | 973 | hints.ai_flags = AI_CANONNAME; |
1001 | res = NULL; | | 974 | res = NULL; |
1002 | error = getaddrinfo(remotehost, "0", &hints, &res); | | 975 | error = getaddrinfo(remotehost, "0", &hints, &res); |
1003 | if (error) | | 976 | if (error) |
1004 | return (NULL); | | 977 | return NULL; |
1005 | | | 978 | |
1006 | for (r = res; r; r = r->ai_next) { | | 979 | for (r = res; r; r = r->ai_next) { |
1007 | h2[0] = '\0'; | | 980 | h2[0] = '\0'; |
1008 | if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2), | | 981 | if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2), |
1009 | NULL, 0, niflags) != 0) | | 982 | NULL, 0, niflags) != 0) |
1010 | continue; | | 983 | continue; |
1011 | if (strcmp(h1, h2) == 0) { | | 984 | if (strcmp(h1, h2) == 0) { |
1012 | freeaddrinfo(res); | | 985 | freeaddrinfo(res); |
1013 | return (remotehost); | | 986 | return remotehost; |
1014 | } | | 987 | } |
1015 | } | | 988 | } |
1016 | | | 989 | |
1017 | /* | | 990 | /* |
1018 | * either the DNS adminstrator has made a configuration | | 991 | * either the DNS adminstrator has made a configuration |
1019 | * mistake, or someone has attempted to spoof us | | 992 | * mistake, or someone has attempted to spoof us |
1020 | */ | | 993 | */ |
1021 | syslog(LOG_NOTICE, "rcmd: address %s not listed for host %s", | | 994 | syslog(LOG_NOTICE, "rcmd: address %s not listed for host %s", |
1022 | h1, res->ai_canonname ? res->ai_canonname : remotehost); | | 995 | h1, res->ai_canonname ? res->ai_canonname : remotehost); |
1023 | freeaddrinfo(res); | | 996 | freeaddrinfo(res); |
1024 | return (NULL); | | 997 | return NULL; |
1025 | } | | 998 | } |