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.1.1 (Berkeley) 08/20/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 #endif 109 case '?': 110 default: 111 usage(); 112 exit(2); 113 } 114 115 argc -= optind; 116 argv += optind; 117 118 #ifdef KERBEROS 119 if (use_kerberos && vacuous) { 120 syslog(LOG_ERR, "only one of -k and -v allowed"); 121 exit(2); 122 } 123 #endif 124 125 fromlen = sizeof (from); 126 if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 127 syslog(LOG_ERR, "getpeername: %m"); 128 _exit(1); 129 } 130 if (keepalive && 131 setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 132 sizeof(on)) < 0) 133 syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 134 linger.l_onoff = 1; 135 linger.l_linger = 60; /* XXX */ 136 if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger, 137 sizeof (linger)) < 0) 138 syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 139 doit(&from); 140 } 141 142 char username[20] = "USER="; 143 char homedir[64] = "HOME="; 144 char shell[64] = "SHELL="; 145 char path[100] = "PATH="; 146 char *envinit[] = 147 {homedir, shell, path, username, 0}; 148 char **environ; 149 150 doit(fromp) 151 struct sockaddr_in *fromp; 152 { 153 char cmdbuf[NCARGS+1], *cp; 154 char locuser[16], remuser[16]; 155 struct passwd *pwd; 156 int s; 157 struct hostent *hp; 158 char *hostname, *errorstr = NULL, *errorhost; 159 u_short port; 160 int pv[2], pid, cc; 161 int nfd; 162 fd_set ready, readfrom; 163 char buf[BUFSIZ], sig; 164 int one = 1; 165 char remotehost[2 * MAXHOSTNAMELEN + 1]; 166 167 #ifdef KERBEROS 168 AUTH_DAT *kdata = (AUTH_DAT *) NULL; 169 KTEXT ticket = (KTEXT) NULL; 170 char instance[INST_SZ], version[VERSION_SIZE]; 171 struct sockaddr_in fromaddr; 172 int rc; 173 long authopts; 174 int pv1[2], pv2[2]; 175 fd_set wready, writeto; 176 177 fromaddr = *fromp; 178 #endif 179 180 (void) signal(SIGINT, SIG_DFL); 181 (void) signal(SIGQUIT, SIG_DFL); 182 (void) signal(SIGTERM, SIG_DFL); 183 #ifdef DEBUG 184 { int t = open(_PATH_TTY, 2); 185 if (t >= 0) { 186 ioctl(t, TIOCNOTTY, (char *)0); 187 (void) close(t); 188 } 189 } 190 #endif 191 fromp->sin_port = ntohs((u_short)fromp->sin_port); 192 if (fromp->sin_family != AF_INET) { 193 syslog(LOG_ERR, "malformed \"from\" address (af %d)\n", 194 fromp->sin_family); 195 exit(1); 196 } 197 #ifdef IP_OPTIONS 198 { 199 u_char optbuf[BUFSIZ/3], *cp; 200 char lbuf[BUFSIZ], *lp; 201 int optsize = sizeof(optbuf), ipproto; 202 struct protoent *ip; 203 204 if ((ip = getprotobyname("ip")) != NULL) 205 ipproto = ip->p_proto; 206 else 207 ipproto = IPPROTO_IP; 208 if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) && 209 optsize != 0) { 210 lp = lbuf; 211 for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3) 212 sprintf(lp, " %2.2x", *cp); 213 syslog(LOG_NOTICE, 214 "Connection received from %s using IP options (ignored):%s", 215 inet_ntoa(fromp->sin_addr), lbuf); 216 if (setsockopt(0, ipproto, IP_OPTIONS, 217 (char *)NULL, optsize) != 0) { 218 syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m"); 219 exit(1); 220 } 221 } 222 } 223 #endif 224 225 #ifdef KERBEROS 226 if (!use_kerberos) 227 #endif 228 if (fromp->sin_port >= IPPORT_RESERVED || 229 fromp->sin_port < IPPORT_RESERVED/2) { 230 syslog(LOG_NOTICE|LOG_AUTH, 231 "Connection from %s on illegal port", 232 inet_ntoa(fromp->sin_addr)); 233 exit(1); 234 } 235 236 (void) alarm(60); 237 port = 0; 238 for (;;) { 239 char c; 240 if ((cc = read(0, &c, 1)) != 1) { 241 if (cc < 0) 242 syslog(LOG_NOTICE, "read: %m"); 243 shutdown(0, 1+1); 244 exit(1); 245 } 246 if (c== 0) 247 break; 248 port = port * 10 + c - '0'; 249 } 250 251 (void) alarm(0); 252 if (port != 0) { 253 int lport = IPPORT_RESERVED - 1; 254 s = rresvport(&lport); 255 if (s < 0) { 256 syslog(LOG_ERR, "can't get stderr port: %m"); 257 exit(1); 258 } 259 #ifdef KERBEROS 260 if (!use_kerberos) 261 #endif 262 if (port >= IPPORT_RESERVED) { 263 syslog(LOG_ERR, "2nd port not reserved\n"); 264 exit(1); 265 } 266 fromp->sin_port = htons(port); 267 if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) { 268 syslog(LOG_INFO, "connect second port: %m"); 269 exit(1); 270 } 271 } 272 273 #ifdef KERBEROS 274 if (vacuous) { 275 error("rshd: remote host requires Kerberos authentication\n"); 276 exit(1); 277 } 278 #endif 279 280 #ifdef notdef 281 /* from inetd, socket is already on 0, 1, 2 */ 282 dup2(f, 0); 283 dup2(f, 1); 284 dup2(f, 2); 285 #endif 286 hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr), 287 fromp->sin_family); 288 if (hp) { 289 /* 290 * If name returned by gethostbyaddr is in our domain, 291 * attempt to verify that we haven't been fooled by someone 292 * in a remote net; look up the name and check that this 293 * address corresponds to the name. 294 */ 295 hostname = hp->h_name; 296 #ifdef KERBEROS 297 if (!use_kerberos) 298 #endif 299 if (check_all || local_domain(hp->h_name)) { 300 strncpy(remotehost, hp->h_name, sizeof(remotehost) - 1); 301 remotehost[sizeof(remotehost) - 1] = 0; 302 errorhost = remotehost; 303 hp = gethostbyname(remotehost); 304 if (hp == NULL) { 305 syslog(LOG_INFO, 306 "Couldn't look up address for %s", 307 remotehost); 308 errorstr = 309 "Couldn't look up address for your host (%s)\n"; 310 hostname = inet_ntoa(fromp->sin_addr); 311 } else for (; ; hp->h_addr_list++) { 312 if (hp->h_addr_list[0] == NULL) { 313 syslog(LOG_NOTICE, 314 "Host addr %s not listed for host %s", 315 inet_ntoa(fromp->sin_addr), 316 hp->h_name); 317 errorstr = 318 "Host address mismatch for %s\n"; 319 hostname = inet_ntoa(fromp->sin_addr); 320 break; 321 } 322 if (!bcmp(hp->h_addr_list[0], 323 (caddr_t)&fromp->sin_addr, 324 sizeof(fromp->sin_addr))) { 325 hostname = hp->h_name; 326 break; 327 } 328 } 329 } 330 } else 331 errorhost = hostname = inet_ntoa(fromp->sin_addr); 332 333 #ifdef KERBEROS 334 if (use_kerberos) { 335 kdata = (AUTH_DAT *) authbuf; 336 ticket = (KTEXT) tickbuf; 337 authopts = 0L; 338 strcpy(instance, "*"); 339 version[VERSION_SIZE - 1] = '\0'; 340 rc = krb_recvauth(authopts, 0, ticket, "rcmd", 341 instance, &fromaddr, 342 (struct sockaddr_in *) 0, 343 kdata, "", (bit_64 *) 0, version); 344 if (rc != KSUCCESS) { 345 error("Kerberos authentication failure: %s\n", 346 krb_err_txt[rc]); 347 exit(1); 348 } 349 } else 350 #endif 351 getstr(remuser, sizeof(remuser), "remuser"); 352 353 getstr(locuser, sizeof(locuser), "locuser"); 354 getstr(cmdbuf, sizeof(cmdbuf), "command"); 355 setpwent(); 356 pwd = getpwnam(locuser); 357 if (pwd == NULL) { 358 if (errorstr == NULL) 359 errorstr = "Login incorrect.\n"; 360 goto fail; 361 } 362 if (chdir(pwd->pw_dir) < 0) { 363 (void) chdir("/"); 364 #ifdef notdef 365 error("No remote directory.\n"); 366 exit(1); 367 #endif 368 } 369 370 #ifdef KERBEROS 371 if (use_kerberos) { 372 if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') { 373 if (kuserok(kdata, locuser) != 0) { 374 syslog(LOG_NOTICE|LOG_AUTH, 375 "Kerberos rsh denied to %s.%s@%s", 376 kdata->pname, kdata->pinst, kdata->prealm); 377 error("Permission denied.\n"); 378 exit(1); 379 } 380 } 381 } else 382 #endif 383 384 if (errorstr || 385 pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' && 386 ruserok(hostname, pwd->pw_uid == 0, remuser, locuser) < 0) { 387 fail: 388 if (errorstr == NULL) 389 errorstr = "Permission denied.\n"; 390 error(errorstr, errorhost); 391 exit(1); 392 } 393 394 if (pwd->pw_uid && !access(_PATH_NOLOGIN, F_OK)) { 395 error("Logins currently disabled.\n"); 396 exit(1); 397 } 398 399 (void) write(2, "\0", 1); 400 sent_null = 1; 401 402 if (port) { 403 if (pipe(pv) < 0) { 404 error("Can't make pipe.\n"); 405 exit(1); 406 } 407 pid = fork(); 408 if (pid == -1) { 409 error("Can't fork; try again.\n"); 410 exit(1); 411 } 412 if (pid) { 413 { 414 (void) close(0); (void) close(1); 415 } 416 (void) close(2); (void) close(pv[1]); 417 418 FD_ZERO(&readfrom); 419 FD_SET(s, &readfrom); 420 FD_SET(pv[0], &readfrom); 421 if (pv[0] > s) 422 nfd = pv[0]; 423 else 424 nfd = s; 425 ioctl(pv[0], FIONBIO, (char *)&one); 426 427 /* should set s nbio! */ 428 nfd++; 429 do { 430 ready = readfrom; 431 if (select(nfd, &ready, (fd_set *)0, 432 (fd_set *)0, (struct timeval *)0) < 0) 433 break; 434 if (FD_ISSET(s, &ready)) { 435 int ret; 436 ret = read(s, &sig, 1); 437 if (ret <= 0) 438 FD_CLR(s, &readfrom); 439 else 440 killpg(pid, sig); 441 } 442 if (FD_ISSET(pv[0], &ready)) { 443 errno = 0; 444 cc = read(pv[0], buf, sizeof(buf)); 445 if (cc <= 0) { 446 shutdown(s, 1+1); 447 FD_CLR(pv[0], &readfrom); 448 } else { 449 (void) 450 write(s, buf, cc); 451 } 452 } 453 454 } while (FD_ISSET(s, &readfrom) || 455 FD_ISSET(pv[0], &readfrom)); 456 exit(0); 457 } 458 setpgrp(0, getpid()); 459 (void) close(s); (void) close(pv[0]); 460 dup2(pv[1], 2); 461 close(pv[1]); 462 } 463 if (*pwd->pw_shell == '\0') 464 pwd->pw_shell = _PATH_BSHELL; 465 #if BSD > 43 466 if (setlogin(pwd->pw_name) < 0) 467 syslog(LOG_ERR, "setlogin() failed: %m"); 468 #endif 469 (void) setgid((gid_t)pwd->pw_gid); 470 initgroups(pwd->pw_name, pwd->pw_gid); 471 (void) setuid((uid_t)pwd->pw_uid); 472 environ = envinit; 473 strncat(homedir, pwd->pw_dir, sizeof(homedir)-6); 474 strcat(path, _PATH_DEFPATH); 475 strncat(shell, pwd->pw_shell, sizeof(shell)-7); 476 strncat(username, pwd->pw_name, sizeof(username)-6); 477 cp = rindex(pwd->pw_shell, '/'); 478 if (cp) 479 cp++; 480 else 481 cp = pwd->pw_shell; 482 endpwent(); 483 if (pwd->pw_uid == 0) { 484 #ifdef KERBEROS 485 if (use_kerberos) 486 syslog(LOG_INFO|LOG_AUTH, 487 "ROOT Kerberos shell from %s.%s@%s on %s, comm: %s\n", 488 kdata->pname, kdata->pinst, kdata->prealm, 489 hostname, cmdbuf); 490 else 491 #endif 492 syslog(LOG_INFO|LOG_AUTH, 493 "ROOT shell from %s@%s, comm: %s\n", 494 remuser, hostname, cmdbuf); 495 } 496 execl(pwd->pw_shell, cp, "-c", cmdbuf, 0); 497 perror(pwd->pw_shell); 498 exit(1); 499 } 500 501 /* 502 * Report error to client. 503 * Note: can't be used until second socket has connected 504 * to client, or older clients will hang waiting 505 * for that connection first. 506 */ 507 /*VARARGS1*/ 508 error(fmt, a1, a2, a3) 509 char *fmt; 510 int a1, a2, a3; 511 { 512 char buf[BUFSIZ], *bp = buf; 513 514 if (sent_null == 0) 515 *bp++ = 1; 516 (void) sprintf(bp, fmt, a1, a2, a3); 517 (void) write(2, buf, strlen(buf)); 518 } 519 520 getstr(buf, cnt, err) 521 char *buf; 522 int cnt; 523 char *err; 524 { 525 char c; 526 527 do { 528 if (read(0, &c, 1) != 1) 529 exit(1); 530 *buf++ = c; 531 if (--cnt == 0) { 532 error("%s too long\n", err); 533 exit(1); 534 } 535 } while (c != 0); 536 } 537 538 /* 539 * Check whether host h is in our local domain, 540 * defined as sharing the last two components of the domain part, 541 * or the entire domain part if the local domain has only one component. 542 * If either name is unqualified (contains no '.'), 543 * assume that the host is local, as it will be 544 * interpreted as such. 545 */ 546 local_domain(h) 547 char *h; 548 { 549 char localhost[MAXHOSTNAMELEN]; 550 char *p1, *p2, *topdomain(); 551 552 localhost[0] = 0; 553 (void) gethostname(localhost, sizeof(localhost)); 554 p1 = topdomain(localhost); 555 p2 = topdomain(h); 556 if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2)) 557 return(1); 558 return(0); 559 } 560 561 char * 562 topdomain(h) 563 char *h; 564 { 565 register char *p; 566 char *maybe = NULL; 567 int dots = 0; 568 569 for (p = h + strlen(h); p >= h; p--) { 570 if (*p == '.') { 571 if (++dots == 2) 572 return (p); 573 maybe = p; 574 } 575 } 576 return (maybe); 577 } 578 579 usage() 580 { 581 syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS); 582 } 583