rlogind.c revision 67001
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 67001 2000-10-12 07:18:20Z ru $"; 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 __P((int, union sockunion *)); 120int control __P((int, char *, int)); 121void protocol __P((int, int)); 122void cleanup __P((int)); 123void fatal __P((int, char *, int)); 124int do_rlogin __P((union sockunion *)); 125void getstr __P((char *, int, char *)); 126void setup_term __P((int)); 127int do_krb_login __P((struct sockaddr_in *)); 128void usage __P((void)); 129 130 131int 132main(argc, argv) 133 int argc; 134 char *argv[]; 135{ 136 extern int __check_rhosts_file; 137 union sockunion from; 138 int ch, fromlen, on; 139 140 openlog("rlogind", LOG_PID | LOG_CONS, LOG_AUTH); 141 142 opterr = 0; 143 while ((ch = getopt(argc, argv, ARGSTR)) != -1) 144 switch (ch) { 145 case 'D': 146 no_delay = 1; 147 break; 148 case 'a': 149 check_all = 1; 150 break; 151 case 'l': 152 __check_rhosts_file = 0; 153 break; 154 case 'n': 155 keepalive = 0; 156 break; 157#ifdef CRYPT 158 case 'x': 159 doencrypt = 1; 160 break; 161#endif 162 case '?': 163 default: 164 usage(); 165 break; 166 } 167 argc -= optind; 168 argv += optind; 169 170 fromlen = sizeof (from); 171 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 172 syslog(LOG_ERR,"Can't get peer name of remote host: %m"); 173 fatal(STDERR_FILENO, "Can't get peer name of remote host", 1); 174 } 175 on = 1; 176 if (keepalive && 177 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) 178 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 179 if (no_delay && 180 setsockopt(0, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)) < 0) 181 syslog(LOG_WARNING, "setsockopt (TCP_NODELAY): %m"); 182 if (from.su_family == AF_INET) 183 { 184 on = IPTOS_LOWDELAY; 185 if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0) 186 syslog(LOG_WARNING, "setsockopt (IP_TOS): %m"); 187 } 188 189 doit(0, &from); 190 return 0; 191} 192 193int child; 194int netf; 195char line[MAXPATHLEN]; 196int confirmed; 197 198struct winsize win = { 0, 0, 0, 0 }; 199 200 201void 202doit(f, fromp) 203 int f; 204 union sockunion *fromp; 205{ 206 int master, pid, on = 1; 207 int authenticated = 0; 208 char hostname[2 * MAXHOSTNAMELEN + 1]; 209 char nameinfo[2 * INET6_ADDRSTRLEN + 1]; 210 char c; 211 212 alarm(60); 213 read(f, &c, 1); 214 215 if (c != 0) 216 exit(1); 217 218 alarm(0); 219 220 realhostname_sa(hostname, sizeof(hostname) - 1, 221 (struct sockaddr *)fromp, fromp->su_len); 222 /* error check ? */ 223 fromp->su_port = ntohs((u_short)fromp->su_port); 224 hostname[sizeof(hostname) - 1] = '\0'; 225 226 { 227 if ((fromp->su_family != AF_INET 228#ifdef INET6 229 && fromp->su_family != AF_INET6 230#endif 231 ) || 232 fromp->su_port >= IPPORT_RESERVED || 233 fromp->su_port < IPPORT_RESERVED/2) { 234 getnameinfo((struct sockaddr *)fromp, 235 fromp->su_len, 236 nameinfo, sizeof(nameinfo), NULL, 0, 237 NI_NUMERICHOST|NI_WITHSCOPEID); 238 /* error check ? */ 239 syslog(LOG_NOTICE, "Connection from %s on illegal port", 240 nameinfo); 241 fatal(f, "Permission denied", 0); 242 } 243#ifdef IP_OPTIONS 244 if (fromp->su_family == AF_INET) 245 { 246 u_char optbuf[BUFSIZ/3]; 247 int optsize = sizeof(optbuf), ipproto, i; 248 struct protoent *ip; 249 250 if ((ip = getprotobyname("ip")) != NULL) 251 ipproto = ip->p_proto; 252 else 253 ipproto = IPPROTO_IP; 254 if (getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, 255 &optsize) == 0 && optsize != 0) { 256 for (i = 0; i < optsize; ) { 257 u_char c = optbuf[i]; 258 if (c == IPOPT_LSRR || c == IPOPT_SSRR) { 259 syslog(LOG_NOTICE, 260 "Connection refused from %s with IP option %s", 261 inet_ntoa(fromp->su_sin.sin_addr), 262 c == IPOPT_LSRR ? "LSRR" : "SSRR"); 263 exit(1); 264 } 265 if (c == IPOPT_EOL) 266 break; 267 i += (c == IPOPT_NOP) ? 1 : optbuf[i+1]; 268 } 269 } 270 } 271#endif 272 if (do_rlogin(fromp) == 0) 273 authenticated++; 274 } 275 if (confirmed == 0) { 276 write(f, "", 1); 277 confirmed = 1; /* we sent the null! */ 278 } 279#ifdef CRYPT 280 if (doencrypt) 281 (void) des_enc_write(f, 282 SECURE_MESSAGE, 283 strlen(SECURE_MESSAGE), 284 schedule, &kdata->session); 285#endif 286 netf = f; 287 288 pid = forkpty(&master, line, NULL, &win); 289 if (pid < 0) { 290 if (errno == ENOENT) 291 fatal(f, "Out of ptys", 0); 292 else 293 fatal(f, "Forkpty", 1); 294 } 295 if (pid == 0) { 296 if (f > 2) /* f should always be 0, but... */ 297 (void) close(f); 298 setup_term(0); 299 if (*lusername=='-') { 300 syslog(LOG_ERR, "tried to pass user \"%s\" to login", 301 lusername); 302 fatal(STDERR_FILENO, "invalid user", 0); 303 } 304 if (authenticated) { 305 execl(_PATH_LOGIN, "login", "-p", 306 "-h", hostname, "-f", lusername, (char *)NULL); 307 } else 308 execl(_PATH_LOGIN, "login", "-p", 309 "-h", hostname, lusername, (char *)NULL); 310 fatal(STDERR_FILENO, _PATH_LOGIN, 1); 311 /*NOTREACHED*/ 312 } 313#ifdef CRYPT 314 /* 315 * If encrypted, don't turn on NBIO or the des read/write 316 * routines will croak. 317 */ 318 319 if (!doencrypt) 320#endif 321 ioctl(f, FIONBIO, &on); 322 ioctl(master, FIONBIO, &on); 323 ioctl(master, TIOCPKT, &on); 324 signal(SIGCHLD, cleanup); 325 protocol(f, master); 326 signal(SIGCHLD, SIG_IGN); 327 cleanup(0); 328} 329 330char magic[2] = { 0377, 0377 }; 331char oobdata[] = {TIOCPKT_WINDOW}; 332 333/* 334 * Handle a "control" request (signaled by magic being present) 335 * in the data stream. For now, we are only willing to handle 336 * window size changes. 337 */ 338int 339control(pty, cp, n) 340 int pty; 341 char *cp; 342 int n; 343{ 344 struct winsize w; 345 346 if (n < 4+sizeof (w) || cp[2] != 's' || cp[3] != 's') 347 return (0); 348 oobdata[0] &= ~TIOCPKT_WINDOW; /* we know he heard */ 349 bcopy(cp+4, (char *)&w, sizeof(w)); 350 w.ws_row = ntohs(w.ws_row); 351 w.ws_col = ntohs(w.ws_col); 352 w.ws_xpixel = ntohs(w.ws_xpixel); 353 w.ws_ypixel = ntohs(w.ws_ypixel); 354 (void)ioctl(pty, TIOCSWINSZ, &w); 355 return (4+sizeof (w)); 356} 357 358/* 359 * rlogin "protocol" machine. 360 */ 361void 362protocol(f, p) 363 register int f, p; 364{ 365 char pibuf[1024+1], fibuf[1024], *pbp, *fbp; 366 int pcc = 0, fcc = 0; 367 int cc, nfd, n; 368 char cntl; 369 370 /* 371 * Must ignore SIGTTOU, otherwise we'll stop 372 * when we try and set slave pty's window shape 373 * (our controlling tty is the master pty). 374 */ 375 (void) signal(SIGTTOU, SIG_IGN); 376 send(f, oobdata, 1, MSG_OOB); /* indicate new rlogin */ 377 if (f > p) 378 nfd = f + 1; 379 else 380 nfd = p + 1; 381 if (nfd > FD_SETSIZE) { 382 syslog(LOG_ERR, "select mask too small, increase FD_SETSIZE"); 383 fatal(f, "internal error (select mask too small)", 0); 384 } 385 for (;;) { 386 fd_set ibits, obits, ebits, *omask; 387 388 FD_ZERO(&ebits); 389 FD_ZERO(&ibits); 390 FD_ZERO(&obits); 391 omask = (fd_set *)NULL; 392 if (fcc) { 393 FD_SET(p, &obits); 394 omask = &obits; 395 } else 396 FD_SET(f, &ibits); 397 if (pcc >= 0) { 398 if (pcc) { 399 FD_SET(f, &obits); 400 omask = &obits; 401 } else 402 FD_SET(p, &ibits); 403 } 404 FD_SET(p, &ebits); 405 if ((n = select(nfd, &ibits, omask, &ebits, 0)) < 0) { 406 if (errno == EINTR) 407 continue; 408 fatal(f, "select", 1); 409 } 410 if (n == 0) { 411 /* shouldn't happen... */ 412 sleep(5); 413 continue; 414 } 415#define pkcontrol(c) ((c)&(TIOCPKT_FLUSHWRITE|TIOCPKT_NOSTOP|TIOCPKT_DOSTOP)) 416 if (FD_ISSET(p, &ebits)) { 417 cc = read(p, &cntl, 1); 418 if (cc == 1 && pkcontrol(cntl)) { 419 cntl |= oobdata[0]; 420 send(f, &cntl, 1, MSG_OOB); 421 if (cntl & TIOCPKT_FLUSHWRITE) { 422 pcc = 0; 423 FD_CLR(p, &ibits); 424 } 425 } 426 } 427 if (FD_ISSET(f, &ibits)) { 428#ifdef CRYPT 429 if (doencrypt) 430 fcc = des_enc_read(f, fibuf, sizeof(fibuf), 431 schedule, &kdata->session); 432 else 433#endif 434 fcc = read(f, fibuf, sizeof(fibuf)); 435 if (fcc < 0 && errno == EWOULDBLOCK) 436 fcc = 0; 437 else { 438 register char *cp; 439 int left, n; 440 441 if (fcc <= 0) 442 break; 443 fbp = fibuf; 444 445 top: 446 for (cp = fibuf; cp < fibuf+fcc-1; cp++) 447 if (cp[0] == magic[0] && 448 cp[1] == magic[1]) { 449 left = fcc - (cp-fibuf); 450 n = control(p, cp, left); 451 if (n) { 452 left -= n; 453 if (left > 0) 454 bcopy(cp+n, cp, left); 455 fcc -= n; 456 goto top; /* n^2 */ 457 } 458 } 459 FD_SET(p, &obits); /* try write */ 460 } 461 } 462 463 if (FD_ISSET(p, &obits) && fcc > 0) { 464 cc = write(p, fbp, fcc); 465 if (cc > 0) { 466 fcc -= cc; 467 fbp += cc; 468 } 469 } 470 471 if (FD_ISSET(p, &ibits)) { 472 pcc = read(p, pibuf, sizeof (pibuf)); 473 pbp = pibuf; 474 if (pcc < 0 && errno == EWOULDBLOCK) 475 pcc = 0; 476 else if (pcc <= 0) 477 break; 478 else if (pibuf[0] == 0) { 479 pbp++, pcc--; 480#ifdef CRYPT 481 if (!doencrypt) 482#endif 483 FD_SET(f, &obits); /* try write */ 484 } else { 485 if (pkcontrol(pibuf[0])) { 486 pibuf[0] |= oobdata[0]; 487 send(f, &pibuf[0], 1, MSG_OOB); 488 } 489 pcc = 0; 490 } 491 } 492 if ((FD_ISSET(f, &obits)) && pcc > 0) { 493#ifdef CRYPT 494 if (doencrypt) 495 cc = des_enc_write(f, pbp, pcc, 496 schedule, &kdata->session); 497 else 498#endif 499 cc = write(f, pbp, pcc); 500 if (cc < 0 && errno == EWOULDBLOCK) { 501 /* 502 * This happens when we try write after read 503 * from p, but some old kernels balk at large 504 * writes even when select returns true. 505 */ 506 if (!FD_ISSET(p, &ibits)) 507 sleep(5); 508 continue; 509 } 510 if (cc > 0) { 511 pcc -= cc; 512 pbp += cc; 513 } 514 } 515 } 516} 517 518void 519cleanup(signo) 520 int signo; 521{ 522 char *p; 523 524 p = line + sizeof(_PATH_DEV) - 1; 525 if (logout(p)) 526 logwtmp(p, "", ""); 527 (void)chflags(line, 0); 528 (void)chmod(line, 0666); 529 (void)chown(line, 0, 0); 530 *p = 'p'; 531 (void)chflags(line, 0); 532 (void)chmod(line, 0666); 533 (void)chown(line, 0, 0); 534 shutdown(netf, 2); 535 exit(1); 536} 537 538void 539fatal(f, msg, syserr) 540 int f; 541 char *msg; 542 int syserr; 543{ 544 int len; 545 char buf[BUFSIZ], *bp = buf; 546 547 /* 548 * Prepend binary one to message if we haven't sent 549 * the magic null as confirmation. 550 */ 551 if (!confirmed) 552 *bp++ = '\01'; /* error indicator */ 553 if (syserr) 554 len = snprintf(bp, sizeof(buf), "rlogind: %s: %s.\r\n", 555 msg, strerror(errno)); 556 else 557 len = snprintf(bp, sizeof(buf), "rlogind: %s.\r\n", msg); 558 (void) write(f, buf, bp + len - buf); 559 exit(1); 560} 561 562int 563do_rlogin(dest) 564 union sockunion *dest; 565{ 566 567 getstr(rusername, sizeof(rusername), "remuser too long"); 568 getstr(lusername, sizeof(lusername), "locuser too long"); 569 getstr(term+ENVSIZE, sizeof(term)-ENVSIZE, "Terminal type too long"); 570 571 pwd = getpwnam(lusername); 572 if (pwd == NULL) 573 return (-1); 574 /* XXX why don't we syslog() failure? */ 575 576 return (iruserok_sa(dest, dest->su_len, pwd->pw_uid == 0, rusername, 577 lusername)); 578} 579 580void 581getstr(buf, cnt, errmsg) 582 char *buf; 583 int cnt; 584 char *errmsg; 585{ 586 char c; 587 588 do { 589 if (read(0, &c, 1) != 1) 590 exit(1); 591 if (--cnt < 0) 592 fatal(STDOUT_FILENO, errmsg, 0); 593 *buf++ = c; 594 } while (c != 0); 595} 596 597extern char **environ; 598 599void 600setup_term(fd) 601 int fd; 602{ 603 register char *cp = index(term+ENVSIZE, '/'); 604 char *speed; 605 struct termios tt; 606 607#ifndef notyet 608 tcgetattr(fd, &tt); 609 if (cp) { 610 *cp++ = '\0'; 611 speed = cp; 612 cp = index(speed, '/'); 613 if (cp) 614 *cp++ = '\0'; 615 cfsetspeed(&tt, atoi(speed)); 616 } 617 618 tt.c_iflag = TTYDEF_IFLAG; 619 tt.c_oflag = TTYDEF_OFLAG; 620 tt.c_lflag = TTYDEF_LFLAG; 621 tcsetattr(fd, TCSAFLUSH, &tt); 622#else 623 if (cp) { 624 *cp++ = '\0'; 625 speed = cp; 626 cp = index(speed, '/'); 627 if (cp) 628 *cp++ = '\0'; 629 tcgetattr(fd, &tt); 630 cfsetspeed(&tt, atoi(speed)); 631 tcsetattr(fd, TCSAFLUSH, &tt); 632 } 633#endif 634 635 env[0] = term; 636 env[1] = 0; 637 environ = env; 638} 639 640void 641usage() 642{ 643 syslog(LOG_ERR, "usage: rlogind [-" ARGSTR "]"); 644} 645