summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/rcmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/net/rcmd.c')
-rw-r--r--src/lib/libc/net/rcmd.c297
1 files changed, 221 insertions, 76 deletions
diff --git a/src/lib/libc/net/rcmd.c b/src/lib/libc/net/rcmd.c
index bd920faadb..79892bd5a1 100644
--- a/src/lib/libc/net/rcmd.c
+++ b/src/lib/libc/net/rcmd.c
@@ -34,7 +34,7 @@
34 */ 34 */
35 35
36#if defined(LIBC_SCCS) && !defined(lint) 36#if defined(LIBC_SCCS) && !defined(lint)
37static char *rcsid = "$OpenBSD: rcmd.c,v 1.32 1999/12/16 21:30:34 deraadt Exp $"; 37static char *rcsid = "$OpenBSD: rcmd.c,v 1.33 2000/01/27 05:18:47 itojun Exp $";
38#endif /* LIBC_SCCS and not lint */ 38#endif /* LIBC_SCCS and not lint */
39 39
40#include <sys/param.h> 40#include <sys/param.h>
@@ -58,8 +58,9 @@ static char *rcsid = "$OpenBSD: rcmd.c,v 1.32 1999/12/16 21:30:34 deraadt Exp $"
58#include <netgroup.h> 58#include <netgroup.h>
59 59
60int __ivaliduser __P((FILE *, in_addr_t, const char *, const char *)); 60int __ivaliduser __P((FILE *, in_addr_t, const char *, const char *));
61static int __icheckhost __P((u_int32_t, const char *)); 61int __ivaliduser_sa __P((FILE *, struct sockaddr *, const char *, const char *));
62static char *__gethostloop __P((u_int32_t)); 62static int __icheckhost __P((struct sockaddr *, const char *));
63static char *__gethostloop __P((struct sockaddr *));
63 64
64int 65int
65rcmd(ahost, rport, locuser, remuser, cmd, fd2p) 66rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
@@ -68,8 +69,22 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
68 const char *locuser, *remuser, *cmd; 69 const char *locuser, *remuser, *cmd;
69 int *fd2p; 70 int *fd2p;
70{ 71{
71 struct hostent *hp; 72 return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
72 struct sockaddr_in sin, from; 73}
74
75int
76rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, af)
77 char **ahost;
78 in_port_t rport;
79 const char *locuser, *remuser, *cmd;
80 int *fd2p;
81 int af;
82{
83 static char hbuf[MAXHOSTNAMELEN];
84 char pbuf[NI_MAXSERV];
85 struct addrinfo hints, *res, *r;
86 int error;
87 struct sockaddr_storage from;
73 fd_set *readsp = NULL; 88 fd_set *readsp = NULL;
74 int oldmask; 89 int oldmask;
75 pid_t pid; 90 pid_t pid;
@@ -95,16 +110,29 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
95 } 110 }
96 111
97 pid = getpid(); 112 pid = getpid();
98 hp = gethostbyname(*ahost); 113 snprintf(pbuf, sizeof(pbuf), "%u", ntohs(rport));
99 if (hp == NULL) { 114 memset(&hints, 0, sizeof(hints));
100 herror(*ahost); 115 hints.ai_family = af;
116 hints.ai_socktype = SOCK_STREAM;
117 hints.ai_flags = AI_CANONNAME;
118 error = getaddrinfo(*ahost, pbuf, &hints, &res);
119 if (error) {
120#if 0
121 warnx("%s: %s", *ahost, gai_strerror(error));
122#endif
101 return (-1); 123 return (-1);
102 } 124 }
103 *ahost = hp->h_name; 125 if (res->ai_canonname) {
104 126 strncpy(hbuf, res->ai_canonname, sizeof(hbuf) - 1);
127 hbuf[sizeof(hbuf) - 1] = '\0';
128 *ahost = hbuf;
129 } else
130 ; /*XXX*/
131
132 r = res;
105 oldmask = sigblock(sigmask(SIGURG)); 133 oldmask = sigblock(sigmask(SIGURG));
106 for (timo = 1, lport = IPPORT_RESERVED - 1;;) { 134 for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
107 s = rresvport(&lport); 135 s = rresvport_af(&lport, r->ai_family);
108 if (s < 0) { 136 if (s < 0) {
109 if (errno == EAGAIN) 137 if (errno == EAGAIN)
110 (void)fprintf(stderr, 138 (void)fprintf(stderr,
@@ -113,15 +141,11 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
113 (void)fprintf(stderr, "rcmd: socket: %s\n", 141 (void)fprintf(stderr, "rcmd: socket: %s\n",
114 strerror(errno)); 142 strerror(errno));
115 sigsetmask(oldmask); 143 sigsetmask(oldmask);
144 freeaddrinfo(res);
116 return (-1); 145 return (-1);
117 } 146 }
118 fcntl(s, F_SETOWN, pid); 147 fcntl(s, F_SETOWN, pid);
119 bzero(&sin, sizeof sin); 148 if (connect(s, r->ai_addr, r->ai_addrlen) >= 0)
120 sin.sin_len = sizeof(struct sockaddr_in);
121 sin.sin_family = hp->h_addrtype;
122 sin.sin_port = rport;
123 bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length);
124 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
125 break; 149 break;
126 (void)close(s); 150 (void)close(s);
127 if (errno == EADDRINUSE) { 151 if (errno == EADDRINUSE) {
@@ -133,23 +157,39 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
133 timo *= 2; 157 timo *= 2;
134 continue; 158 continue;
135 } 159 }
136 if (hp->h_addr_list[1] != NULL) { 160 if (r->ai_next) {
137 int oerrno = errno; 161 int oerrno = errno;
162 char hbuf[NI_MAXHOST];
163#ifdef NI_WITHSCOPEID
164 const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
165#else
166 const int niflags = NI_NUMERICHOST;
167#endif
138 168
139 (void)fprintf(stderr, "connect to address %s: ", 169 hbuf[0] = '\0';
140 inet_ntoa(sin.sin_addr)); 170 if (getnameinfo(r->ai_addr, r->ai_addrlen,
171 hbuf, sizeof(hbuf), NULL, 0, niflags) != 0)
172 strcpy(hbuf, "(invalid)");
173 (void)fprintf(stderr, "connect to address %s: ", hbuf);
141 errno = oerrno; 174 errno = oerrno;
142 perror(0); 175 perror(0);
143 hp->h_addr_list++; 176 r = r->ai_next;
144 bcopy(hp->h_addr_list[0], &sin.sin_addr, hp->h_length); 177 hbuf[0] = '\0';
145 (void)fprintf(stderr, "Trying %s...\n", 178 if (getnameinfo(r->ai_addr, r->ai_addrlen,
146 inet_ntoa(sin.sin_addr)); 179 hbuf, sizeof(hbuf), NULL, 0, niflags) != 0)
180 strcpy(hbuf, "(invalid)");
181 (void)fprintf(stderr, "Trying %s...\n", hbuf);
147 continue; 182 continue;
148 } 183 }
149 (void)fprintf(stderr, "%s: %s\n", hp->h_name, strerror(errno)); 184 (void)fprintf(stderr, "%s: %s\n", res->ai_canonname,
185 strerror(errno));
150 sigsetmask(oldmask); 186 sigsetmask(oldmask);
187 freeaddrinfo(res);
151 return (-1); 188 return (-1);
152 } 189 }
190 /* given "af" can be PF_UNSPEC, we need the real af for "s" */
191 af = r->ai_family;
192 freeaddrinfo(res);
153#if 0 193#if 0
154 /* 194 /*
155 * try to rresvport() to the same port. This will make rresvport() 195 * try to rresvport() to the same port. This will make rresvport()
@@ -162,7 +202,7 @@ rcmd(ahost, rport, locuser, remuser, cmd, fd2p)
162 lport = 0; 202 lport = 0;
163 } else { 203 } else {
164 char num[8]; 204 char num[8];
165 int s2 = rresvport(&lport), s3; 205 int s2 = rresvport_af(&lport, af), s3;
166 int len = sizeof(from); 206 int len = sizeof(from);
167 int fdssize = howmany(MAX(s, s2)+1, NFDBITS) * sizeof(fd_mask); 207 int fdssize = howmany(MAX(s, s2)+1, NFDBITS) * sizeof(fd_mask);
168 208
@@ -202,9 +242,18 @@ again:
202 * XXX careful for ftp bounce attacks. If discovered, shut them 242 * XXX careful for ftp bounce attacks. If discovered, shut them
203 * down and check for the real auxiliary channel to connect. 243 * down and check for the real auxiliary channel to connect.
204 */ 244 */
205 if (from.sin_family == AF_INET && from.sin_port == htons(20)) { 245 switch (from.ss_family) {
246 case AF_INET:
247 case AF_INET6:
248 if (getnameinfo((struct sockaddr *)&from, len,
249 NULL, 0, num, sizeof(num), NI_NUMERICSERV) == 0 &&
250 atoi(num) != 20) {
251 break;
252 }
206 close(s3); 253 close(s3);
207 goto again; 254 goto again;
255 default:
256 break;
208 } 257 }
209 (void)close(s2); 258 (void)close(s2);
210 if (s3 < 0) { 259 if (s3 < 0) {
@@ -214,13 +263,20 @@ again:
214 goto bad; 263 goto bad;
215 } 264 }
216 *fd2p = s3; 265 *fd2p = s3;
217 from.sin_port = ntohs(from.sin_port); 266 switch (from.ss_family) {
218 if (from.sin_family != AF_INET || 267 case AF_INET:
219 from.sin_port >= IPPORT_RESERVED || 268 case AF_INET6:
220 from.sin_port < IPPORT_RESERVED / 2) { 269 if (getnameinfo((struct sockaddr *)&from, len,
221 (void)fprintf(stderr, 270 NULL, 0, num, sizeof(num), NI_NUMERICSERV) != 0 ||
222 "socket: protocol failure in circuit setup.\n"); 271 (atoi(num) >= IPPORT_RESERVED ||
223 goto bad2; 272 atoi(num) < IPPORT_RESERVED / 2)) {
273 (void)fprintf(stderr,
274 "socket: protocol failure in circuit setup.\n");
275 goto bad2;
276 }
277 break;
278 default:
279 break;
224 } 280 }
225 } 281 }
226 (void)write(s, locuser, strlen(locuser)+1); 282 (void)write(s, locuser, strlen(locuser)+1);
@@ -261,21 +317,24 @@ ruserok(rhost, superuser, ruser, luser)
261 const char *rhost, *ruser, *luser; 317 const char *rhost, *ruser, *luser;
262 int superuser; 318 int superuser;
263{ 319{
264 struct hostent *hp; 320 struct addrinfo hints, *res, *r;
265 char **ap; 321 int error;
266 int i; 322
267#define MAXADDRS 35 323 memset(&hints, 0, sizeof(hints));
268 u_int32_t addrs[MAXADDRS + 1]; 324 hints.ai_family = PF_UNSPEC;
269 325 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
270 if ((hp = gethostbyname(rhost)) == NULL) 326 error = getaddrinfo(rhost, "0", &hints, &res);
327 if (error)
271 return (-1); 328 return (-1);
272 for (i = 0, ap = hp->h_addr_list; *ap && i < MAXADDRS; ++ap, ++i)
273 bcopy(*ap, &addrs[i], sizeof(addrs[i]));
274 addrs[i] = 0;
275 329
276 for (i = 0; i < MAXADDRS && addrs[i]; i++) 330 for (r = res; r; r = r->ai_next) {
277 if (iruserok((in_addr_t)addrs[i], superuser, ruser, luser) == 0) 331 if (iruserok_sa(r->ai_addr, r->ai_addrlen, superuser, ruser,
332 luser) == 0) {
333 freeaddrinfo(res);
278 return (0); 334 return (0);
335 }
336 }
337 freeaddrinfo(res);
279 return (-1); 338 return (-1);
280} 339}
281 340
@@ -294,6 +353,24 @@ iruserok(raddr, superuser, ruser, luser)
294 int superuser; 353 int superuser;
295 const char *ruser, *luser; 354 const char *ruser, *luser;
296{ 355{
356 struct sockaddr_in sin;
357
358 memset(&sin, 0, sizeof(sin));
359 sin.sin_family = AF_INET;
360 sin.sin_len = sizeof(struct sockaddr_in);
361 memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
362 return iruserok_sa(&sin, sizeof(struct sockaddr_in), superuser, ruser,
363 luser);
364}
365
366int
367iruserok_sa(raddr, rlen, superuser, ruser, luser)
368 const void *raddr;
369 int rlen;
370 int superuser;
371 const char *ruser, *luser;
372{
373 struct sockaddr *sa;
297 register char *cp; 374 register char *cp;
298 struct stat sbuf; 375 struct stat sbuf;
299 struct passwd *pwd; 376 struct passwd *pwd;
@@ -302,11 +379,15 @@ iruserok(raddr, superuser, ruser, luser)
302 int first; 379 int first;
303 char pbuf[MAXPATHLEN]; 380 char pbuf[MAXPATHLEN];
304 381
382 sa = (struct sockaddr *)raddr;
383#ifdef lint
384 rlen = rlen;
385#endif
305 first = 1; 386 first = 1;
306 hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r"); 387 hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "r");
307again: 388again:
308 if (hostf) { 389 if (hostf) {
309 if (__ivaliduser(hostf, raddr, luser, ruser) == 0) { 390 if (__ivaliduser_sa(hostf, sa, luser, ruser) == 0) {
310 (void)fclose(hostf); 391 (void)fclose(hostf);
311 return (0); 392 return (0);
312 } 393 }
@@ -369,13 +450,27 @@ __ivaliduser(hostf, raddrl, luser, ruser)
369 in_addr_t raddrl; 450 in_addr_t raddrl;
370 const char *luser, *ruser; 451 const char *luser, *ruser;
371{ 452{
453 struct sockaddr_in sin;
454
455 memset(&sin, 0, sizeof(sin));
456 sin.sin_family = AF_INET;
457 sin.sin_len = sizeof(struct sockaddr_in);
458 memcpy(&sin.sin_addr, &raddrl, sizeof(sin.sin_addr));
459 return __ivaliduser_sa(hostf, (struct sockaddr *)&sin, luser, ruser);
460}
461
462int
463__ivaliduser_sa(hostf, raddr, luser, ruser)
464 FILE *hostf;
465 struct sockaddr *raddr;
466 const char *luser, *ruser;
467{
372 register char *user, *p; 468 register char *user, *p;
373 char *buf; 469 char *buf;
374 const char *auser, *ahost; 470 const char *auser, *ahost;
375 int hostok, userok; 471 int hostok, userok;
376 char *rhost = (char *)-1; 472 char *rhost = (char *)-1;
377 char domain[MAXHOSTNAMELEN]; 473 char domain[MAXHOSTNAMELEN];
378 u_int32_t raddr = (u_int32_t)raddrl;
379 size_t buflen; 474 size_t buflen;
380 475
381 getdomainname(domain, sizeof(domain)); 476 getdomainname(domain, sizeof(domain));
@@ -509,27 +604,54 @@ bail:
509/* 604/*
510 * Returns "true" if match, 0 if no match. If we do not find any 605 * Returns "true" if match, 0 if no match. If we do not find any
511 * semblance of an A->PTR->A loop, allow a simple #.#.#.# match to work. 606 * semblance of an A->PTR->A loop, allow a simple #.#.#.# match to work.
607 *
608 * NI_WITHSCOPEID is useful for comparing sin6_scope_id portion
609 * if af == AF_INET6.
512 */ 610 */
513static int 611static int
514__icheckhost(raddr, lhost) 612__icheckhost(raddr, lhost)
515 u_int32_t raddr; 613 struct sockaddr *raddr;
516 const char *lhost; 614 const char *lhost;
517{ 615{
518 register struct hostent *hp; 616 struct addrinfo hints, *res, *r;
519 register char **pp; 617 char h1[NI_MAXHOST], h2[NI_MAXHOST];
520 struct in_addr in; 618 int error;
521 619#ifdef NI_WITHSCOPEID
522 hp = gethostbyname(lhost); 620 const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
523 if (hp != NULL) { 621#else
524 /* Spin through ip addresses. */ 622 const int niflags = NI_NUMERICHOST;
525 for (pp = hp->h_addr_list; *pp; ++pp) 623#endif
526 if (!bcmp(&raddr, *pp, sizeof(raddr))) 624
527 return (1); 625 h1[0] = '\0';
626 if (getnameinfo(raddr, raddr->sa_len, h1, sizeof(h1), NULL, 0,
627 niflags) != 0)
628 return (0);
629
630 /* Resolve laddr into sockaddr */
631 memset(&hints, 0, sizeof(hints));
632 hints.ai_family = raddr->sa_family;
633 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
634 res = NULL;
635 error = getaddrinfo(lhost, "0", &hints, &res);
636 if (error)
637 return (0);
638
639 /*
640 * Try string comparisons between raddr and laddr.
641 */
642 for (r = res; r; r = r->ai_next) {
643 h2[0] = '\0';
644 if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2),
645 NULL, 0, niflags) != 0)
646 continue;
647 if (strcmp(h1, h2) == 0) {
648 freeaddrinfo(res);
649 return (1);
650 }
528 } 651 }
529 652
530 in.s_addr = raddr; 653 /* No match. */
531 if (strcmp(lhost, inet_ntoa(in)) == 0) 654 freeaddrinfo(res);
532 return (1);
533 return (0); 655 return (0);
534} 656}
535 657
@@ -537,39 +659,62 @@ __icheckhost(raddr, lhost)
537 * Return the hostname associated with the supplied address. 659 * Return the hostname associated with the supplied address.
538 * Do a reverse lookup as well for security. If a loop cannot 660 * Do a reverse lookup as well for security. If a loop cannot
539 * be found, pack the result of inet_ntoa() into the string. 661 * be found, pack the result of inet_ntoa() into the string.
662 *
663 * NI_WITHSCOPEID is useful for comparing sin6_scope_id portion
664 * if af == AF_INET6.
540 */ 665 */
541static char * 666static char *
542__gethostloop(raddr) 667__gethostloop(raddr)
543 u_int32_t raddr; 668 struct sockaddr *raddr;
544{ 669{
545 static char remotehost[MAXHOSTNAMELEN]; 670 static char remotehost[NI_MAXHOST];
546 struct hostent *hp; 671 char h1[NI_MAXHOST], h2[NI_MAXHOST];
547 struct in_addr in; 672 struct addrinfo hints, *res, *r;
673 int error;
674#ifdef NI_WITHSCOPEID
675 const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
676#else
677 const int niflags = NI_NUMERICHOST;
678#endif
548 679
549 hp = gethostbyaddr((char *) &raddr, sizeof(raddr), AF_INET); 680 h1[0] = remotehost[0] = '\0';
550 if (hp == NULL) 681 if (getnameinfo(raddr, raddr->sa_len, remotehost, sizeof(remotehost),
682 NULL, 0, NI_NAMEREQD) != 0)
683 return (NULL);
684 if (getnameinfo(raddr, raddr->sa_len, h1, sizeof(h1), NULL, 0,
685 niflags) != 0)
551 return (NULL); 686 return (NULL);
552 687
553 /* 688 /*
554 * Look up the name and check that the supplied 689 * Look up the name and check that the supplied
555 * address is in the list 690 * address is in the list
556 */ 691 */
557 strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 692 memset(&hints, 0, sizeof(hints));
558 remotehost[sizeof(remotehost) - 1] = '\0'; 693 hints.ai_family = raddr->sa_family;
559 hp = gethostbyname(remotehost); 694 hints.ai_socktype = SOCK_DGRAM; /*dummy*/
560 if (hp == NULL) 695 hints.ai_flags = AI_CANONNAME;
696 res = NULL;
697 error = getaddrinfo(remotehost, "0", &hints, &res);
698 if (error)
561 return (NULL); 699 return (NULL);
562 700
563 for (; hp->h_addr_list[0] != NULL; hp->h_addr_list++) 701 for (r = res; r; r = r->ai_next) {
564 if (!bcmp(hp->h_addr_list[0], (caddr_t)&raddr, sizeof(raddr))) 702 h2[0] = '\0';
703 if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2),
704 NULL, 0, niflags) != 0)
705 continue;
706 if (strcmp(h1, h2) == 0) {
707 freeaddrinfo(res);
565 return (remotehost); 708 return (remotehost);
709 }
710 }
566 711
567 /* 712 /*
568 * either the DNS adminstrator has made a configuration 713 * either the DNS adminstrator has made a configuration
569 * mistake, or someone has attempted to spoof us 714 * mistake, or someone has attempted to spoof us
570 */ 715 */
571 in.s_addr = raddr;
572 syslog(LOG_NOTICE, "rcmd: address %s not listed for host %s", 716 syslog(LOG_NOTICE, "rcmd: address %s not listed for host %s",
573 inet_ntoa(in), hp->h_name); 717 h1, res->ai_canonname ? res->ai_canonname : remotehost);
718 freeaddrinfo(res);
574 return (NULL); 719 return (NULL);
575} 720}