1 /*- 2 * Copyright (c) 1988, 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 char copyright[] = 10 "@(#) Copyright (c) 1988, 1989 The Regents of the University of California.\n\ 11 All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)rshd.c 5.38 (Berkeley) 03/02/91"; 16 #endif /* not lint */ 17 18 /* 19 * From: 20 * $Source: /mit/kerberos/ucb/mit/rshd/RCS/rshd.c,v $ 21 * $Header: /mit/kerberos/ucb/mit/rshd/RCS/rshd.c,v 22 * 5.2 89/07/31 19:30:04 kfall Exp $ 23 */ 24 25 /* 26 * remote shell server: 27 * [port]\0 28 * remuser\0 29 * locuser\0 30 * command\0 31 * data 32 */ 33 #include <sys/param.h> 34 #include <sys/ioctl.h> 35 #include <sys/time.h> 36 #include <fcntl.h> 37 #include <signal.h> 38 39 #include <sys/socket.h> 40 #include <netinet/in.h> 41 #include <arpa/inet.h> 42 #include <netdb.h> 43 44 #include <pwd.h> 45 #include <syslog.h> 46 #include <unistd.h> 47 #include <errno.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <paths.h> 52 53 int keepalive = 1; 54 int check_all = 0; 55 char *index(), *rindex(), *strncat(); 56 /*VARARGS1*/ 57 int error(); 58 int sent_null; 59 60 #ifdef KERBEROS 61 #include <kerberosIV/des.h> 62 #include <kerberosIV/krb.h> 63 #define VERSION_SIZE 9 64 #define SECURE_MESSAGE "This rsh session is using DES encryption for all transmissions.\r\n" 65 #define OPTIONS "alknvx" 66 char authbuf[sizeof(AUTH_DAT)]; 67 char tickbuf[sizeof(KTEXT_ST)]; 68 int doencrypt, use_kerberos, vacuous; 69 Key_schedule schedule; 70 #else 71 #define OPTIONS "aln" 72 #endif 73 74 /*ARGSUSED*/ 75 main(argc, argv) 76 int argc; 77 char **argv; 78 { 79 extern int opterr, optind; 80 extern int _check_rhosts_file; 81 struct linger linger; 82 int ch, on = 1, fromlen; 83 struct sockaddr_in from; 84 85 openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON); 86 87 opterr = 0; 88 while ((ch = getopt(argc, argv, OPTIONS)) != EOF) 89 switch (ch) { 90 case 'a': 91 check_all = 1; 92 break; 93 case 'l': 94 _check_rhosts_file = 0; 95 break; 96 case 'n': 97 keepalive = 0; 98 break; 99 #ifdef KERBEROS 100 case 'k': 101 use_kerberos = 1; 102 break; 103 104 case 'v': 105 vacuous = 1; 106 break; 107 108 #ifdef CRYPT 109 case 'x': 110 doencrypt = 1; 111 break; 112 #endif 113 #endif 114 case '?': 115 default: 116 usage(); 117 exit(2); 118 } 119 120 argc -= optind; 121 argv += optind; 122 123 #ifdef KERBEROS 124 if (use_kerberos && vacuous) { 125 syslog(LOG_ERR, "only one of -k and -v allowed"); 126 exit(2); 127 } 128 #ifdef CRYPT 129 if (doencrypt && !use_kerberos) { 130 syslog(LOG_ERR, "-k is required for -x"); 131 exit(2); 132 } 133 #endif 134 #endif 135 136 fromlen = sizeof (from); 137 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 138 syslog(LOG_ERR, "getpeername: %m"); 139 _exit(1); 140 } 141 if (keepalive && 142 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 143 sizeof(on)) < 0) 144 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 145 linger.l_onoff = 1; 146 linger.l_linger = 60; /* XXX */ 147 if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, 148 sizeof (linger)) < 0) 149 syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 150 doit(&from); 151 } 152 153 char username[20] = "USER="; 154 char homedir[64] = "HOME="; 155 char shell[64] = "SHELL="; 156 char path[100] = "PATH="; 157 char *envinit[] = 158 {homedir, shell, path, username, 0}; 159 char **environ; 160 161 doit(fromp) 162 struct sockaddr_in *fromp; 163 { 164 char cmdbuf[NCARGS+1], *cp; 165 char locuser[16], remuser[16]; 166 struct passwd *pwd; 167 int s; 168 struct hostent *hp; 169 char *hostname, *errorstr = NULL, *errorhost; 170 u_short port; 171 int pv[2], pid, cc; 172 int nfd; 173 fd_set ready, readfrom; 174 char buf[BUFSIZ], sig; 175 int one = 1; 176 char remotehost[2 * MAXHOSTNAMELEN + 1]; 177 178 #ifdef KERBEROS 179 AUTH_DAT *kdata = (AUTH_DAT *) NULL; 180 KTEXT ticket = (KTEXT) NULL; 181 char instance[INST_SZ], version[VERSION_SIZE]; 182 struct sockaddr_in fromaddr; 183 int rc; 184 long authopts; 185 int pv1[2], pv2[2]; 186 fd_set wready, writeto; 187 188 fromaddr = *fromp; 189 #endif 190 191 (void) signal(SIGINT, SIG_DFL); 192 (void) signal(SIGQUIT, SIG_DFL); 193 (void) signal(SIGTERM, SIG_DFL); 194 #ifdef DEBUG 195 { int t = open(_PATH_TTY, 2); 196 if (t >= 0) { 197 ioctl(t, TIOCNOTTY, (char *)0); 198 (void) close(t); 199 } 200 } 201 #endif 202 fromp->sin_port = ntohs((u_short)fromp->sin_port); 203 if (fromp->sin_family != AF_INET) { 204 syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", 205 fromp->sin_family); 206 exit(1); 207 } 208 #ifdef IP_OPTIONS 209 { 210 u_char optbuf[BUFSIZ/3], *cp; 211 char lbuf[BUFSIZ], *lp; 212 int optsize = sizeof(optbuf), ipproto; 213 struct protoent *ip; 214 215 if ((ip = getprotobyname("ip")) != NULL) 216 ipproto = ip->p_proto; 217 else 218 ipproto = IPPROTO_IP; 219 if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) && 220 optsize != 0) { 221 lp = lbuf; 222 for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 223 sprintf(lp, " %2.2x", *cp); 224 syslog(LOG_NOTICE, 225 "Connection received from %s using IP options (ignored):%s", 226 inet_ntoa(fromp->sin_addr), lbuf); 227 if (setsockopt(0, ipproto, IP_OPTIONS, 228 (char *)NULL, optsize) != 0) { 229 syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 230 exit(1); 231 } 232 } 233 } 234 #endif 235 236 #ifdef KERBEROS 237 if (!use_kerberos) 238 #endif 239 if (fromp->sin_port >= IPPORT_RESERVED || 240 fromp->sin_port < IPPORT_RESERVED/2) { 241 syslog(LOG_NOTICE|LOG_AUTH, 242 "Connection from %s on illegal port", 243 inet_ntoa(fromp->sin_addr)); 244 exit(1); 245 } 246 247 (void) alarm(60); 248 port = 0; 249 for (;;) { 250 char c; 251 if ((cc = read(0, &c, 1)) != 1) { 252 if (cc < 0) 253 syslog(LOG_NOTICE, "read: %m"); 254 shutdown(0, 1+1); 255 exit(1); 256 } 257 if (c== 0) 258 break; 259 port = port * 10 + c - '0'; 260 } 261 262 (void) alarm(0); 263 if (port != 0) { 264 int lport = IPPORT_RESERVED - 1; 265 s = rresvport(&lport); 266 if (s < 0) { 267 syslog(LOG_ERR, "can't get stderr port: %m"); 268 exit(1); 269 } 270 #ifdef KERBEROS 271 if (!use_kerberos) 272 #endif 273 if (port >= IPPORT_RESERVED) { 274 syslog(LOG_ERR, "2nd port not reserved\n"); 275 exit(1); 276 } 277 fromp->sin_port = htons(port); 278 if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) { 279 syslog(LOG_INFO, "connect second port: %m"); 280 exit(1); 281 } 282 } 283 284 #ifdef KERBEROS 285 if (vacuous) { 286 error("rshd: remote host requires Kerberos authentication\n"); 287 exit(1); 288 } 289 #endif 290 291 #ifdef notdef 292 /* from inetd, socket is already on 0, 1, 2 */ 293 dup2(f, 0); 294 dup2(f, 1); 295 dup2(f, 2); 296 #endif 297 hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr), 298 fromp->sin_family); 299 if (hp) { 300 /* 301 * If name returned by gethostbyaddr is in our domain, 302 * attempt to verify that we haven't been fooled by someone 303 * in a remote net; look up the name and check that this 304 * address corresponds to the name. 305 */ 306 hostname = hp->h_name; 307 #ifdef KERBEROS 308 if (!use_kerberos) 309 #endif 310 if (check_all || local_domain(hp->h_name)) { 311 strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 312 remotehost[sizeof(remotehost) - 1] = 0; 313 errorhost = remotehost; 314 hp = gethostbyname(remotehost); 315 if (hp == NULL) { 316 syslog(LOG_INFO, 317 "Couldn't look up address for %s", 318 remotehost); 319 errorstr = 320 "Couldn't look up address for your host (%s)\n"; 321 hostname = inet_ntoa(fromp->sin_addr); 322 } else for (; ; hp->h_addr_list++) { 323 if (hp->h_addr_list[0] == NULL) { 324 syslog(LOG_NOTICE, 325 "Host addr %s not listed for host %s", 326 inet_ntoa(fromp->sin_addr), 327 hp->h_name); 328 errorstr = 329 "Host address mismatch for %s\n"; 330 hostname = inet_ntoa(fromp->sin_addr); 331 break; 332 } 333 if (!bcmp(hp->h_addr_list[0], 334 (caddr_t)&fromp->sin_addr, 335 sizeof(fromp->sin_addr))) { 336 hostname = hp->h_name; 337 break; 338 } 339 } 340 } 341 } else 342 errorhost = hostname = inet_ntoa(fromp->sin_addr); 343 344 #ifdef KERBEROS 345 if (use_kerberos) { 346 kdata = (AUTH_DAT *) authbuf; 347 ticket = (KTEXT) tickbuf; 348 authopts = 0L; 349 strcpy(instance, "*"); 350 version[VERSION_SIZE - 1] = '\0'; 351 #ifdef CRYPT 352 if (doencrypt) { 353 struct sockaddr_in local_addr; 354 rc = sizeof(local_addr); 355 if (getsockname(0, (struct sockaddr *)&local_addr, 356 &rc) < 0) { 357 syslog(LOG_ERR, "getsockname: %m"); 358 error("rlogind: getsockname: %m"); 359 exit(1); 360 } 361 authopts = KOPT_DO_MUTUAL; 362 rc = krb_recvauth(authopts, 0, ticket, 363 "rcmd", instance, &fromaddr, 364 &local_addr, kdata, "", schedule, 365 version); 366 des_set_key(kdata->session, schedule); 367 } else 368 #endif 369 rc = krb_recvauth(authopts, 0, ticket, "rcmd", 370 instance, &fromaddr, 371 (struct sockaddr_in *) 0, 372 kdata, "", (bit_64 *) 0, version); 373 if (rc != KSUCCESS) { 374 error("Kerberos authentication failure: %s\n", 375 krb_err_txt[rc]); 376 exit(1); 377 } 378 } else 379 #endif 380 getstr(remuser, sizeof(remuser), "remuser"); 381 382 getstr(locuser, sizeof(locuser), "locuser"); 383 getstr(cmdbuf, sizeof(cmdbuf), "command"); 384 setpwent(); 385 pwd = getpwnam(locuser); 386 if (pwd == NULL) { 387 if (errorstr == NULL) 388 errorstr = "Login incorrect.\n"; 389 goto fail; 390 } 391 if (chdir(pwd->pw_dir) < 0) { 392 (void) chdir("/"); 393 #ifdef notdef 394 error("No remote directory.\n"); 395 exit(1); 396 #endif 397 } 398 399 #ifdef KERBEROS 400 if (use_kerberos) { 401 if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') { 402 if (kuserok(kdata, locuser) != 0) { 403 syslog(LOG_NOTICE|LOG_AUTH, 404 "Kerberos rsh denied to %s.%s@%s", 405 kdata->pname, kdata->pinst, kdata->prealm); 406 error("Permission denied.\n"); 407 exit(1); 408 } 409 } 410 } else 411 #endif 412 413 if (errorstr || 414 pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && 415 ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) { 416 fail: 417 if (errorstr == NULL) 418 errorstr = "Permission denied.\n"; 419 error(errorstr, errorhost); 420 exit(1); 421 } 422 423 if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) { 424 error("Logins currently disabled.\n"); 425 exit(1); 426 } 427 428 (void) write(2, "\0", 1); 429 sent_null = 1; 430 431 if (port) { 432 if (pipe(pv) < 0) { 433 error("Can't make pipe.\n"); 434 exit(1); 435 } 436 #ifdef CRYPT 437 #ifdef KERBEROS 438 if (doencrypt) { 439 if (pipe(pv1) < 0) { 440 error("Can't make 2nd pipe.\n"); 441 exit(1); 442 } 443 if (pipe(pv2) < 0) { 444 error("Can't make 3rd pipe.\n"); 445 exit(1); 446 } 447 } 448 #endif 449 #endif 450 pid = fork(); 451 if (pid == -1) { 452 error("Can't fork; try again.\n"); 453 exit(1); 454 } 455 if (pid) { 456 #ifdef CRYPT 457 #ifdef KERBEROS 458 if (doencrypt) { 459 static char msg[] = SECURE_MESSAGE; 460 (void) close(pv1[1]); 461 (void) close(pv2[1]); 462 des_write(s, msg, sizeof(msg)); 463 464 } else 465 #endif 466 #endif 467 { 468 (void) close(0); (void) close(1); 469 } 470 (void) close(2); (void) close(pv[1]); 471 472 FD_ZERO(&readfrom); 473 FD_SET(s, &readfrom); 474 FD_SET(pv[0], &readfrom); 475 if (pv[0] > s) 476 nfd = pv[0]; 477 else 478 nfd = s; 479 #ifdef CRYPT 480 #ifdef KERBEROS 481 if (doencrypt) { 482 FD_ZERO(&writeto); 483 FD_SET(pv2[0], &writeto); 484 FD_SET(pv1[0], &readfrom); 485 486 nfd = MAX(nfd, pv2[0]); 487 nfd = MAX(nfd, pv1[0]); 488 } else 489 #endif 490 #endif 491 ioctl(pv[0], FIONBIO, (char *)&one); 492 493 /* should set s nbio! */ 494 nfd++; 495 do { 496 ready = readfrom; 497 #ifdef CRYPT 498 #ifdef KERBEROS 499 if (doencrypt) { 500 wready = writeto; 501 if (select(nfd, &ready, 502 &wready, (fd_set *) 0, 503 (struct timeval *) 0) < 0) 504 break; 505 } else 506 #endif 507 #endif 508 if (select(nfd, &ready, (fd_set *)0, 509 (fd_set *)0, (struct timeval *)0) < 0) 510 break; 511 if (FD_ISSET(s, &ready)) { 512 int ret; 513 #ifdef CRYPT 514 #ifdef KERBEROS 515 if (doencrypt) 516 ret = des_read(s, &sig, 1); 517 else 518 #endif 519 #endif 520 ret = read(s, &sig, 1); 521 if (ret <= 0) 522 FD_CLR(s, &readfrom); 523 else 524 killpg(pid, sig); 525 } 526 if (FD_ISSET(pv[0], &ready)) { 527 errno = 0; 528 cc = read(pv[0], buf, sizeof(buf)); 529 if (cc <= 0) { 530 shutdown(s, 1+1); 531 FD_CLR(pv[0], &readfrom); 532 } else { 533 #ifdef CRYPT 534 #ifdef KERBEROS 535 if (doencrypt) 536 (void) 537 des_write(s, buf, cc); 538 else 539 #endif 540 #endif 541 (void) 542 write(s, buf, cc); 543 } 544 } 545 #ifdef CRYPT 546 #ifdef KERBEROS 547 if (doencrypt && FD_ISSET(pv1[0], &ready)) { 548 errno = 0; 549 cc = read(pv1[0], buf, sizeof(buf)); 550 if (cc <= 0) { 551 shutdown(pv1[0], 1+1); 552 FD_CLR(pv1[0], &readfrom); 553 } else 554 (void) des_write(1, buf, cc); 555 } 556 557 if (doencrypt && FD_ISSET(pv2[0], &wready)) { 558 errno = 0; 559 cc = des_read(0, buf, sizeof(buf)); 560 if (cc <= 0) { 561 shutdown(pv2[0], 1+1); 562 FD_CLR(pv2[0], &writeto); 563 } else 564 (void) write(pv2[0], buf, cc); 565 } 566 #endif 567 #endif 568 569 } while (FD_ISSET(s, &readfrom) || 570 #ifdef CRYPT 571 #ifdef KERBEROS 572 (doencrypt && FD_ISSET(pv1[0], &readfrom)) || 573 #endif 574 #endif 575 FD_ISSET(pv[0], &readfrom)); 576 exit(0); 577 } 578 setpgrp(0, getpid()); 579 (void) close(s); (void) close(pv[0]); 580 #ifdef CRYPT 581 #ifdef KERBEROS 582 if (doencrypt) { 583 close(pv1[0]); close(pv2[0]); 584 dup2(pv1[1], 1); 585 dup2(pv2[1], 0); 586 close(pv1[1]); 587 close(pv2[1]); 588 } 589 #endif 590 #endif 591 dup2(pv[1], 2); 592 close(pv[1]); 593 } 594 if (*pwd->pw_shell == '\0') 595 pwd->pw_shell = _PATH_BSHELL; 596 #if BSD > 43 597 if (setlogin(pwd->pw_name) < 0) 598 syslog(LOG_ERR, "setlogin() failed: %m"); 599 #endif 600 (void) setgid((gid_t)pwd->pw_gid); 601 initgroups(pwd->pw_name, pwd->pw_gid); 602 (void) setuid((uid_t)pwd->pw_uid); 603 environ = envinit; 604 strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 605 strcat(path, _PATH_DEFPATH); 606 strncat(shell, pwd->pw_shell, sizeof(shell)-7); 607 strncat(username, pwd->pw_name, sizeof(username)-6); 608 cp = rindex(pwd->pw_shell, '/'); 609 if (cp) 610 cp++; 611 else 612 cp = pwd->pw_shell; 613 endpwent(); 614 if (pwd->pw_uid == 0) { 615 #ifdef KERBEROS 616 if (use_kerberos) 617 syslog(LOG_INFO|LOG_AUTH, 618 "ROOT Kerberos shell from %s.%s@%s on %s, comm: %s\n", 619 kdata->pname, kdata->pinst, kdata->prealm, 620 hostname, cmdbuf); 621 else 622 #endif 623 syslog(LOG_INFO|LOG_AUTH, 624 "ROOT shell from %s@%s, comm: %s\n", 625 remuser, hostname, cmdbuf); 626 } 627 execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); 628 perror(pwd->pw_shell); 629 exit(1); 630 } 631 632 /* 633 * Report error to client. 634 * Note: can't be used until second socket has connected 635 * to client, or older clients will hang waiting 636 * for that connection first. 637 */ 638 /*VARARGS1*/ 639 error(fmt, a1, a2, a3) 640 char *fmt; 641 int a1, a2, a3; 642 { 643 char buf[BUFSIZ], *bp = buf; 644 645 if (sent_null == 0) 646 *bp++ = 1; 647 (void) sprintf(bp, fmt, a1, a2, a3); 648 (void) write(2, buf, strlen(buf)); 649 } 650 651 getstr(buf, cnt, err) 652 char *buf; 653 int cnt; 654 char *err; 655 { 656 char c; 657 658 do { 659 if (read(0, &c, 1) != 1) 660 exit(1); 661 *buf++ = c; 662 if (--cnt == 0) { 663 error("%s too long\n", err); 664 exit(1); 665 } 666 } while (c != 0); 667 } 668 669 /* 670 * Check whether host h is in our local domain, 671 * defined as sharing the last two components of the domain part, 672 * or the entire domain part if the local domain has only one component. 673 * If either name is unqualified (contains no '.'), 674 * assume that the host is local, as it will be 675 * interpreted as such. 676 */ 677 local_domain(h) 678 char *h; 679 { 680 char localhost[MAXHOSTNAMELEN]; 681 char *p1, *p2, *topdomain(); 682 683 localhost[0] = 0; 684 (void) gethostname(localhost, sizeof(localhost)); 685 p1 = topdomain(localhost); 686 p2 = topdomain(h); 687 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 688 return(1); 689 return(0); 690 } 691 692 char * 693 topdomain(h) 694 char *h; 695 { 696 register char *p; 697 char *maybe = NULL; 698 int dots = 0; 699 700 for (p = h + strlen(h); p >= h; p--) { 701 if (*p == '.') { 702 if (++dots == 2) 703 return (p); 704 maybe = p; 705 } 706 } 707 return (maybe); 708 } 709 710 usage() 711 { 712 syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS); 713 } 714