rlogind.c revision 90377
1/*- 2 * Copyright (c) 1983, 1988, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35static const char copyright[] = 36"@(#) Copyright (c) 1983, 1988, 1989, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static const char sccsid[] = "@(#)rlogind.c 8.1 (Berkeley) 6/4/93"; 43#endif 44static const char rcsid[] = 45 "$FreeBSD: head/libexec/rlogind/rlogind.c 90377 2002-02-07 23:57:01Z imp $"; 46#endif /* not lint */ 47 48/* 49 * remote login server: 50 * \0 51 * remuser\0 52 * locuser\0 53 * terminal_type/speed\0 54 * data 55 */ 56 57#define FD_SETSIZE 16 /* don't need many bits for select */ 58#include <sys/types.h> 59#include <sys/param.h> 60#include <sys/stat.h> 61#include <sys/ioctl.h> 62#include <signal.h> 63#include <termios.h> 64 65#include <sys/socket.h> 66#include <netinet/in.h> 67#include <netinet/in_systm.h> 68#include <netinet/ip.h> 69#include <netinet/tcp.h> 70#include <arpa/inet.h> 71#include <netdb.h> 72 73#include <errno.h> 74#include <libutil.h> 75#include <pwd.h> 76#include <syslog.h> 77#include <stdio.h> 78#include <stdlib.h> 79#include <string.h> 80#include <unistd.h> 81#include "pathnames.h" 82 83 84#ifndef TIOCPKT_WINDOW 85#define TIOCPKT_WINDOW 0x80 86#endif 87 88#define ARGSTR "Dalnx" 89 90/* wrapper for KAME-special getnameinfo() */ 91#ifndef NI_WITHSCOPEID 92#define NI_WITHSCOPEID 0 93#endif 94 95char *env[2]; 96#define NMAX 30 97char lusername[NMAX+1], rusername[NMAX+1]; 98static char term[64] = "TERM="; 99#define ENVSIZE (sizeof("TERM=")-1) /* skip null for concatenation */ 100int keepalive = 1; 101int check_all = 0; 102int no_delay; 103 104struct passwd *pwd; 105 106union sockunion { 107 struct sockinet { 108 u_char si_len; 109 u_char si_family; 110 u_short si_port; 111 } su_si; 112 struct sockaddr_in su_sin; 113 struct sockaddr_in6 su_sin6; 114}; 115#define su_len su_si.si_len 116#define su_family su_si.si_family 117#define su_port su_si.si_port 118 119void doit(int, union sockunion *); 120int control(int, char *, int); 121void protocol(int, int); 122void cleanup(int); 123void fatal(int, char *, int); 124int do_rlogin(union sockunion *); 125void getstr(char *, int, char *); 126void setup_term(int); 127int do_krb_login(struct sockaddr_in *); 128void usage(void); 129 130 131int 132main(int argc, char *argv[]) 133{ 134 extern int __check_rhosts_file; 135 union sockunion from; 136 int ch, fromlen, on; 137 138 openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 139 140 opterr = 0; 141 while ((ch = getopt(argc, argv, ARGSTR)) != -1) 142 switch (ch) { 143 case 'D': 144 no_delay = 1; 145 break; 146 case 'a': 147 check_all = 1; 148 break; 149 case 'l': 150 __check_rhosts_file = 0; 151 break; 152 case 'n': 153 keepalive = 0; 154 break; 155#ifdef CRYPT 156 case 'x': 157 doencrypt = 1; 158 break; 159#endif 160 case '?': 161 default: 162 usage(); 163 break; 164 } 165 argc -= optind; 166 argv += optind; 167 168 fromlen = sizeof (from); 169 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 170 syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 171 fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 172 } 173 on = 1; 174 if (keepalive && 175 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 176 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 177 if (no_delay && 178 setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) 179 syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m"); 180 if (from.su_family == AF_INET) 181 { 182 on = IPTOS_LOWDELAY; 183 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 184 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 185 } 186 187 doit(0, &from); 188 return 0; 189} 190 191int child; 192int netf; 193char line[MAXPATHLEN]; 194int confirmed; 195 196struct winsize win = { 0, 0, 0, 0 }; 197 198 199void 200doit(int f, union sockunion *fromp) 201{ 202 int master, pid, on = 1; 203 int authenticated = 0; 204 char hostname[2 * MAXHOSTNAMELEN + 1]; 205 char nameinfo[2 * INET6_ADDRSTRLEN + 1]; 206 char c; 207 208 alarm(60); 209 read(f, &c, 1); 210 211 if (c != 0) 212 exit(1); 213 214 alarm(0); 215 216 realhostname_sa(hostname, sizeof(hostname) - 1, 217 (struct sockaddr *)fromp, fromp->su_len); 218 /* error check ? */ 219 fromp->su_port = ntohs((u_short)fromp->su_port); 220 hostname[sizeof(hostname) - 1] = '\0'; 221 222 { 223 if ((fromp->su_family != AF_INET 224#ifdef INET6 225 && fromp->su_family != AF_INET6 226#endif 227 ) || 228 fromp->su_port >= IPPORT_RESERVED || 229 fromp->su_port < IPPORT_RESERVED/2) { 230 getnameinfo((struct sockaddr *)fromp, 231 fromp->su_len, 232 nameinfo, sizeof(nameinfo), NULL, 0, 233 NI_NUMERICHOST|NI_WITHSCOPEID); 234 /* error check ? */ 235 syslog(LOG_NOTICE, "Connection from %s on illegal port", 236 nameinfo); 237 fatal(f, "Permission denied", 0); 238 } 239#ifdef IP_OPTIONS 240 if (fromp->su_family == AF_INET) 241 { 242 u_char optbuf[BUFSIZ/3]; 243 int optsize = sizeof(optbuf), ipproto, i; 244 struct protoent *ip; 245 246 if ((ip = getprotobyname("ip")) != NULL) 247 ipproto = ip->p_proto; 248 else 249 ipproto = IPPROTO_IP; 250 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 251 &optsize) == 0 && optsize != 0) { 252 for (i = 0; i < optsize; ) { 253 u_char c = optbuf[i]; 254 if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 255 syslog(LOG_NOTICE, 256 "Connection refused from %s with IP option %s", 257 inet_ntoa(fromp->su_sin.sin_addr), 258 c == IPOPT_LSRR ? "LSRR" : "SSRR"); 259 exit(1); 260 } 261 if (c == IPOPT_EOL) 262 break; 263 i += (c == IPOPT_NOP) ? 1 : optbuf[i+1]; 264 } 265 } 266 } 267#endif 268 if (do_rlogin(fromp) == 0) 269 authenticated++; 270 } 271 if (confirmed == 0) { 272 write(f, "", 1); 273 confirmed = 1; /* we sent the null! */ 274 } 275#ifdef CRYPT 276 if (doencrypt) 277 (void) des_enc_write(f, 278 SECURE_MESSAGE, 279 strlen(SECURE_MESSAGE), 280 schedule, &kdata->session); 281#endif 282 netf = f; 283 284 pid = forkpty(&master, line, NULL, &win); 285 if (pid < 0) { 286 if (errno == ENOENT) 287 fatal(f, "Out of ptys", 0); 288 else 289 fatal(f, "Forkpty", 1); 290 } 291 if (pid == 0) { 292 if (f > 2) /* f should always be 0, but... */ 293 (void) close(f); 294 setup_term(0); 295 if (*lusername=='-') { 296 syslog(LOG_ERR, "tried to pass user \"%s\" to login", 297 lusername); 298 fatal(STDERR_FILENO, "invalid user", 0); 299 } 300 if (authenticated) { 301 execl(_PATH_LOGIN, "login", "-p", 302 "-h", hostname, "-f", lusername, (char *)NULL); 303 } else 304 execl(_PATH_LOGIN, "login", "-p", 305 "-h", hostname, lusername, (char *)NULL); 306 fatal(STDERR_FILENO, _PATH_LOGIN, 1); 307 /*NOTREACHED*/ 308 } 309#ifdef CRYPT 310 /* 311 * If encrypted, don't turn on NBIO or the des read/write 312 * routines will croak. 313 */ 314 315 if (!doencrypt) 316#endif 317 ioctl(f, FIONBIO, &on); 318 ioctl(master, FIONBIO, &on); 319 ioctl(master, TIOCPKT, &on); 320 signal(SIGCHLD, cleanup); 321 protocol(f, master); 322 signal(SIGCHLD, SIG_IGN); 323 cleanup(0); 324} 325 326char magic[2] = { 0377, 0377 }; 327char oobdata[] = {TIOCPKT_WINDOW}; 328 329/* 330 * Handle a "control" request (signaled by magic being present) 331 * in the data stream. For now, we are only willing to handle 332 * window size changes. 333 */ 334int 335control(int pty, char *cp, int n) 336{ 337 struct winsize w; 338 339 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 340 return (0); 341 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 342 bcopy(cp+4, (char *)&w, sizeof(w)); 343 w.ws_row = ntohs(w.ws_row); 344 w.ws_col = ntohs(w.ws_col); 345 w.ws_xpixel = ntohs(w.ws_xpixel); 346 w.ws_ypixel = ntohs(w.ws_ypixel); 347 (void)ioctl(pty, TIOCSWINSZ, &w); 348 return (4+sizeof (w)); 349} 350 351/* 352 * rlogin "protocol" machine. 353 */ 354void 355protocol(int f, int p) 356{ 357 char pibuf[1024+1], fibuf[1024], *pbp = NULL, *fbp = NULL; 358 int pcc = 0, fcc = 0; 359 int cc, nfd, n; 360 char cntl; 361 362 /* 363 * Must ignore SIGTTOU, otherwise we'll stop 364 * when we try and set slave pty's window shape 365 * (our controlling tty is the master pty). 366 */ 367 (void) signal(SIGTTOU, SIG_IGN); 368 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 369 if (f > p) 370 nfd = f + 1; 371 else 372 nfd = p + 1; 373 if (nfd > FD_SETSIZE) { 374 syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 375 fatal(f, "internal error (select mask too small)", 0); 376 } 377 for (;;) { 378 fd_set ibits, obits, ebits, *omask; 379 380 FD_ZERO(&ebits); 381 FD_ZERO(&ibits); 382 FD_ZERO(&obits); 383 omask = (fd_set *)NULL; 384 if (fcc) { 385 FD_SET(p, &obits); 386 omask = &obits; 387 } else 388 FD_SET(f, &ibits); 389 if (pcc >= 0) { 390 if (pcc) { 391 FD_SET(f, &obits); 392 omask = &obits; 393 } else 394 FD_SET(p, &ibits); 395 } 396 FD_SET(p, &ebits); 397 if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 398 if (errno == EINTR) 399 continue; 400 fatal(f, "select", 1); 401 } 402 if (n == 0) { 403 /* shouldn't happen... */ 404 sleep(5); 405 continue; 406 } 407#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 408 if (FD_ISSET(p, &ebits)) { 409 cc = read(p, &cntl, 1); 410 if (cc == 1 && pkcontrol(cntl)) { 411 cntl |= oobdata[0]; 412 send(f, &cntl, 1, MSG_OOB); 413 if (cntl & TIOCPKT_FLUSHWRITE) { 414 pcc = 0; 415 FD_CLR(p, &ibits); 416 } 417 } 418 } 419 if (FD_ISSET(f, &ibits)) { 420#ifdef CRYPT 421 if (doencrypt) 422 fcc = des_enc_read(f, fibuf, sizeof(fibuf), 423 schedule, &kdata->session); 424 else 425#endif 426 fcc = read(f, fibuf, sizeof(fibuf)); 427 if (fcc < 0 && errno == EWOULDBLOCK) 428 fcc = 0; 429 else { 430 char *cp; 431 int left, n; 432 433 if (fcc <= 0) 434 break; 435 fbp = fibuf; 436 437 top: 438 for (cp = fibuf; cp < fibuf+fcc-1; cp++) 439 if (cp[0] == magic[0] && 440 cp[1] == magic[1]) { 441 left = fcc - (cp-fibuf); 442 n = control(p, cp, left); 443 if (n) { 444 left -= n; 445 if (left > 0) 446 bcopy(cp+n, cp, left); 447 fcc -= n; 448 goto top; /* n^2 */ 449 } 450 } 451 FD_SET(p, &obits); /* try write */ 452 } 453 } 454 455 if (FD_ISSET(p, &obits) && fcc > 0) { 456 cc = write(p, fbp, fcc); 457 if (cc > 0) { 458 fcc -= cc; 459 fbp += cc; 460 } 461 } 462 463 if (FD_ISSET(p, &ibits)) { 464 pcc = read(p, pibuf, sizeof (pibuf)); 465 pbp = pibuf; 466 if (pcc < 0 && errno == EWOULDBLOCK) 467 pcc = 0; 468 else if (pcc <= 0) 469 break; 470 else if (pibuf[0] == 0) { 471 pbp++, pcc--; 472#ifdef CRYPT 473 if (!doencrypt) 474#endif 475 FD_SET(f, &obits); /* try write */ 476 } else { 477 if (pkcontrol(pibuf[0])) { 478 pibuf[0] |= oobdata[0]; 479 send(f, &pibuf[0], 1, MSG_OOB); 480 } 481 pcc = 0; 482 } 483 } 484 if ((FD_ISSET(f, &obits)) && pcc > 0) { 485#ifdef CRYPT 486 if (doencrypt) 487 cc = des_enc_write(f, pbp, pcc, 488 schedule, &kdata->session); 489 else 490#endif 491 cc = write(f, pbp, pcc); 492 if (cc < 0 && errno == EWOULDBLOCK) { 493 /* 494 * This happens when we try write after read 495 * from p, but some old kernels balk at large 496 * writes even when select returns true. 497 */ 498 if (!FD_ISSET(p, &ibits)) 499 sleep(5); 500 continue; 501 } 502 if (cc > 0) { 503 pcc -= cc; 504 pbp += cc; 505 } 506 } 507 } 508} 509 510void 511cleanup(int signo) 512{ 513 char *p; 514 515 p = line + sizeof(_PATH_DEV) - 1; 516 if (logout(p)) 517 logwtmp(p, "", ""); 518 (void)chflags(line, 0); 519 (void)chmod(line, 0666); 520 (void)chown(line, 0, 0); 521 *p = 'p'; 522 (void)chflags(line, 0); 523 (void)chmod(line, 0666); 524 (void)chown(line, 0, 0); 525 shutdown(netf, 2); 526 exit(1); 527} 528 529void 530fatal(int f, char *msg, int syserr) 531{ 532 int len; 533 char buf[BUFSIZ], *bp = buf; 534 535 /* 536 * Prepend binary one to message if we haven't sent 537 * the magic null as confirmation. 538 */ 539 if (!confirmed) 540 *bp++ = '\01'; /* error indicator */ 541 if (syserr) 542 len = snprintf(bp, sizeof(buf), "rlogind: %s: %s.\r\n", 543 msg, strerror(errno)); 544 else 545 len = snprintf(bp, sizeof(buf), "rlogind: %s.\r\n", msg); 546 if (len < 0) 547 len = 0; 548 (void) write(f, buf, bp + len - buf); 549 exit(1); 550} 551 552int 553do_rlogin(union sockunion *dest) 554{ 555 556 getstr(rusername, sizeof(rusername), "remuser too long"); 557 getstr(lusername, sizeof(lusername), "locuser too long"); 558 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 559 560 pwd = getpwnam(lusername); 561 if (pwd == NULL) 562 return (-1); 563 /* XXX why don't we syslog() failure? */ 564 565 return (iruserok_sa(dest, dest->su_len, pwd->pw_uid == 0, rusername, 566 lusername)); 567} 568 569void 570getstr(char *buf, int cnt, char *errmsg) 571{ 572 char c; 573 574 do { 575 if (read(STDIN_FILENO, &c, 1) != 1) 576 exit(1); 577 if (--cnt < 0) 578 fatal(STDOUT_FILENO, errmsg, 0); 579 *buf++ = c; 580 } while (c != 0); 581} 582 583extern char **environ; 584 585void 586setup_term(int fd) 587{ 588 char *cp = index(term+ENVSIZE, '/'); 589 char *speed; 590 struct termios tt; 591 592#ifndef notyet 593 tcgetattr(fd, &tt); 594 if (cp) { 595 *cp++ = '\0'; 596 speed = cp; 597 cp = index(speed, '/'); 598 if (cp) 599 *cp++ = '\0'; 600 cfsetspeed(&tt, atoi(speed)); 601 } 602 603 tt.c_iflag = TTYDEF_IFLAG; 604 tt.c_oflag = TTYDEF_OFLAG; 605 tt.c_lflag = TTYDEF_LFLAG; 606 tcsetattr(fd, TCSAFLUSH, &tt); 607#else 608 if (cp) { 609 *cp++ = '\0'; 610 speed = cp; 611 cp = index(speed, '/'); 612 if (cp) 613 *cp++ = '\0'; 614 tcgetattr(fd, &tt); 615 cfsetspeed(&tt, atoi(speed)); 616 tcsetattr(fd, TCSAFLUSH, &tt); 617 } 618#endif 619 620 env[0] = term; 621 env[1] = 0; 622 environ = env; 623} 624 625void 626usage(void) 627{ 628 syslog(LOG_ERR, "usage: rlogind [-" ARGSTR "]"); 629} 630