1 /* $NetBSD: rlogind.c,v 1.24 2001/02/04 22:14:13 christos Exp $ */ 2 3 /* 4 * Copyright (C) 1998 WIDE Project. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by WIDE Project and 18 * its contributors. 19 * 4. Neither the name of the project nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 /*- 37 * Copyright (c) 1983, 1988, 1989, 1993 38 * The Regents of the University of California. All rights reserved. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 3. All advertising materials mentioning features or use of this software 49 * must display the following acknowledgement: 50 * This product includes software developed by the University of 51 * California, Berkeley and its contributors. 52 * 4. Neither the name of the University nor the names of its contributors 53 * may be used to endorse or promote products derived from this software 54 * without specific prior written permission. 55 * 56 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 57 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 58 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 59 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 60 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 61 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 62 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 63 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 64 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 65 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 66 * SUCH DAMAGE. 67 */ 68 69 #include <sys/cdefs.h> 70 #ifndef lint 71 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1989, 1993\n\ 72 The Regents of the University of California. All rights reserved.\n"); 73 #if 0 74 static char sccsid[] = "@(#)rlogind.c 8.2 (Berkeley) 4/28/95"; 75 #else 76 __RCSID("$NetBSD: rlogind.c,v 1.24 2001/02/04 22:14:13 christos Exp $"); 77 #endif 78 #endif /* not lint */ 79 80 /* 81 * remote login server: 82 * \0 83 * remuser\0 84 * locuser\0 85 * terminal_type/speed\0 86 * data 87 */ 88 89 #define FD_SETSIZE 16 /* don't need many bits for select */ 90 #include <sys/param.h> 91 #include <sys/stat.h> 92 #include <sys/ioctl.h> 93 #include <signal.h> 94 #include <termios.h> 95 96 #include <sys/socket.h> 97 #include <netinet/in.h> 98 #include <netinet/in_systm.h> 99 #include <netinet/ip.h> 100 #include <arpa/inet.h> 101 #include <netdb.h> 102 103 #include <pwd.h> 104 #include <syslog.h> 105 #include <errno.h> 106 #include <stdio.h> 107 #include <unistd.h> 108 #include <stdlib.h> 109 #include <string.h> 110 #include <util.h> 111 #include <utmp.h> 112 #include "pathnames.h" 113 114 #ifndef TIOCPKT_WINDOW 115 #define TIOCPKT_WINDOW 0x80 116 #endif 117 118 #define OPTIONS "alnL" 119 120 char *env[2]; 121 #define NMAX 30 122 char lusername[NMAX+1], rusername[NMAX+1]; 123 static char term[64] = "TERM="; 124 #define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 125 int keepalive = 1; 126 int check_all = 0; 127 int log_success = 0; 128 129 struct passwd *pwd; 130 131 void doit __P((int, struct sockaddr *)); 132 int control __P((int, char *, int)); 133 void protocol __P((int, int)); 134 void cleanup __P((int)); 135 void fatal __P((int, char *, int)); 136 int do_rlogin __P((struct sockaddr *, char *)); 137 void getstr __P((char *, int, char *)); 138 void setup_term __P((int)); 139 #if 0 140 int do_krb_login __P((union sockunion *)); 141 #endif 142 void usage __P((void)); 143 int local_domain __P((char *)); 144 char *topdomain __P((char *)); 145 int main __P((int, char *[])); 146 147 extern int __check_rhosts_file; 148 extern char *__rcmd_errstr; /* syslog hook from libc/net/rcmd.c */ 149 extern char **environ; 150 151 int 152 main(argc, argv) 153 int argc; 154 char *argv[]; 155 { 156 struct sockaddr_storage from; 157 int ch, fromlen, on; 158 159 openlog("rlogind", LOG_PID, LOG_AUTH); 160 161 opterr = 0; 162 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 163 switch (ch) { 164 case 'a': 165 check_all = 1; 166 break; 167 case 'l': 168 __check_rhosts_file = 0; 169 break; 170 case 'n': 171 keepalive = 0; 172 break; 173 case 'L': 174 log_success = 1; 175 break; 176 case '?': 177 default: 178 usage(); 179 break; 180 } 181 argc -= optind; 182 argv += optind; 183 184 fromlen = sizeof (from); /* xxx */ 185 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 186 syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 187 fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 188 } 189 #ifdef INET6 190 if (((struct sockaddr *)&from)->sa_family == AF_INET6 && 191 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr) && 192 sizeof(struct sockaddr_in) <= sizeof(from)) { 193 struct sockaddr_in sin; 194 struct sockaddr_in6 *sin6; 195 const int off = sizeof(struct sockaddr_in6) - 196 sizeof(struct sockaddr_in); 197 198 sin6 = (struct sockaddr_in6 *)&from; 199 memset(&sin, 0, sizeof(sin)); 200 sin.sin_family = AF_INET; 201 sin.sin_len = sizeof(struct sockaddr_in); 202 memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[off], 203 sizeof(sin.sin_addr)); 204 memcpy(&from, &sin, sizeof(sin)); 205 fromlen = sin.sin_len; 206 } 207 #else 208 if (((struct sockaddr *)&from)->sa_family == AF_INET6 && 209 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&from)->sin6_addr)) { 210 char hbuf[NI_MAXHOST]; 211 if (getnameinfo((struct sockaddr *)&from, fromlen, hbuf, 212 sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) { 213 strncpy(hbuf, "invalid", sizeof(hbuf)); 214 } 215 syslog(LOG_ERR, "malformed \"from\" address (v4 mapped, %s)\n", 216 hbuf); 217 exit(1); 218 } 219 #endif 220 on = 1; 221 if (keepalive && 222 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 223 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 224 #if defined(IP_TOS) 225 if (((struct sockaddr *)&from)->sa_family == AF_INET) { 226 on = IPTOS_LOWDELAY; 227 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 228 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 229 } 230 #endif 231 doit(0, (struct sockaddr *)&from); 232 /* NOTREACHED */ 233 #ifdef __GNUC__ 234 exit(0); 235 #endif 236 } 237 238 int child; 239 int netf; 240 char line[MAXPATHLEN]; 241 int confirmed; 242 243 struct winsize win = { 0, 0, 0, 0 }; 244 245 246 void 247 doit(f, fromp) 248 int f; 249 struct sockaddr *fromp; 250 { 251 int master, pid, on = 1; 252 int authenticated = 0; 253 char utmphost[UT_HOSTSIZE + 1]; 254 char *hostname; 255 char hostnamebuf[2 * MAXHOSTNAMELEN + 1]; 256 char c; 257 char naddr[NI_MAXHOST]; 258 char saddr[NI_MAXHOST]; 259 char raddr[NI_MAXHOST]; 260 int af = fromp->sa_family; 261 u_int16_t *portp; 262 struct addrinfo hints, *res, *res0; 263 int gaierror; 264 #ifdef NI_WITHSCOPEID 265 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID; 266 #else 267 const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; 268 #endif 269 270 alarm(60); 271 read(f, &c, 1); 272 273 if (c != 0) 274 exit(1); 275 276 alarm(0); 277 switch (af) { 278 case AF_INET: 279 portp = &((struct sockaddr_in *)fromp)->sin_port; 280 break; 281 #ifdef INET6 282 case AF_INET6: 283 portp = &((struct sockaddr_in6 *)fromp)->sin6_port; 284 break; 285 #endif 286 default: 287 syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", af); 288 exit(1); 289 } 290 if (getnameinfo((struct sockaddr *)fromp, fromp->sa_len, 291 naddr, sizeof(naddr), NULL, 0, niflags) != 0) { 292 syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", af); 293 exit(1); 294 } 295 296 if (getnameinfo((struct sockaddr *)fromp, fromp->sa_len, 297 saddr, sizeof(saddr), NULL, 0, NI_NAMEREQD) == 0) { 298 /* 299 * If name returned by gethostbyaddr is in our domain, 300 * attempt to verify that we haven't been fooled by someone 301 * in a remote net; look up the name and check that this 302 * address corresponds to the name. 303 */ 304 hostname = saddr; 305 res0 = NULL; 306 if (check_all || local_domain(saddr)) { 307 strncpy(hostnamebuf, saddr, sizeof(hostnamebuf) - 1); 308 hostnamebuf[sizeof(hostnamebuf) - 1] = 0; 309 memset(&hints, 0, sizeof(hints)); 310 hints.ai_family = fromp->sa_family; 311 hints.ai_socktype = SOCK_STREAM; 312 hints.ai_flags = AI_CANONNAME; 313 gaierror = getaddrinfo(hostnamebuf, "0", &hints, &res0); 314 if (gaierror) { 315 syslog(LOG_NOTICE, 316 "Couldn't look up address for %s: %s", 317 hostnamebuf, gai_strerror(gaierror)); 318 hostname = naddr; 319 } else { 320 for (res = res0; res; res = res->ai_next) { 321 if (res->ai_family != fromp->sa_family) 322 continue; 323 if (res->ai_addrlen != fromp->sa_len) 324 continue; 325 if (getnameinfo(res->ai_addr, 326 res->ai_addrlen, 327 raddr, sizeof(raddr), NULL, 0, 328 niflags) == 0 329 && strcmp(naddr, raddr) == 0) { 330 hostname = res->ai_canonname 331 ? res->ai_canonname 332 : saddr; 333 break; 334 } 335 } 336 if (res == NULL) { 337 syslog(LOG_NOTICE, 338 "Host addr %s not listed for host %s", 339 naddr, res0->ai_canonname 340 ? res0->ai_canonname 341 : saddr); 342 hostname = naddr; 343 } 344 } 345 } 346 hostname = strncpy(hostnamebuf, hostname, 347 sizeof(hostnamebuf) - 1); 348 if (res0) 349 freeaddrinfo(res0); 350 } else 351 hostname = strncpy(hostnamebuf, naddr, 352 sizeof(hostnamebuf) - 1); 353 354 hostnamebuf[sizeof(hostnamebuf) - 1] = '\0'; 355 356 if (strlen(hostname) < sizeof(utmphost)) 357 (void)strcpy(utmphost, hostname); 358 else 359 (void)strncpy(utmphost, hostname, sizeof(utmphost)); 360 utmphost[sizeof(utmphost) - 1] = '\0'; 361 362 if (ntohs(*portp) >= IPPORT_RESERVED || 363 ntohs(*portp) < IPPORT_RESERVED/2) { 364 syslog(LOG_NOTICE, "Connection from %s on illegal port", 365 naddr); 366 fatal(f, "Permission denied", 0); 367 } 368 #ifdef IP_OPTIONS 369 if (fromp->sa_family == AF_INET) { 370 u_char optbuf[BUFSIZ/3], *cp; 371 char lbuf[BUFSIZ], *lp; 372 int optsize = sizeof(optbuf), ipproto; 373 struct protoent *ip; 374 375 if ((ip = getprotobyname("ip")) != NULL) 376 ipproto = ip->p_proto; 377 else 378 ipproto = IPPROTO_IP; 379 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 380 &optsize) == 0 && optsize != 0) { 381 lp = lbuf; 382 for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 383 sprintf(lp, " %2.2x", *cp); 384 syslog(LOG_NOTICE, 385 "Connection received using IP options (ignored):%s", 386 lbuf); 387 if (setsockopt(0, ipproto, IP_OPTIONS, 388 (char *)NULL, optsize) != 0) { 389 syslog(LOG_ERR, 390 "setsockopt IP_OPTIONS NULL: %m"); 391 exit(1); 392 } 393 } 394 } 395 #endif 396 if (do_rlogin(fromp, hostname) == 0) 397 authenticated++; 398 if (confirmed == 0) { 399 write(f, "", 1); 400 confirmed = 1; /* we sent the null! */ 401 } 402 netf = f; 403 404 pid = forkpty(&master, line, NULL, &win); 405 if (pid < 0) { 406 if (errno == ENOENT) 407 fatal(f, "Out of ptys", 0); 408 else 409 fatal(f, "Forkpty", 1); 410 } 411 if (pid == 0) { 412 if (f > 2) /* f should always be 0, but... */ 413 (void) close(f); 414 setup_term(0); 415 if (authenticated) 416 execl(_PATH_LOGIN, "login", "-p", 417 "-h", utmphost, "-f", "--", lusername, (char *)0); 418 else 419 execl(_PATH_LOGIN, "login", "-p", 420 "-h", utmphost, "--", lusername, (char *)0); 421 fatal(STDERR_FILENO, _PATH_LOGIN, 1); 422 /*NOTREACHED*/ 423 } 424 ioctl(f, FIONBIO, &on); 425 ioctl(master, FIONBIO, &on); 426 ioctl(master, TIOCPKT, &on); 427 signal(SIGCHLD, cleanup); 428 protocol(f, master); 429 signal(SIGCHLD, SIG_IGN); 430 cleanup(0); 431 } 432 433 char magic[2] = { 0377, 0377 }; 434 char oobdata[] = {TIOCPKT_WINDOW}; 435 436 /* 437 * Handle a "control" request (signaled by magic being present) 438 * in the data stream. For now, we are only willing to handle 439 * window size changes. 440 */ 441 int 442 control(pty, cp, n) 443 int pty; 444 char *cp; 445 int n; 446 { 447 struct winsize w; 448 449 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 450 return (0); 451 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 452 memmove(&w, cp+4, sizeof(w)); 453 w.ws_row = ntohs(w.ws_row); 454 w.ws_col = ntohs(w.ws_col); 455 w.ws_xpixel = ntohs(w.ws_xpixel); 456 w.ws_ypixel = ntohs(w.ws_ypixel); 457 (void)ioctl(pty, TIOCSWINSZ, &w); 458 return (4+sizeof (w)); 459 } 460 461 /* 462 * rlogin "protocol" machine. 463 */ 464 void 465 protocol(f, p) 466 int f, p; 467 { 468 char pibuf[1024+1], fibuf[1024], *pbp = NULL, *fbp = NULL; 469 /* XXX gcc above */ 470 int pcc = 0, fcc = 0; 471 int cc, nfd, n; 472 char cntl; 473 474 /* 475 * Must ignore SIGTTOU, otherwise we'll stop 476 * when we try and set slave pty's window shape 477 * (our controlling tty is the master pty). 478 */ 479 (void) signal(SIGTTOU, SIG_IGN); 480 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 481 if (f > p) 482 nfd = f + 1; 483 else 484 nfd = p + 1; 485 if (nfd > FD_SETSIZE) { 486 syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 487 fatal(f, "internal error (select mask too small)", 0); 488 } 489 for (;;) { 490 fd_set ibits, obits, ebits, *omask; 491 492 FD_ZERO(&ebits); 493 FD_ZERO(&ibits); 494 FD_ZERO(&obits); 495 omask = (fd_set *)NULL; 496 if (fcc) { 497 FD_SET(p, &obits); 498 omask = &obits; 499 } else 500 FD_SET(f, &ibits); 501 if (pcc >= 0) { 502 if (pcc) { 503 FD_SET(f, &obits); 504 omask = &obits; 505 } else 506 FD_SET(p, &ibits); 507 } 508 FD_SET(p, &ebits); 509 if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 510 if (errno == EINTR) 511 continue; 512 fatal(f, "select", 1); 513 } 514 if (n == 0) { 515 /* shouldn't happen... */ 516 sleep(5); 517 continue; 518 } 519 #define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 520 if (FD_ISSET(p, &ebits)) { 521 cc = read(p, &cntl, 1); 522 if (cc == 1 && pkcontrol(cntl)) { 523 cntl |= oobdata[0]; 524 send(f, &cntl, 1, MSG_OOB); 525 if (cntl & TIOCPKT_FLUSHWRITE) { 526 pcc = 0; 527 FD_CLR(p, &ibits); 528 } 529 } 530 } 531 if (FD_ISSET(f, &ibits)) { 532 fcc = read(f, fibuf, sizeof(fibuf)); 533 if (fcc < 0 && errno == EWOULDBLOCK) 534 fcc = 0; 535 else { 536 char *cp; 537 int left, n; 538 539 if (fcc <= 0) 540 break; 541 fbp = fibuf; 542 543 top: 544 for (cp = fibuf; cp < fibuf+fcc-1; cp++) 545 if (cp[0] == magic[0] && 546 cp[1] == magic[1]) { 547 left = fcc - (cp-fibuf); 548 n = control(p, cp, left); 549 if (n) { 550 left -= n; 551 if (left > 0) 552 memmove(cp, 553 cp+n, 554 left); 555 fcc -= n; 556 goto top; /* n^2 */ 557 } 558 } 559 FD_SET(p, &obits); /* try write */ 560 } 561 } 562 563 if (FD_ISSET(p, &obits) && fcc > 0) { 564 cc = write(p, fbp, fcc); 565 if (cc > 0) { 566 fcc -= cc; 567 fbp += cc; 568 } 569 } 570 571 if (FD_ISSET(p, &ibits)) { 572 pcc = read(p, pibuf, sizeof (pibuf)); 573 pbp = pibuf; 574 if (pcc < 0 && errno == EWOULDBLOCK) 575 pcc = 0; 576 else if (pcc <= 0) 577 break; 578 else if (pibuf[0] == 0) { 579 pbp++, pcc--; 580 FD_SET(f, &obits); /* try write */ 581 } else { 582 if (pkcontrol(pibuf[0])) { 583 pibuf[0] |= oobdata[0]; 584 send(f, &pibuf[0], 1, MSG_OOB); 585 } 586 pcc = 0; 587 } 588 } 589 if ((FD_ISSET(f, &obits)) && pcc > 0) { 590 cc = write(f, pbp, pcc); 591 if (cc < 0 && errno == EWOULDBLOCK) { 592 /* 593 * This happens when we try write after read 594 * from p, but some old kernels balk at large 595 * writes even when select returns true. 596 */ 597 if (!FD_ISSET(p, &ibits)) 598 sleep(5); 599 continue; 600 } 601 if (cc > 0) { 602 pcc -= cc; 603 pbp += cc; 604 } 605 } 606 } 607 } 608 609 void 610 cleanup(signo) 611 int signo; 612 { 613 char *p, c; 614 615 p = line + sizeof(_PATH_DEV) - 1; 616 if (logout(p)) 617 logwtmp(p, "", ""); 618 (void)chmod(line, 0666); 619 (void)chown(line, 0, 0); 620 c = *p; *p = 'p'; 621 (void)chmod(line, 0666); 622 (void)chown(line, 0, 0); 623 *p = c; 624 if (ttyaction(line, "rlogind", "root")) 625 syslog(LOG_ERR, "%s: ttyaction failed", line); 626 shutdown(netf, 2); 627 exit(1); 628 } 629 630 void 631 fatal(f, msg, syserr) 632 int f; 633 char *msg; 634 int syserr; 635 { 636 int len; 637 char buf[BUFSIZ], *bp = buf; 638 639 /* 640 * Prepend binary one to message if we haven't sent 641 * the magic null as confirmation. 642 */ 643 if (!confirmed) 644 *bp++ = '\01'; /* error indicator */ 645 if (syserr) 646 len = sprintf(bp, "rlogind: %s: %s.\r\n", 647 msg, strerror(errno)); 648 else 649 len = sprintf(bp, "rlogind: %s.\r\n", msg); 650 (void) write(f, buf, bp + len - buf); 651 exit(1); 652 } 653 654 int 655 do_rlogin(dest, host) 656 struct sockaddr *dest; 657 char *host; 658 { 659 int retval; 660 661 getstr(rusername, sizeof(rusername), "remuser too long"); 662 getstr(lusername, sizeof(lusername), "locuser too long"); 663 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 664 665 pwd = getpwnam(lusername); 666 if (pwd == NULL) { 667 syslog(LOG_INFO, 668 "%s@%s as %s: unknown login.", rusername, host, lusername); 669 return (-1); 670 } 671 672 retval = iruserok_sa(dest, dest->sa_len, pwd->pw_uid == 0, rusername, 673 lusername); 674 /* XXX put inet_ntoa(dest->sin_addr.s_addr) into all messages below */ 675 if (retval == 0) { 676 if (log_success) 677 syslog(LOG_INFO, "%s@%s as %s: iruserok succeeded", 678 rusername, host, lusername); 679 } else { 680 if (__rcmd_errstr) 681 syslog(LOG_INFO, "%s@%s as %s: iruserok failed (%s)", 682 rusername, host, lusername, __rcmd_errstr); 683 else 684 syslog(LOG_INFO, "%s@%s as %s: iruserok failed", 685 rusername, host, lusername); 686 } 687 return(retval); 688 } 689 690 void 691 getstr(buf, cnt, errmsg) 692 char *buf; 693 int cnt; 694 char *errmsg; 695 { 696 char c; 697 698 do { 699 if (read(0, &c, 1) != 1) 700 exit(1); 701 if (--cnt < 0) 702 fatal(STDOUT_FILENO, errmsg, 0); 703 *buf++ = c; 704 } while (c != 0); 705 } 706 707 708 void 709 setup_term(fd) 710 int fd; 711 { 712 char *cp = index(term+ENVSIZE, '/'); 713 char *speed; 714 struct termios tt; 715 716 #ifndef notyet 717 tcgetattr(fd, &tt); 718 if (cp) { 719 *cp++ = '\0'; 720 speed = cp; 721 cp = index(speed, '/'); 722 if (cp) 723 *cp++ = '\0'; 724 cfsetspeed(&tt, atoi(speed)); 725 } 726 727 tt.c_iflag = TTYDEF_IFLAG; 728 tt.c_oflag = TTYDEF_OFLAG; 729 tt.c_lflag = TTYDEF_LFLAG; 730 tcsetattr(fd, TCSAFLUSH, &tt); 731 #else 732 if (cp) { 733 *cp++ = '\0'; 734 speed = cp; 735 cp = index(speed, '/'); 736 if (cp) 737 *cp++ = '\0'; 738 tcgetattr(fd, &tt); 739 cfsetspeed(&tt, atoi(speed)); 740 tcsetattr(fd, TCSAFLUSH, &tt); 741 } 742 #endif 743 744 env[0] = term; 745 env[1] = 0; 746 environ = env; 747 } 748 749 750 void 751 usage() 752 { 753 syslog(LOG_ERR, "usage: rlogind [-alnL]"); 754 } 755 756 /* 757 * Check whether host h is in our local domain, 758 * defined as sharing the last two components of the domain part, 759 * or the entire domain part if the local domain has only one component. 760 * If either name is unqualified (contains no '.'), 761 * assume that the host is local, as it will be 762 * interpreted as such. 763 */ 764 int 765 local_domain(h) 766 char *h; 767 { 768 char localhost[MAXHOSTNAMELEN + 1]; 769 char *p1, *p2; 770 771 localhost[0] = 0; 772 (void) gethostname(localhost, sizeof(localhost)); 773 localhost[sizeof(localhost) - 1] = '\0'; 774 p1 = topdomain(localhost); 775 p2 = topdomain(h); 776 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 777 return (1); 778 return (0); 779 } 780 781 char * 782 topdomain(h) 783 char *h; 784 { 785 char *p; 786 char *maybe = NULL; 787 int dots = 0; 788 789 for (p = h + strlen(h); p >= h; p--) { 790 if (*p == '.') { 791 if (++dots == 2) 792 return (p); 793 maybe = p; 794 } 795 } 796 return (maybe); 797 } 798