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