1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 3011 jbeck * Common Development and Distribution License (the "License"). 6 3011 jbeck * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 3011 jbeck 22 0 stevel /* 23 6536 gtb * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel /* Copyright (c) 1983-1989 AT&T */ 28 0 stevel /* All Rights Reserved */ 29 0 stevel 30 0 stevel /* 31 0 stevel * Portions of this source code were derived from Berkeley 4.3 BSD 32 0 stevel * under license from the Regents of the University of California. 33 0 stevel */ 34 0 stevel 35 0 stevel #define _FILE_OFFSET_BITS 64 36 0 stevel 37 0 stevel /* 38 0 stevel * remote shell server: 39 0 stevel * remuser\0 40 0 stevel * locuser\0 41 0 stevel * command\0 42 0 stevel * data 43 0 stevel */ 44 0 stevel #include <sys/types.h> 45 0 stevel #include <sys/ioctl.h> 46 0 stevel #include <sys/telioctl.h> 47 0 stevel #include <sys/param.h> 48 0 stevel #include <sys/socket.h> 49 0 stevel #include <sys/time.h> 50 0 stevel #include <sys/stat.h> 51 0 stevel #include <sys/file.h> 52 0 stevel #include <sys/select.h> 53 0 stevel 54 0 stevel #include <netinet/in.h> 55 0 stevel 56 0 stevel #include <arpa/inet.h> 57 0 stevel 58 0 stevel #include <unistd.h> 59 0 stevel #include <string.h> 60 0 stevel #include <stdio.h> 61 0 stevel #include <stdarg.h> 62 0 stevel #include <errno.h> 63 0 stevel #include <pwd.h> 64 0 stevel #include <grp.h> 65 0 stevel #include <signal.h> 66 0 stevel #include <netdb.h> 67 0 stevel #include <syslog.h> 68 0 stevel #include <fcntl.h> 69 0 stevel #include <ctype.h> 70 0 stevel #include <locale.h> 71 0 stevel 72 0 stevel #include <sys/resource.h> 73 0 stevel #include <sys/filio.h> 74 0 stevel #include <shadow.h> 75 0 stevel #include <stdlib.h> 76 0 stevel 77 0 stevel #include <security/pam_appl.h> 78 8126 Joep #include <deflt.h> 79 0 stevel 80 0 stevel #include <k5-int.h> 81 0 stevel #include <krb5_repository.h> 82 0 stevel #include <com_err.h> 83 0 stevel #include <kcmd.h> 84 3011 jbeck 85 3011 jbeck #include <addr_match.h> 86 6536 gtb #include <store_forw_creds.h> 87 0 stevel 88 0 stevel #ifndef NCARGS 89 0 stevel #define NCARGS 5120 90 0 stevel #endif /* !NCARGS */ 91 0 stevel 92 0 stevel static void error(char *, ...); 93 0 stevel static void doit(int, struct sockaddr_storage *, char **); 94 0 stevel static void getstr(int, char *, int, char *); 95 0 stevel 96 0 stevel static int legalenvvar(char *); 97 0 stevel static void add_to_envinit(char *); 98 0 stevel static int locale_envmatch(char *, char *); 99 0 stevel 100 0 stevel /* Function decls. for functions not in any header file. (Grrrr.) */ 101 0 stevel extern int audit_rshd_setup(void); 102 0 stevel extern int audit_rshd_success(char *, char *, char *, char *); 103 0 stevel extern int audit_rshd_fail(char *, char *, char *, char *, char *); 104 0 stevel extern int audit_settid(int); 105 0 stevel 106 0 stevel static int do_encrypt = 0; 107 0 stevel static pam_handle_t *pamh; 108 0 stevel 109 0 stevel /* 110 0 stevel * This is the shell/kshell daemon. The very basic protocol for checking 111 0 stevel * authentication and authorization is: 112 0 stevel * 1) Check authentication. 113 0 stevel * 2) Check authorization via the access-control files: 114 0 stevel * ~/.k5login (using krb5_kuserok) and/or 115 0 stevel * Execute command if configured authoriztion checks pass, else deny 116 0 stevel * permission. 117 0 stevel * 118 0 stevel * The configuration is done either by command-line arguments passed by inetd, 119 0 stevel * or by the name of the daemon. If command-line arguments are present, they 120 0 stevel * take priority. The options are: 121 0 stevel * -k allow kerberos authentication (krb5 only; krb4 support is not provided) 122 0 stevel * -5 same as `-k', mainly for compatability with MIT 123 0 stevel * -e allow encrypted session 124 0 stevel * -c demand authenticator checksum 125 0 stevel * -i ignore authenticator checksum 126 0 stevel * -U Refuse connections that cannot be mapped to a name via `gethostbyname' 127 0 stevel * -s <tos> Set the IP TOS option 128 0 stevel * -S <keytab> Set the keytab file to use 129 0 stevel * -M <realm> Set the Kerberos realm to use 130 0 stevel */ 131 0 stevel 132 0 stevel #define ARGSTR "ek5ciUD:M:S:L:?:" 133 0 stevel #define RSHD_BUFSIZ (50 * 1024) 134 0 stevel 135 0 stevel static krb5_context bsd_context; 136 0 stevel static krb5_keytab keytab = NULL; 137 0 stevel static krb5_ccache ccache = NULL; 138 0 stevel static krb5_keyblock *sessionkey = NULL; 139 0 stevel 140 0 stevel static int require_encrypt = 0; 141 0 stevel static int resolve_hostname = 0; 142 0 stevel static int krb5auth_flag = 0; /* Flag set, when KERBEROS is enabled */ 143 0 stevel static enum kcmd_proto kcmd_protocol; 144 0 stevel 145 0 stevel #ifdef DEBUG 146 0 stevel static int debug_port = 0; 147 0 stevel #endif /* DEBUG */ 148 0 stevel 149 0 stevel /* 150 0 stevel * There are two authentication related masks: 151 0 stevel * auth_ok and auth_sent. 152 0 stevel * The auth_ok mask is the or'ing of authentication 153 0 stevel * systems any one of which can be used. 154 0 stevel * The auth_sent mask is the or'ing of one or more authentication/authorization 155 0 stevel * systems that succeeded. If the and'ing 156 0 stevel * of these two masks is true, then authorization is successful. 157 0 stevel */ 158 0 stevel 159 0 stevel #define AUTH_KRB5 (0x2) 160 0 stevel static int auth_ok = 0; 161 0 stevel static int auth_sent = 0; 162 0 stevel static int checksum_required = 0; 163 0 stevel static int checksum_ignored = 0; 164 0 stevel 165 0 stevel /* 166 0 stevel * Leave room for 4 environment variables to be passed. 167 0 stevel * The "-L env_var" option has been added primarily to 168 0 stevel * maintain compatability with MIT. 169 0 stevel */ 170 0 stevel #define MAXENV 4 171 0 stevel static char *save_env[MAXENV]; 172 0 stevel static int num_env = 0; 173 0 stevel 174 0 stevel static void usage(void); 175 0 stevel static krb5_error_code recvauth(int, int *); 176 0 stevel 177 0 stevel /*ARGSUSED*/ 178 473 bw int 179 0 stevel main(int argc, char **argv, char **renvp) 180 0 stevel { 181 0 stevel struct linger linger; 182 0 stevel int on = 1, fromlen; 183 0 stevel struct sockaddr_storage from; 184 0 stevel int fd = 0; 185 0 stevel 186 0 stevel extern int opterr, optind; 187 0 stevel extern char *optarg; 188 0 stevel int ch; 189 0 stevel int tos = -1; 190 0 stevel krb5_error_code status; 191 0 stevel 192 0 stevel openlog("rsh", LOG_PID | LOG_ODELAY, LOG_DAEMON); 193 0 stevel (void) audit_rshd_setup(); /* BSM */ 194 0 stevel fromlen = sizeof (from); 195 0 stevel 196 0 stevel (void) setlocale(LC_ALL, ""); 197 0 stevel 198 0 stevel /* 199 0 stevel * Analyze parameters. 200 0 stevel */ 201 0 stevel opterr = 0; 202 0 stevel while ((ch = getopt(argc, argv, ARGSTR)) != EOF) 203 0 stevel switch (ch) { 204 0 stevel case '5': 205 0 stevel case 'k': 206 0 stevel auth_ok |= AUTH_KRB5; 207 0 stevel krb5auth_flag++; 208 0 stevel break; 209 0 stevel 210 0 stevel case 'c': 211 0 stevel checksum_required = 1; 212 0 stevel krb5auth_flag++; 213 0 stevel break; 214 0 stevel case 'i': 215 0 stevel checksum_ignored = 1; 216 0 stevel krb5auth_flag++; 217 0 stevel break; 218 0 stevel 219 0 stevel case 'e': 220 0 stevel require_encrypt = 1; 221 0 stevel krb5auth_flag++; 222 0 stevel break; 223 0 stevel #ifdef DEBUG 224 0 stevel case 'D': 225 0 stevel debug_port = atoi(optarg); 226 0 stevel break; 227 0 stevel #endif /* DEBUG */ 228 0 stevel case 'U': 229 0 stevel resolve_hostname = 1; 230 0 stevel break; 231 0 stevel 232 0 stevel case 'M': 233 0 stevel krb5_set_default_realm(bsd_context, optarg); 234 0 stevel krb5auth_flag++; 235 0 stevel break; 236 0 stevel 237 0 stevel case 'S': 238 0 stevel if ((status = krb5_kt_resolve(bsd_context, optarg, 239 0 stevel &keytab))) { 240 0 stevel com_err("rsh", status, 241 0 stevel gettext("while resolving " 242 0 stevel "srvtab file %s"), optarg); 243 0 stevel exit(2); 244 0 stevel } 245 0 stevel krb5auth_flag++; 246 0 stevel break; 247 0 stevel 248 0 stevel case 's': 249 0 stevel if (optarg == NULL || ((tos = atoi(optarg)) < 0) || 250 0 stevel (tos > 255)) { 251 0 stevel syslog(LOG_ERR, "rshd: illegal tos value: " 252 0 stevel "%s\n", optarg); 253 0 stevel } 254 0 stevel break; 255 0 stevel 256 0 stevel case 'L': 257 0 stevel if (num_env < MAXENV) { 258 0 stevel save_env[num_env] = strdup(optarg); 259 0 stevel if (!save_env[num_env++]) { 260 0 stevel com_err("rsh", ENOMEM, 261 0 stevel gettext("in saving env")); 262 0 stevel exit(2); 263 0 stevel } 264 0 stevel } else { 265 0 stevel (void) fprintf(stderr, gettext("rshd: Only %d" 266 0 stevel " -L arguments allowed\n"), 267 0 stevel MAXENV); 268 0 stevel exit(2); 269 0 stevel } 270 0 stevel break; 271 0 stevel 272 0 stevel case '?': 273 0 stevel default: 274 0 stevel usage(); 275 0 stevel exit(1); 276 0 stevel break; 277 0 stevel } 278 0 stevel 279 0 stevel if (optind == 0) { 280 0 stevel usage(); 281 0 stevel exit(1); 282 0 stevel } 283 0 stevel argc -= optind; 284 0 stevel argv += optind; 285 0 stevel 286 0 stevel if (krb5auth_flag > 0) { 287 0 stevel status = krb5_init_context(&bsd_context); 288 0 stevel if (status) { 289 0 stevel syslog(LOG_ERR, "Error initializing krb5: %s", 290 0 stevel error_message(status)); 291 0 stevel exit(1); 292 0 stevel } 293 0 stevel } 294 0 stevel 295 0 stevel if (!checksum_required && !checksum_ignored) 296 0 stevel checksum_ignored = 1; 297 0 stevel 298 0 stevel if (checksum_required && checksum_ignored) { 299 0 stevel syslog(LOG_CRIT, gettext("Checksums are required and ignored." 300 0 stevel "These options are mutually exclusive" 301 0 stevel "--check the documentation.")); 302 0 stevel error("Configuration error: mutually exclusive " 303 0 stevel "options specified.\n"); 304 0 stevel exit(1); 305 0 stevel } 306 0 stevel 307 0 stevel #ifdef DEBUG 308 0 stevel if (debug_port) { 309 0 stevel int s; 310 0 stevel struct sockaddr_in sin; 311 0 stevel 312 0 stevel if ((s = socket(AF_INET, SOCK_STREAM, PF_UNSPEC)) < 0) { 313 0 stevel fprintf(stderr, gettext("Error in socket: %s\n"), 314 0 stevel strerror(errno)); 315 0 stevel exit(2); 316 0 stevel } 317 0 stevel (void) memset((char *)&sin, 0, sizeof (sin)); 318 0 stevel sin.sin_family = AF_INET; 319 0 stevel sin.sin_port = htons(debug_port); 320 0 stevel sin.sin_addr.s_addr = INADDR_ANY; 321 0 stevel 322 0 stevel (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, 323 0 stevel (char *)&on, sizeof (on)); 324 0 stevel 325 0 stevel if ((bind(s, (struct sockaddr *)&sin, sizeof (sin))) < 0) { 326 0 stevel (void) fprintf(stderr, gettext("Error in bind: %s\n"), 327 0 stevel strerror(errno)); 328 0 stevel exit(2); 329 0 stevel } 330 0 stevel if ((listen(s, 5)) < 0) { 331 0 stevel (void) fprintf(stderr, gettext("Error in listen: %s\n"), 332 0 stevel strerror(errno)); 333 0 stevel exit(2); 334 0 stevel } 335 0 stevel if ((fd = accept(s, (struct sockaddr *)&from, 336 0 stevel &fromlen)) < 0) { 337 0 stevel (void) fprintf(stderr, gettext("Error in accept: %s\n"), 338 0 stevel strerror(errno)); 339 0 stevel exit(2); 340 0 stevel } 341 0 stevel (void) close(s); 342 0 stevel } 343 0 stevel else 344 0 stevel #endif /* DEBUG */ 345 0 stevel { 346 0 stevel if (getpeername(STDIN_FILENO, (struct sockaddr *)&from, 347 0 stevel (socklen_t *)&fromlen) < 0) { 348 0 stevel (void) fprintf(stderr, "rshd: "); 349 0 stevel perror("getpeername"); 350 0 stevel _exit(1); 351 0 stevel } 352 0 stevel fd = STDIN_FILENO; 353 0 stevel } 354 0 stevel 355 0 stevel if (audit_settid(fd) != 0) { 356 0 stevel perror("settid"); 357 0 stevel exit(1); 358 0 stevel } 359 0 stevel 360 0 stevel if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, 361 0 stevel sizeof (on)) < 0) 362 0 stevel syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m"); 363 0 stevel linger.l_onoff = 1; 364 0 stevel linger.l_linger = 60; /* XXX */ 365 0 stevel if (setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&linger, 366 0 stevel sizeof (linger)) < 0) 367 0 stevel syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m"); 368 0 stevel 369 0 stevel if ((tos != -1) && (setsockopt(fd, IPPROTO_IP, IP_TOS, (char *)&tos, 370 0 stevel sizeof (tos)) < 0) && 371 0 stevel (errno != ENOPROTOOPT)) { 372 0 stevel syslog(LOG_ERR, "setsockopt (IP_TOS %d): %m"); 373 0 stevel } 374 0 stevel 375 0 stevel doit(dup(fd), &from, renvp); 376 473 bw return (0); 377 0 stevel } 378 0 stevel 379 0 stevel /* 380 0 stevel * locale environments to be passed to shells. 381 0 stevel */ 382 0 stevel static char *localeenv[] = { 383 0 stevel "LANG", 384 0 stevel "LC_CTYPE", "LC_NUMERIC", "LC_TIME", "LC_COLLATE", 385 0 stevel "LC_MONETARY", "LC_MESSAGES", "LC_ALL", NULL}; 386 0 stevel 387 0 stevel /* 388 0 stevel * The following is for the environment variable list 389 0 stevel * used in the call to execle(). envinit is declared here, 390 0 stevel * but populated after the call to getpwnam(). 391 0 stevel */ 392 0 stevel static char *homedir; /* "HOME=" */ 393 0 stevel static char *shell; /* "SHELL=" */ 394 0 stevel static char *username; /* "USER=" */ 395 0 stevel static char *tz; /* "TZ=" */ 396 0 stevel 397 0 stevel static char homestr[] = "HOME="; 398 0 stevel static char shellstr[] = "SHELL="; 399 0 stevel static char userstr[] = "USER="; 400 0 stevel static char tzstr[] = "TZ="; 401 0 stevel 402 0 stevel static char **envinit; 403 0 stevel #define PAM_ENV_ELIM 16 /* allow 16 PAM environment variables */ 404 0 stevel #define USERNAME_LEN 16 /* maximum number of characters in user name */ 405 0 stevel 406 0 stevel /* 407 0 stevel * See PSARC opinion 1992/025 408 0 stevel */ 409 0 stevel static char userpath[] = "PATH=/usr/bin:"; 410 0 stevel static char rootpath[] = "PATH=/usr/sbin:/usr/bin"; 411 0 stevel 412 0 stevel static char cmdbuf[NCARGS+1]; 413 0 stevel static char hostname [MAXHOSTNAMELEN + 1]; 414 0 stevel static char locuser[USERNAME_LEN + 1]; 415 0 stevel static char remuser[USERNAME_LEN + 1]; 416 0 stevel 417 0 stevel #define KRB5_RECVAUTH_V5 5 418 0 stevel #define SIZEOF_INADDR sizeof (struct in_addr) 419 0 stevel 420 0 stevel #define MAX_REPOSITORY_LEN 255 421 0 stevel static char repository[MAX_REPOSITORY_LEN]; 422 0 stevel 423 0 stevel static char *kremuser; 424 0 stevel static krb5_principal client = NULL; 425 0 stevel 426 0 stevel static char remote_addr[64]; 427 0 stevel static char local_addr[64]; 428 0 stevel 429 8126 Joep #define _PATH_DEFAULT_LOGIN "/etc/default/login" 430 8126 Joep 431 0 stevel static void 432 0 stevel doit(int f, struct sockaddr_storage *fromp, char **renvp) 433 0 stevel { 434 0 stevel char *cp; 435 0 stevel 436 0 stevel struct passwd *pwd; 437 0 stevel char *path; 438 0 stevel char *tzenv; 439 0 stevel struct spwd *shpwd; 440 0 stevel struct stat statb; 441 0 stevel char **lenvp; 442 0 stevel 443 0 stevel krb5_error_code status; 444 0 stevel int valid_checksum; 445 0 stevel int cnt; 446 0 stevel int sin_len; 447 0 stevel struct sockaddr_in localaddr; 448 0 stevel 449 0 stevel int s; 450 0 stevel in_port_t port; 451 0 stevel pid_t pid; 452 0 stevel int pv[2], pw[2], px[2], cc; 453 0 stevel char buf[RSHD_BUFSIZ]; 454 0 stevel char sig; 455 0 stevel int one = 1; 456 0 stevel int v = 0; 457 0 stevel int err = 0; 458 0 stevel int idx = 0; 459 0 stevel char **pam_env; 460 0 stevel char abuf[INET6_ADDRSTRLEN]; 461 0 stevel struct sockaddr_in *sin; 462 0 stevel struct sockaddr_in6 *sin6; 463 0 stevel int fromplen; 464 0 stevel int homedir_len, shell_len, username_len, tz_len; 465 0 stevel int no_name; 466 3011 jbeck boolean_t bad_port; 467 0 stevel int netf = 0; 468 0 stevel 469 0 stevel (void) signal(SIGINT, SIG_DFL); 470 0 stevel (void) signal(SIGQUIT, SIG_DFL); 471 0 stevel (void) signal(SIGTERM, SIG_DFL); 472 0 stevel (void) signal(SIGXCPU, SIG_DFL); 473 0 stevel (void) signal(SIGXFSZ, SIG_DFL); 474 0 stevel (void) sigset(SIGCHLD, SIG_IGN); 475 0 stevel (void) signal(SIGPIPE, SIG_DFL); 476 0 stevel (void) signal(SIGHUP, SIG_DFL); 477 0 stevel 478 0 stevel #ifdef DEBUG 479 0 stevel { int t = open("/dev/tty", 2); 480 0 stevel if (t >= 0) { 481 0 stevel (void) setsid(); 482 0 stevel (void) close(t); 483 0 stevel } 484 0 stevel } 485 0 stevel #endif 486 0 stevel if (fromp->ss_family == AF_INET) { 487 0 stevel sin = (struct sockaddr_in *)fromp; 488 0 stevel port = ntohs((ushort_t)sin->sin_port); 489 0 stevel fromplen = sizeof (struct sockaddr_in); 490 0 stevel } else if (fromp->ss_family == AF_INET6) { 491 0 stevel sin6 = (struct sockaddr_in6 *)fromp; 492 0 stevel port = ntohs((ushort_t)sin6->sin6_port); 493 0 stevel fromplen = sizeof (struct sockaddr_in6); 494 0 stevel } else { 495 0 stevel syslog(LOG_ERR, "wrong address family\n"); 496 0 stevel exit(1); 497 0 stevel } 498 0 stevel 499 3011 jbeck if (fromp->ss_family == AF_INET6) { 500 3011 jbeck if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 501 3011 jbeck struct in_addr ipv4_addr; 502 3011 jbeck 503 3011 jbeck IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, &ipv4_addr); 504 3011 jbeck (void) inet_ntop(AF_INET, &ipv4_addr, abuf, 505 3011 jbeck sizeof (abuf)); 506 3011 jbeck } else { 507 3011 jbeck (void) inet_ntop(AF_INET6, &sin6->sin6_addr, abuf, 508 3011 jbeck sizeof (abuf)); 509 3011 jbeck } 510 3011 jbeck } else if (fromp->ss_family == AF_INET) { 511 3011 jbeck (void) inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof (abuf)); 512 3011 jbeck } 513 3011 jbeck 514 0 stevel sin_len = sizeof (struct sockaddr_in); 515 3011 jbeck if (getsockname(f, (struct sockaddr *)&localaddr, &sin_len) < 0) { 516 0 stevel perror("getsockname"); 517 0 stevel exit(1); 518 0 stevel } 519 0 stevel 520 0 stevel netf = f; 521 0 stevel 522 0 stevel bad_port = (port >= IPPORT_RESERVED || 523 0 stevel port < (uint_t)(IPPORT_RESERVED/2)); 524 0 stevel 525 3011 jbeck /* Get the name of the client side host to use later */ 526 0 stevel no_name = (getnameinfo((const struct sockaddr *) fromp, fromplen, 527 0 stevel hostname, sizeof (hostname), NULL, 0, 0) != 0); 528 0 stevel 529 3011 jbeck if (bad_port || no_name != 0) { 530 3011 jbeck /* 531 3011 jbeck * If there is no host name available then use the 532 3011 jbeck * IP address to identify the host in the PAM call 533 3011 jbeck * below. Do the same if a bad port was used, to 534 3011 jbeck * prevent untrustworthy authentication. 535 3011 jbeck */ 536 3011 jbeck (void) strlcpy(hostname, abuf, sizeof (hostname)); 537 3011 jbeck } 538 3011 jbeck 539 3011 jbeck if (no_name != 0) { 540 3011 jbeck /* 541 3011 jbeck * If the '-U' option was given on the cmd line, 542 3011 jbeck * we must be able to lookup the hostname 543 3011 jbeck */ 544 3011 jbeck if (resolve_hostname) { 545 3011 jbeck syslog(LOG_ERR, "rshd: Couldn't resolve your " 546 3011 jbeck "address into a host name.\r\n Please " 547 3011 jbeck "contact your net administrator"); 548 3011 jbeck exit(1); 549 0 stevel } 550 3011 jbeck } else { 551 3011 jbeck /* 552 3011 jbeck * Even if getnameinfo() succeeded, we still have to check 553 3011 jbeck * for spoofing. 554 3011 jbeck */ 555 3011 jbeck check_address("rshd", fromp, sin, sin6, abuf, hostname, 556 3011 jbeck sizeof (hostname)); 557 0 stevel } 558 0 stevel 559 0 stevel if (!krb5auth_flag && bad_port) { 560 0 stevel if (no_name) 561 0 stevel syslog(LOG_NOTICE, "connection from %s - " 562 0 stevel "bad port\n", abuf); 563 0 stevel else 564 0 stevel syslog(LOG_NOTICE, "connection from %s (%s) - " 565 0 stevel "bad port\n", hostname, abuf); 566 0 stevel exit(1); 567 0 stevel } 568 0 stevel 569 0 stevel (void) alarm(60); 570 0 stevel port = 0; 571 0 stevel for (;;) { 572 0 stevel char c; 573 0 stevel if ((cc = read(f, &c, 1)) != 1) { 574 0 stevel if (cc < 0) 575 0 stevel syslog(LOG_NOTICE, "read: %m"); 576 0 stevel (void) shutdown(f, 1+1); 577 0 stevel exit(1); 578 0 stevel } 579 0 stevel if (c == 0) 580 0 stevel break; 581 0 stevel port = port * 10 + c - '0'; 582 0 stevel } 583 0 stevel (void) alarm(0); 584 0 stevel if (port != 0) { 585 0 stevel int lport = 0; 586 0 stevel struct sockaddr_storage ctl_addr; 587 0 stevel int addrlen; 588 0 stevel 589 0 stevel (void) memset(&ctl_addr, 0, sizeof (ctl_addr)); 590 0 stevel addrlen = sizeof (ctl_addr); 591 0 stevel if (getsockname(f, (struct sockaddr *)&ctl_addr, 592 0 stevel &addrlen) < 0) { 593 0 stevel syslog(LOG_ERR, "getsockname: %m"); 594 0 stevel exit(1); 595 0 stevel } 596 0 stevel get_port: 597 0 stevel /* 598 0 stevel * 0 means that rresvport_addr() will bind to a port in 599 0 stevel * the anonymous priviledged port range. 600 0 stevel */ 601 0 stevel if (krb5auth_flag) { 602 0 stevel /* 603 0 stevel * Kerberos does not support IPv6 yet. 604 0 stevel */ 605 0 stevel lport = IPPORT_RESERVED - 1; 606 0 stevel } 607 0 stevel s = rresvport_addr(&lport, &ctl_addr); 608 0 stevel 609 0 stevel if (s < 0) { 610 0 stevel syslog(LOG_ERR, "can't get stderr port: %m"); 611 0 stevel exit(1); 612 0 stevel } 613 0 stevel if (!krb5auth_flag && (port >= IPPORT_RESERVED)) { 614 0 stevel syslog(LOG_ERR, "2nd port not reserved\n"); 615 0 stevel exit(1); 616 0 stevel } 617 0 stevel if (fromp->ss_family == AF_INET) { 618 0 stevel sin->sin_port = htons((ushort_t)port); 619 0 stevel } else if (fromp->ss_family == AF_INET6) { 620 0 stevel sin6->sin6_port = htons((ushort_t)port); 621 0 stevel } 622 0 stevel if (connect(s, (struct sockaddr *)fromp, fromplen) < 0) { 623 0 stevel if (errno == EADDRINUSE) { 624 0 stevel (void) close(s); 625 0 stevel goto get_port; 626 0 stevel } 627 0 stevel syslog(LOG_INFO, "connect second port: %m"); 628 0 stevel exit(1); 629 0 stevel } 630 0 stevel } 631 0 stevel (void) dup2(f, 0); 632 0 stevel (void) dup2(f, 1); 633 0 stevel (void) dup2(f, 2); 634 0 stevel 635 0 stevel #ifdef DEBUG 636 0 stevel syslog(LOG_NOTICE, "rshd: Client hostname = %s", hostname); 637 0 stevel if (debug_port) 638 0 stevel syslog(LOG_NOTICE, "rshd: Debug port is %d", debug_port); 639 0 stevel if (krb5auth_flag > 0) 640 0 stevel syslog(LOG_NOTICE, "rshd: Kerberos mode is ON"); 641 0 stevel else 642 0 stevel syslog(LOG_NOTICE, "rshd: Kerberos mode is OFF"); 643 0 stevel #endif /* DEBUG */ 644 0 stevel 645 0 stevel if (krb5auth_flag > 0) { 646 0 stevel if ((status = recvauth(f, &valid_checksum))) { 647 0 stevel syslog(LOG_ERR, gettext("Kerberos Authentication " 648 0 stevel "failed \n")); 649 0 stevel error("Authentication failed: %s\n", 650 0 stevel error_message(status)); 651 0 stevel (void) audit_rshd_fail("Kerberos Authentication " 652 0 stevel "failed", hostname, remuser, locuser, cmdbuf); 653 0 stevel exit(1); 654 0 stevel } 655 0 stevel 656 0 stevel if (checksum_required && !valid_checksum && 657 0 stevel kcmd_protocol == KCMD_OLD_PROTOCOL) { 658 0 stevel syslog(LOG_WARNING, "Client did not supply required" 659 0 stevel " checksum--connection rejected."); 660 0 stevel error("Client did not supply required" 661 0 stevel "checksum--connection rejected.\n"); 662 0 stevel (void) audit_rshd_fail("Client did not supply required" 663 0 stevel " checksum--connection rejected.", hostname, 664 0 stevel remuser, locuser, cmdbuf); /* BSM */ 665 0 stevel goto signout; 666 0 stevel } 667 0 stevel 668 0 stevel /* 669 0 stevel * Authentication has succeeded, we now need 670 0 stevel * to check authorization. 671 0 stevel * 672 0 stevel * krb5_kuserok returns 1 if OK. 673 0 stevel */ 674 0 stevel if (client && krb5_kuserok(bsd_context, client, locuser)) { 675 0 stevel auth_sent |= AUTH_KRB5; 676 0 stevel } else { 677 0 stevel syslog(LOG_ERR, "Principal %s (%s@%s) for local user " 678 0 stevel "%s failed krb5_kuserok.\n", 679 0 stevel kremuser, remuser, hostname, locuser); 680 0 stevel } 681 0 stevel } else { 682 0 stevel getstr(netf, remuser, sizeof (remuser), "remuser"); 683 0 stevel getstr(netf, locuser, sizeof (locuser), "locuser"); 684 0 stevel getstr(netf, cmdbuf, sizeof (cmdbuf), "command"); 685 0 stevel } 686 0 stevel 687 0 stevel #ifdef DEBUG 688 0 stevel syslog(LOG_NOTICE, "rshd: locuser = %s, remuser = %s, cmdbuf = %s", 689 0 stevel locuser, remuser, cmdbuf); 690 0 stevel #endif /* DEBUG */ 691 0 stevel 692 0 stevel /* 693 0 stevel * Note that there is no rsh conv functions at present. 694 0 stevel */ 695 0 stevel if (krb5auth_flag > 0) { 696 0 stevel if ((err = pam_start("krsh", locuser, NULL, &pamh)) 697 0 stevel != PAM_SUCCESS) { 698 0 stevel syslog(LOG_ERR, "pam_start() failed: %s\n", 699 0 stevel pam_strerror(0, err)); 700 0 stevel exit(1); 701 0 stevel } 702 0 stevel } 703 0 stevel else 704 0 stevel { 705 0 stevel if ((err = pam_start("rsh", locuser, NULL, &pamh)) 706 0 stevel != PAM_SUCCESS) { 707 0 stevel syslog(LOG_ERR, "pam_start() failed: %s\n", 708 0 stevel pam_strerror(0, err)); 709 0 stevel exit(1); 710 0 stevel } 711 0 stevel } 712 0 stevel if ((err = pam_set_item(pamh, PAM_RHOST, hostname)) != PAM_SUCCESS) { 713 0 stevel syslog(LOG_ERR, "pam_set_item() failed: %s\n", 714 0 stevel pam_strerror(pamh, err)); 715 0 stevel exit(1); 716 0 stevel } 717 0 stevel if ((err = pam_set_item(pamh, PAM_RUSER, remuser)) != PAM_SUCCESS) { 718 0 stevel syslog(LOG_ERR, "pam_set_item() failed: %s\n", 719 0 stevel pam_strerror(pamh, err)); 720 0 stevel exit(1); 721 0 stevel } 722 0 stevel 723 0 stevel pwd = getpwnam(locuser); 724 0 stevel shpwd = getspnam(locuser); 725 0 stevel if ((pwd == NULL) || (shpwd == NULL)) { 726 0 stevel if (krb5auth_flag > 0) 727 0 stevel syslog(LOG_ERR, "Principal %s (%s@%s) for local user " 728 0 stevel "%s has no account.\n", kremuser, remuser, 729 0 stevel hostname, locuser); 730 0 stevel error("permission denied.\n"); 731 0 stevel (void) audit_rshd_fail("Login incorrect", hostname, 732 0 stevel remuser, locuser, cmdbuf); /* BSM */ 733 0 stevel exit(1); 734 0 stevel } 735 0 stevel 736 0 stevel if (krb5auth_flag > 0) { 737 0 stevel (void) snprintf(repository, sizeof (repository), 738 0 stevel KRB5_REPOSITORY_NAME); 739 0 stevel /* 740 0 stevel * We currently only support special handling of the 741 0 stevel * KRB5 PAM repository 742 0 stevel */ 743 0 stevel if (strlen(locuser) != 0) { 744 0 stevel krb5_repository_data_t krb5_data; 745 0 stevel pam_repository_t pam_rep_data; 746 0 stevel 747 0 stevel krb5_data.principal = locuser; 748 0 stevel krb5_data.flags = SUNW_PAM_KRB5_ALREADY_AUTHENTICATED; 749 0 stevel 750 0 stevel pam_rep_data.type = repository; 751 0 stevel pam_rep_data.scope = (void *)&krb5_data; 752 0 stevel pam_rep_data.scope_len = sizeof (krb5_data); 753 0 stevel 754 0 stevel (void) pam_set_item(pamh, PAM_REPOSITORY, 755 0 stevel (void *)&pam_rep_data); 756 0 stevel } 757 0 stevel } 758 0 stevel 759 8126 Joep if (shpwd->sp_pwdp != 0) { 760 8126 Joep if (*shpwd->sp_pwdp != '\0') { 761 8126 Joep if ((v = pam_authenticate(pamh, 0)) != PAM_SUCCESS) { 762 8126 Joep error("permission denied\n"); 763 8126 Joep (void) audit_rshd_fail("Permission denied", 764 8126 Joep hostname, remuser, locuser, cmdbuf); 765 8126 Joep (void) pam_end(pamh, v); 766 8126 Joep exit(1); 767 8126 Joep } 768 8126 Joep } else { 769 8126 Joep int flags; 770 8126 Joep char *p; 771 8126 Joep /* 772 8126 Joep * maintain 2.1 and 4.* and BSD semantics with 773 8126 Joep * anonymous rshd unless PASSREQ is set to YES in 774 8126 Joep * /etc/default/login: then we deny logins with empty 775 8126 Joep * passwords. 776 8126 Joep */ 777 8126 Joep if (defopen(_PATH_DEFAULT_LOGIN) == 0) { 778 8126 Joep flags = defcntl(DC_GETFLAGS, 0); 779 8126 Joep TURNOFF(flags, DC_CASE); 780 8126 Joep (void) defcntl(DC_SETFLAGS, flags); 781 8126 Joep 782 8126 Joep if ((p = defread("PASSREQ=")) != NULL && 783 8126 Joep strcasecmp(p, "YES") == 0) { 784 8126 Joep error("permission denied\n"); 785 8126 Joep (void) audit_rshd_fail( 786 8126 Joep "Permission denied", hostname, 787 8126 Joep remuser, locuser, cmdbuf); 788 8126 Joep (void) pam_end(pamh, PAM_ABORT); 789 8126 Joep (void) defopen(NULL); 790 8126 Joep syslog(LOG_AUTH|LOG_NOTICE, 791 8126 Joep "empty password not allowed for " 792 8126 Joep "%s from %s.", locuser, hostname); 793 8126 Joep exit(1); 794 8126 Joep } 795 8126 Joep (void) defopen(NULL); 796 8126 Joep } 797 8126 Joep /* 798 8126 Joep * /etc/default/login not found or PASSREQ not set 799 8126 Joep * to YES. Allow logins without passwords. 800 8126 Joep */ 801 8126 Joep } 802 0 stevel } 803 0 stevel 804 0 stevel if (krb5auth_flag > 0) { 805 0 stevel if (require_encrypt && (!do_encrypt)) { 806 0 stevel error("You must use encryption.\n"); 807 0 stevel (void) audit_rshd_fail("You must use encryption.", 808 0 stevel hostname, remuser, locuser, cmdbuf); /* BSM */ 809 0 stevel goto signout; 810 0 stevel } 811 0 stevel 812 0 stevel if (!(auth_ok & auth_sent)) { 813 0 stevel if (auth_sent) { 814 0 stevel error("Another authentication mechanism " 815 0 stevel "must be used to access this host.\n"); 816 0 stevel (void) audit_rshd_fail("Another authentication" 817 0 stevel " mechanism must be used to access" 818 0 stevel " this host.\n", hostname, remuser, 819 0 stevel locuser, cmdbuf); /* BSM */ 820 0 stevel goto signout; 821 0 stevel } else { 822 0 stevel error("Permission denied.\n"); 823 0 stevel (void) audit_rshd_fail("Permission denied.", 824 0 stevel hostname, remuser, locuser, cmdbuf); 825 0 stevel /* BSM */ 826 0 stevel goto signout; 827 0 stevel } 828 0 stevel } 829 0 stevel 830 0 stevel 831 0 stevel if (pwd->pw_uid && !access("/etc/nologin", F_OK)) { 832 0 stevel error("Logins currently disabled.\n"); 833 0 stevel (void) audit_rshd_fail("Logins currently disabled.", 834 0 stevel hostname, remuser, locuser, cmdbuf); 835 0 stevel goto signout; 836 0 stevel } 837 0 stevel 838 0 stevel /* Log access to account */ 839 0 stevel if (pwd && (pwd->pw_uid == 0)) { 840 0 stevel syslog(LOG_NOTICE, "Executing %s for user %s (%s@%s)" 841 0 stevel " as ROOT", cmdbuf, 842 0 stevel kremuser, remuser, hostname); 843 0 stevel } 844 0 stevel } 845 0 stevel 846 0 stevel if ((v = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) { 847 0 stevel switch (v) { 848 0 stevel case PAM_NEW_AUTHTOK_REQD: 849 0 stevel error("password expired\n"); 850 0 stevel (void) audit_rshd_fail("Password expired", hostname, 851 0 stevel remuser, locuser, cmdbuf); /* BSM */ 852 0 stevel break; 853 0 stevel case PAM_PERM_DENIED: 854 0 stevel error("account expired\n"); 855 0 stevel (void) audit_rshd_fail("Account expired", hostname, 856 0 stevel remuser, locuser, cmdbuf); /* BSM */ 857 0 stevel break; 858 0 stevel case PAM_AUTHTOK_EXPIRED: 859 0 stevel error("password expired\n"); 860 0 stevel (void) audit_rshd_fail("Password expired", hostname, 861 0 stevel remuser, locuser, cmdbuf); /* BSM */ 862 0 stevel break; 863 0 stevel default: 864 0 stevel error("login incorrect\n"); 865 0 stevel (void) audit_rshd_fail("Permission denied", hostname, 866 0 stevel remuser, locuser, cmdbuf); /* BSM */ 867 0 stevel break; 868 0 stevel } 869 0 stevel (void) pam_end(pamh, PAM_ABORT); 870 0 stevel exit(1); 871 0 stevel } 872 0 stevel 873 0 stevel if (chdir(pwd->pw_dir) < 0) { 874 0 stevel (void) chdir("/"); 875 0 stevel #ifdef notdef 876 0 stevel error("No remote directory.\n"); 877 0 stevel 878 0 stevel exit(1); 879 0 stevel #endif 880 0 stevel } 881 0 stevel 882 0 stevel /* 883 0 stevel * XXX There is no session management currently being done 884 0 stevel */ 885 0 stevel 886 0 stevel (void) write(STDERR_FILENO, "\0", 1); 887 0 stevel if (port || do_encrypt) { 888 0 stevel if ((pipe(pv) < 0)) { 889 0 stevel error("Can't make pipe.\n"); 890 0 stevel (void) pam_end(pamh, PAM_ABORT); 891 0 stevel exit(1); 892 0 stevel } 893 0 stevel if (do_encrypt) { 894 0 stevel if (pipe(pw) < 0) { 895 0 stevel error("Can't make pipe 2.\n"); 896 0 stevel (void) pam_end(pamh, PAM_ABORT); 897 0 stevel exit(1); 898 0 stevel } 899 0 stevel if (pipe(px) < 0) { 900 0 stevel error("Can't make pipe 3.\n"); 901 0 stevel (void) pam_end(pamh, PAM_ABORT); 902 0 stevel exit(1); 903 0 stevel } 904 0 stevel } 905 0 stevel pid = fork(); 906 0 stevel if (pid == (pid_t)-1) { 907 0 stevel error("Fork (to start shell) failed on server. " 908 0 stevel "Please try again later.\n"); 909 0 stevel (void) pam_end(pamh, PAM_ABORT); 910 0 stevel exit(1); 911 0 stevel } 912 0 stevel if (pid) { 913 0 stevel fd_set ready; 914 0 stevel fd_set readfrom; 915 0 stevel 916 0 stevel (void) close(STDIN_FILENO); 917 0 stevel (void) close(STDOUT_FILENO); 918 0 stevel (void) close(STDERR_FILENO); 919 0 stevel (void) close(pv[1]); 920 0 stevel if (do_encrypt) { 921 0 stevel (void) close(pw[1]); 922 0 stevel (void) close(px[0]); 923 0 stevel } else { 924 0 stevel (void) close(f); 925 0 stevel } 926 0 stevel 927 0 stevel (void) FD_ZERO(&readfrom); 928 0 stevel 929 0 stevel FD_SET(pv[0], &readfrom); 930 0 stevel if (do_encrypt) { 931 0 stevel FD_SET(pw[0], &readfrom); 932 0 stevel FD_SET(f, &readfrom); 933 0 stevel } 934 0 stevel if (port) 935 0 stevel FD_SET(s, &readfrom); 936 0 stevel 937 0 stevel /* read f (net), write to px[1] (child stdin) */ 938 0 stevel /* read pw[0] (child stdout), write to f (net) */ 939 0 stevel /* read s (alt. channel), signal child */ 940 0 stevel /* read pv[0] (child stderr), write to s */ 941 0 stevel if (ioctl(pv[0], FIONBIO, (char *)&one) == -1) 942 0 stevel syslog(LOG_INFO, "ioctl FIONBIO: %m"); 943 0 stevel if (do_encrypt && 944 0 stevel ioctl(pw[0], FIONBIO, (char *)&one) == -1) 945 0 stevel syslog(LOG_INFO, "ioctl FIONBIO: %m"); 946 0 stevel do { 947 0 stevel ready = readfrom; 948 0 stevel if (select(FD_SETSIZE, &ready, NULL, 949 0 stevel NULL, NULL) < 0) { 950 0 stevel if (errno == EINTR) { 951 0 stevel continue; 952 0 stevel } else { 953 0 stevel break; 954 0 stevel } 955 0 stevel } 956 0 stevel /* 957 0 stevel * Read from child stderr, write to net 958 0 stevel */ 959 0 stevel if (port && FD_ISSET(pv[0], &ready)) { 960 0 stevel errno = 0; 961 0 stevel cc = read(pv[0], buf, sizeof (buf)); 962 0 stevel if (cc <= 0) { 963 0 stevel (void) shutdown(s, 2); 964 0 stevel FD_CLR(pv[0], &readfrom); 965 0 stevel } else { 966 0 stevel (void) deswrite(s, buf, cc, 1); 967 0 stevel } 968 0 stevel } 969 0 stevel /* 970 0 stevel * Read from alternate channel, signal child 971 0 stevel */ 972 0 stevel if (port && FD_ISSET(s, &ready)) { 973 0 stevel if ((int)desread(s, &sig, 1, 1) <= 0) 974 0 stevel FD_CLR(s, &readfrom); 975 0 stevel else 976 0 stevel (void) killpg(pid, sig); 977 0 stevel } 978 0 stevel /* 979 0 stevel * Read from child stdout, write to net 980 0 stevel */ 981 0 stevel if (do_encrypt && FD_ISSET(pw[0], &ready)) { 982 0 stevel errno = 0; 983 0 stevel cc = read(pw[0], buf, sizeof (buf)); 984 0 stevel if (cc <= 0) { 985 0 stevel (void) shutdown(f, 2); 986 0 stevel FD_CLR(pw[0], &readfrom); 987 0 stevel } else { 988 0 stevel (void) deswrite(f, buf, cc, 0); 989 0 stevel } 990 0 stevel } 991 0 stevel /* 992 0 stevel * Read from the net, write to child stdin 993 0 stevel */ 994 0 stevel if (do_encrypt && FD_ISSET(f, &ready)) { 995 0 stevel errno = 0; 996 0 stevel cc = desread(f, buf, sizeof (buf), 0); 997 0 stevel if (cc <= 0) { 998 0 stevel (void) close(px[1]); 999 0 stevel FD_CLR(f, &readfrom); 1000 0 stevel } else { 1001 0 stevel int wcc; 1002 0 stevel wcc = write(px[1], buf, cc); 1003 0 stevel if (wcc == -1) { 1004 0 stevel /* 1005 0 stevel * pipe closed, 1006 0 stevel * don't read any 1007 0 stevel * more 1008 0 stevel * 1009 0 stevel * might check for 1010 0 stevel * EPIPE 1011 0 stevel */ 1012 0 stevel (void) close(px[1]); 1013 0 stevel FD_CLR(f, &readfrom); 1014 0 stevel } else if (wcc != cc) { 1015 0 stevel /* CSTYLED */ 1016 0 stevel syslog(LOG_INFO, gettext("only wrote %d/%d to child"), 1017 0 stevel wcc, cc); 1018 0 stevel } 1019 0 stevel } 1020 0 stevel } 1021 0 stevel } while ((port && FD_ISSET(s, &readfrom)) || 1022 0 stevel (port && FD_ISSET(pv[0], &readfrom)) || 1023 0 stevel (do_encrypt && FD_ISSET(f, &readfrom)) || 1024 0 stevel (do_encrypt && FD_ISSET(pw[0], &readfrom))); 1025 0 stevel #ifdef DEBUG 1026 0 stevel syslog(LOG_INFO, "Shell process completed."); 1027 0 stevel #endif /* DEBUG */ 1028 0 stevel if (ccache) 1029 0 stevel (void) pam_close_session(pamh, 0); 1030 0 stevel (void) pam_end(pamh, PAM_SUCCESS); 1031 0 stevel 1032 0 stevel exit(0); 1033 0 stevel } /* End of Parent block */ 1034 0 stevel 1035 0 stevel (void) setsid(); /* Should be the same as above. */ 1036 0 stevel (void) close(pv[0]); 1037 0 stevel (void) dup2(pv[1], 2); 1038 0 stevel (void) close(pv[1]); 1039 0 stevel if (port) 1040 0 stevel (void) close(s); 1041 0 stevel if (do_encrypt) { 1042 0 stevel (void) close(f); 1043 0 stevel (void) close(pw[0]); 1044 0 stevel (void) close(px[1]); 1045 0 stevel 1046 0 stevel (void) dup2(px[0], 0); 1047 0 stevel (void) dup2(pw[1], 1); 1048 0 stevel 1049 0 stevel (void) close(px[0]); 1050 0 stevel (void) close(pw[1]); 1051 0 stevel } 1052 0 stevel } 1053 0 stevel 1054 0 stevel if (*pwd->pw_shell == '\0') 1055 0 stevel pwd->pw_shell = "/bin/sh"; 1056 0 stevel if (!do_encrypt) 1057 0 stevel (void) close(f); 1058 0 stevel /* 1059 0 stevel * write audit record before making uid switch 1060 0 stevel */ 1061 0 stevel (void) audit_rshd_success(hostname, remuser, locuser, cmdbuf); /* BSM */ 1062 0 stevel 1063 0 stevel /* set the real (and effective) GID */ 1064 0 stevel if (setgid(pwd->pw_gid) == -1) { 1065 0 stevel error("Invalid gid.\n"); 1066 0 stevel (void) pam_end(pamh, PAM_ABORT); 1067 0 stevel exit(1); 1068 0 stevel } 1069 0 stevel 1070 0 stevel /* 1071 0 stevel * Initialize the supplementary group access list. 1072 0 stevel */ 1073 0 stevel if (strlen(locuser) == 0) { 1074 0 stevel error("No local user.\n"); 1075 0 stevel (void) pam_end(pamh, PAM_ABORT); 1076 0 stevel exit(1); 1077 0 stevel } 1078 0 stevel if (initgroups(locuser, pwd->pw_gid) == -1) { 1079 0 stevel error("Initgroup failed.\n"); 1080 0 stevel (void) pam_end(pamh, PAM_ABORT); 1081 0 stevel exit(1); 1082 0 stevel } 1083 0 stevel 1084 0 stevel if ((v = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { 1085 0 stevel error("Insufficient credentials.\n"); 1086 0 stevel (void) pam_end(pamh, v); 1087 0 stevel exit(1); 1088 0 stevel } 1089 0 stevel 1090 0 stevel /* set the real (and effective) UID */ 1091 0 stevel if (setuid(pwd->pw_uid) == -1) { 1092 0 stevel error("Invalid uid.\n"); 1093 0 stevel (void) pam_end(pamh, PAM_ABORT); 1094 0 stevel exit(1); 1095 0 stevel } 1096 0 stevel 1097 0 stevel /* Change directory only after becoming the appropriate user. */ 1098 0 stevel if (chdir(pwd->pw_dir) < 0) { 1099 0 stevel (void) chdir("/"); 1100 0 stevel if (krb5auth_flag > 0) { 1101 0 stevel syslog(LOG_ERR, "Principal %s (%s@%s) for local user" 1102 0 stevel " %s has no home directory.", 1103 0 stevel kremuser, remuser, hostname, locuser); 1104 0 stevel error("No remote directory.\n"); 1105 0 stevel goto signout; 1106 0 stevel } 1107 0 stevel #ifdef notdef 1108 0 stevel error("No remote directory.\n"); 1109 0 stevel exit(1); 1110 0 stevel #endif 1111 0 stevel } 1112 0 stevel 1113 0 stevel path = (pwd->pw_uid == 0) ? rootpath : userpath; 1114 0 stevel 1115 0 stevel /* 1116 0 stevel * Space for the following environment variables are dynamically 1117 0 stevel * allocated because their lengths are not known before calling 1118 0 stevel * getpwnam(). 1119 0 stevel */ 1120 0 stevel homedir_len = strlen(pwd->pw_dir) + strlen(homestr) + 1; 1121 0 stevel shell_len = strlen(pwd->pw_shell) + strlen(shellstr) + 1; 1122 0 stevel username_len = strlen(pwd->pw_name) + strlen(userstr) + 1; 1123 0 stevel homedir = (char *)malloc(homedir_len); 1124 0 stevel shell = (char *)malloc(shell_len); 1125 0 stevel username = (char *)malloc(username_len); 1126 0 stevel if (homedir == NULL || shell == NULL || username == NULL) { 1127 0 stevel perror("malloc"); 1128 0 stevel exit(1); 1129 0 stevel } 1130 0 stevel (void) snprintf(homedir, homedir_len, "%s%s", homestr, pwd->pw_dir); 1131 0 stevel (void) snprintf(shell, shell_len, "%s%s", shellstr, pwd->pw_shell); 1132 0 stevel (void) snprintf(username, username_len, "%s%s", userstr, pwd->pw_name); 1133 0 stevel 1134 0 stevel /* Pass timezone to executed command. */ 1135 0 stevel if (tzenv = getenv("TZ")) { 1136 0 stevel tz_len = strlen(tzenv) + strlen(tzstr) + 1; 1137 0 stevel tz = malloc(tz_len); 1138 0 stevel if (tz != NULL) 1139 0 stevel (void) snprintf(tz, tz_len, "%s%s", tzstr, tzenv); 1140 0 stevel } 1141 0 stevel 1142 0 stevel add_to_envinit(homedir); 1143 0 stevel add_to_envinit(shell); 1144 0 stevel add_to_envinit(path); 1145 0 stevel add_to_envinit(username); 1146 0 stevel add_to_envinit(tz); 1147 0 stevel 1148 0 stevel if (krb5auth_flag > 0) { 1149 0 stevel int length; 1150 0 stevel char *buffer; 1151 0 stevel 1152 0 stevel /* 1153 0 stevel * If we have KRB5CCNAME set, then copy into the child's 1154 0 stevel * environment. This can't really have a fixed position 1155 0 stevel * because `tz' may or may not be set. 1156 0 stevel */ 1157 0 stevel if (getenv("KRB5CCNAME")) { 1158 0 stevel length = (int)strlen(getenv("KRB5CCNAME")) + 1159 0 stevel (int)strlen("KRB5CCNAME=") + 1; 1160 0 stevel buffer = (char *)malloc(length); 1161 0 stevel 1162 0 stevel if (buffer) { 1163 0 stevel (void) snprintf(buffer, length, "KRB5CCNAME=%s", 1164 0 stevel getenv("KRB5CCNAME")); 1165 0 stevel add_to_envinit(buffer); 1166 0 stevel } 1167 0 stevel } { 1168 0 stevel /* These two are covered by ADDRPAD */ 1169 0 stevel length = strlen(inet_ntoa(localaddr.sin_addr)) + 1 + 1170 0 stevel strlen("KRB5LOCALADDR="); 1171 0 stevel (void) snprintf(local_addr, length, "KRB5LOCALADDR=%s", 1172 0 stevel inet_ntoa(localaddr.sin_addr)); 1173 0 stevel add_to_envinit(local_addr); 1174 0 stevel 1175 0 stevel length = strlen(inet_ntoa(sin->sin_addr)) + 1 + 1176 0 stevel strlen("KRB5REMOTEADDR="); 1177 0 stevel (void) snprintf(remote_addr, length, 1178 0 stevel "KRB5REMOTEADDR=%s", inet_ntoa(sin->sin_addr)); 1179 0 stevel add_to_envinit(remote_addr); 1180 0 stevel } 1181 0 stevel 1182 0 stevel /* 1183 0 stevel * If we do anything else, make sure there is 1184 0 stevel * space in the array. 1185 0 stevel */ 1186 0 stevel for (cnt = 0; cnt < num_env; cnt++) { 1187 0 stevel char *buf; 1188 0 stevel 1189 0 stevel if (getenv(save_env[cnt])) { 1190 0 stevel length = (int)strlen(getenv(save_env[cnt])) + 1191 0 stevel (int)strlen(save_env[cnt]) + 2; 1192 0 stevel 1193 0 stevel buf = (char *)malloc(length); 1194 0 stevel if (buf) { 1195 0 stevel (void) snprintf(buf, length, "%s=%s", 1196 0 stevel save_env[cnt], 1197 0 stevel getenv(save_env[cnt])); 1198 0 stevel add_to_envinit(buf); 1199 0 stevel } 1200 0 stevel } 1201 0 stevel } 1202 0 stevel 1203 0 stevel } 1204 0 stevel 1205 0 stevel /* 1206 0 stevel * add PAM environment variables set by modules 1207 0 stevel * -- only allowed 16 (PAM_ENV_ELIM) 1208 0 stevel * -- check to see if the environment variable is legal 1209 0 stevel */ 1210 0 stevel if ((pam_env = pam_getenvlist(pamh)) != 0) { 1211 0 stevel while (pam_env[idx] != 0) { 1212 0 stevel if (idx < PAM_ENV_ELIM && 1213 0 stevel legalenvvar(pam_env[idx])) { 1214 0 stevel add_to_envinit(pam_env[idx]); 1215 0 stevel } 1216 0 stevel idx++; 1217 0 stevel } 1218 0 stevel } 1219 0 stevel 1220 0 stevel (void) pam_end(pamh, PAM_SUCCESS); 1221 0 stevel 1222 0 stevel /* 1223 0 stevel * Pick up locale environment variables, if any. 1224 0 stevel */ 1225 0 stevel lenvp = renvp; 1226 0 stevel while (*lenvp != NULL) { 1227 0 stevel int index; 1228 0 stevel 1229 0 stevel for (index = 0; localeenv[index] != NULL; index++) 1230 0 stevel /* 1231 0 stevel * locale_envmatch() returns 1 if 1232 0 stevel * *lenvp is localenev[index] and valid. 1233 0 stevel */ 1234 0 stevel if (locale_envmatch(localeenv[index], *lenvp)) { 1235 0 stevel add_to_envinit(*lenvp); 1236 0 stevel break; 1237 0 stevel } 1238 0 stevel 1239 0 stevel lenvp++; 1240 0 stevel } 1241 0 stevel 1242 0 stevel cp = strrchr(pwd->pw_shell, '/'); 1243 0 stevel if (cp != NULL) 1244 0 stevel cp++; 1245 0 stevel else 1246 0 stevel cp = pwd->pw_shell; 1247 0 stevel /* 1248 0 stevel * rdist has been moved to /usr/bin, so /usr/ucb/rdist might not 1249 0 stevel * be present on a system. So if it doesn't exist we fall back 1250 0 stevel * and try for it in /usr/bin. We take care to match the space 1251 0 stevel * after the name because the only purpose of this is to protect 1252 0 stevel * the internal call from old rdist's, not humans who type 1253 0 stevel * "rsh foo /usr/ucb/rdist". 1254 0 stevel */ 1255 0 stevel #define RDIST_PROG_NAME "/usr/ucb/rdist -Server" 1256 0 stevel if (strncmp(cmdbuf, RDIST_PROG_NAME, strlen(RDIST_PROG_NAME)) == 0) { 1257 0 stevel if (stat("/usr/ucb/rdist", &statb) != 0) { 1258 0 stevel (void) strncpy(cmdbuf + 5, "bin", 3); 1259 0 stevel } 1260 0 stevel } 1261 0 stevel 1262 0 stevel #ifdef DEBUG 1263 0 stevel syslog(LOG_NOTICE, "rshd: cmdbuf = %s", cmdbuf); 1264 0 stevel if (do_encrypt) 1265 0 stevel syslog(LOG_NOTICE, "rshd: cmd to be exec'ed = %s", 1266 0 stevel ((char *)cmdbuf + 3)); 1267 0 stevel #endif /* DEBUG */ 1268 0 stevel 1269 0 stevel if (do_encrypt && (strncmp(cmdbuf, "-x ", 3) == 0)) { 1270 0 stevel (void) execle(pwd->pw_shell, cp, "-c", (char *)cmdbuf + 3, 1271 0 stevel NULL, envinit); 1272 0 stevel } else { 1273 0 stevel (void) execle(pwd->pw_shell, cp, "-c", cmdbuf, NULL, 1274 0 stevel envinit); 1275 0 stevel } 1276 0 stevel 1277 0 stevel perror(pwd->pw_shell); 1278 0 stevel exit(1); 1279 0 stevel 1280 0 stevel signout: 1281 0 stevel if (ccache) 1282 0 stevel (void) pam_close_session(pamh, 0); 1283 0 stevel ccache = NULL; 1284 0 stevel (void) pam_end(pamh, PAM_ABORT); 1285 0 stevel exit(1); 1286 0 stevel } 1287 0 stevel 1288 0 stevel static void 1289 0 stevel getstr(fd, buf, cnt, err) 1290 0 stevel int fd; 1291 0 stevel char *buf; 1292 0 stevel int cnt; 1293 0 stevel char *err; 1294 0 stevel { 1295 0 stevel char c; 1296 0 stevel 1297 0 stevel do { 1298 0 stevel if (read(fd, &c, 1) != 1) 1299 0 stevel exit(1); 1300 0 stevel if (cnt-- == 0) { 1301 0 stevel error("%s too long\n", err); 1302 0 stevel exit(1); 1303 0 stevel } 1304 0 stevel *buf++ = c; 1305 0 stevel } while (c != 0); 1306 0 stevel } 1307 0 stevel 1308 0 stevel /*PRINTFLIKE1*/ 1309 0 stevel static void 1310 0 stevel error(char *fmt, ...) 1311 0 stevel { 1312 0 stevel va_list ap; 1313 0 stevel char buf[RSHD_BUFSIZ]; 1314 0 stevel 1315 0 stevel buf[0] = 1; 1316 0 stevel va_start(ap, fmt); 1317 0 stevel (void) vsnprintf(&buf[1], sizeof (buf) - 1, fmt, ap); 1318 0 stevel va_end(ap); 1319 0 stevel (void) write(STDERR_FILENO, buf, strlen(buf)); 1320 0 stevel } 1321 0 stevel 1322 0 stevel static char *illegal[] = { 1323 0 stevel "SHELL=", 1324 0 stevel "HOME=", 1325 0 stevel "LOGNAME=", 1326 0 stevel #ifndef NO_MAIL 1327 0 stevel "MAIL=", 1328 0 stevel #endif 1329 0 stevel "CDPATH=", 1330 0 stevel "IFS=", 1331 0 stevel "PATH=", 1332 0 stevel "USER=", 1333 0 stevel "TZ=", 1334 0 stevel 0 1335 0 stevel }; 1336 0 stevel 1337 0 stevel /* 1338 0 stevel * legalenvvar - can PAM modules insert this environmental variable? 1339 0 stevel */ 1340 0 stevel 1341 0 stevel static int 1342 0 stevel legalenvvar(char *s) 1343 0 stevel { 1344 0 stevel register char **p; 1345 0 stevel 1346 0 stevel for (p = illegal; *p; p++) 1347 0 stevel if (strncmp(s, *p, strlen(*p)) == 0) 1348 0 stevel return (0); 1349 0 stevel 1350 0 stevel if (s[0] == 'L' && s[1] == 'D' && s[2] == '_') 1351 0 stevel return (0); 1352 0 stevel 1353 0 stevel return (1); 1354 0 stevel } 1355 0 stevel 1356 0 stevel /* 1357 0 stevel * Add a string to the environment of the new process. 1358 0 stevel */ 1359 0 stevel 1360 0 stevel static void 1361 0 stevel add_to_envinit(char *string) 1362 0 stevel { 1363 0 stevel /* 1364 0 stevel * Reserve space for 2 * 8 = 16 environment entries initially which 1365 0 stevel * should be enough to avoid reallocation of "envinit" in most cases. 1366 0 stevel */ 1367 0 stevel static int size = 8; 1368 0 stevel static int index = 0; 1369 0 stevel 1370 0 stevel if (string == NULL) 1371 0 stevel return; 1372 0 stevel 1373 0 stevel if ((envinit == NULL) || (index == size)) { 1374 0 stevel size *= 2; 1375 0 stevel envinit = realloc(envinit, (size + 1) * sizeof (char *)); 1376 0 stevel if (envinit == NULL) { 1377 0 stevel perror("malloc"); 1378 0 stevel exit(1); 1379 0 stevel } 1380 0 stevel } 1381 0 stevel 1382 0 stevel envinit[index++] = string; 1383 0 stevel envinit[index] = NULL; 1384 0 stevel } 1385 0 stevel 1386 0 stevel /* 1387 0 stevel * Check if lenv and penv matches or not. 1388 0 stevel */ 1389 0 stevel static int 1390 0 stevel locale_envmatch(char *lenv, char *penv) 1391 0 stevel { 1392 0 stevel while ((*lenv == *penv) && (*lenv != '\0') && (*penv != '=')) { 1393 0 stevel lenv++; 1394 0 stevel penv++; 1395 0 stevel } 1396 0 stevel 1397 0 stevel /* 1398 0 stevel * '/' is eliminated for security reason. 1399 0 stevel */ 1400 0 stevel return ((*lenv == '\0' && *penv == '=' && *(penv + 1) != '/')); 1401 0 stevel } 1402 0 stevel 1403 0 stevel #ifndef KRB_SENDAUTH_VLEN 1404 0 stevel #define KRB_SENDAUTH_VLEN 8 /* length for version strings */ 1405 0 stevel #endif 1406 0 stevel 1407 0 stevel /* MUST be KRB_SENDAUTH_VLEN chars */ 1408 0 stevel #define KRB_SENDAUTH_VERS "AUTHV0.1" 1409 0 stevel #define SIZEOF_INADDR sizeof (struct in_addr) 1410 0 stevel 1411 0 stevel static krb5_error_code 1412 0 stevel recvauth(int netf, int *valid_checksum) 1413 0 stevel { 1414 0 stevel krb5_auth_context auth_context = NULL; 1415 0 stevel krb5_error_code status; 1416 0 stevel struct sockaddr_in laddr; 1417 0 stevel int len; 1418 0 stevel krb5_data inbuf; 1419 0 stevel krb5_authenticator *authenticator; 1420 0 stevel krb5_ticket *ticket; 1421 0 stevel krb5_rcache rcache; 1422 0 stevel krb5_data version; 1423 0 stevel krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */ 1424 0 stevel krb5_data desinbuf; 1425 0 stevel krb5_data desoutbuf; 1426 0 stevel char des_inbuf[2 * RSHD_BUFSIZ]; 1427 0 stevel /* needs to be > largest read size */ 1428 0 stevel char des_outbuf[2 * RSHD_BUFSIZ + 4]; 1429 0 stevel /* needs to be > largest write size */ 1430 0 stevel 1431 0 stevel *valid_checksum = 0; 1432 0 stevel len = sizeof (laddr); 1433 0 stevel 1434 0 stevel if (getsockname(netf, (struct sockaddr *)&laddr, &len)) { 1435 0 stevel exit(1); 1436 0 stevel } 1437 0 stevel 1438 0 stevel if (status = krb5_auth_con_init(bsd_context, &auth_context)) 1439 0 stevel return (status); 1440 0 stevel 1441 0 stevel if (status = krb5_auth_con_genaddrs(bsd_context, auth_context, netf, 1442 0 stevel KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)) 1443 0 stevel return (status); 1444 0 stevel 1445 0 stevel status = krb5_auth_con_getrcache(bsd_context, auth_context, &rcache); 1446 0 stevel if (status) 1447 0 stevel return (status); 1448 0 stevel 1449 0 stevel if (!rcache) { 1450 0 stevel krb5_principal server; 1451 0 stevel 1452 0 stevel status = krb5_sname_to_principal(bsd_context, 0, 0, 1453 0 stevel KRB5_NT_SRV_HST, &server); 1454 0 stevel if (status) 1455 0 stevel return (status); 1456 0 stevel 1457 0 stevel status = krb5_get_server_rcache(bsd_context, 1458 0 stevel krb5_princ_component(bsd_context, server, 0), 1459 0 stevel &rcache); 1460 0 stevel krb5_free_principal(bsd_context, server); 1461 0 stevel if (status) 1462 0 stevel return (status); 1463 0 stevel 1464 0 stevel status = krb5_auth_con_setrcache(bsd_context, auth_context, 1465 0 stevel rcache); 1466 0 stevel if (status) 1467 0 stevel return (status); 1468 0 stevel } 1469 0 stevel 1470 0 stevel status = krb5_recvauth_version(bsd_context, &auth_context, &netf, 1471 0 stevel NULL, /* Specify daemon principal */ 1472 0 stevel 0, /* no flags */ 1473 0 stevel keytab, /* normally NULL to use v5srvtab */ 1474 0 stevel &ticket, /* return ticket */ 1475 0 stevel &version); /* application version string */ 1476 0 stevel 1477 0 stevel 1478 0 stevel if (status) { 1479 0 stevel getstr(netf, locuser, sizeof (locuser), "locuser"); 1480 0 stevel getstr(netf, cmdbuf, sizeof (cmdbuf), "command"); 1481 0 stevel getstr(netf, remuser, sizeof (locuser), "remuser"); 1482 0 stevel return (status); 1483 0 stevel } 1484 0 stevel getstr(netf, locuser, sizeof (locuser), "locuser"); 1485 0 stevel getstr(netf, cmdbuf, sizeof (cmdbuf), "command"); 1486 0 stevel 1487 0 stevel /* Must be V5 */ 1488 0 stevel 1489 0 stevel kcmd_protocol = KCMD_UNKNOWN_PROTOCOL; 1490 0 stevel if (version.length != 9 || version.data == NULL) { 1491 0 stevel syslog(LOG_ERR, "bad application version length"); 1492 0 stevel error(gettext("bad application version length\n")); 1493 0 stevel exit(1); 1494 0 stevel } 1495 0 stevel if (strncmp(version.data, "KCMDV0.1", 9) == 0) { 1496 0 stevel kcmd_protocol = KCMD_OLD_PROTOCOL; 1497 0 stevel } else if (strncmp(version.data, "KCMDV0.2", 9) == 0) { 1498 0 stevel kcmd_protocol = KCMD_NEW_PROTOCOL; 1499 0 stevel } else { 1500 0 stevel syslog(LOG_ERR, "Unrecognized KCMD protocol (%s)", 1501 0 stevel (char *)version.data); 1502 0 stevel error(gettext("Unrecognized KCMD protocol (%s)"), 1503 0 stevel (char *)version.data); 1504 0 stevel exit(1); 1505 0 stevel } 1506 0 stevel getstr(netf, remuser, sizeof (locuser), "remuser"); 1507 0 stevel 1508 0 stevel if ((status = krb5_unparse_name(bsd_context, ticket->enc_part2->client, 1509 0 stevel &kremuser))) 1510 0 stevel return (status); 1511 0 stevel 1512 0 stevel if ((status = krb5_copy_principal(bsd_context, 1513 0 stevel ticket->enc_part2->client, &client))) 1514 0 stevel return (status); 1515 0 stevel 1516 0 stevel 1517 0 stevel if (checksum_required && (kcmd_protocol == KCMD_OLD_PROTOCOL)) { 1518 0 stevel if ((status = krb5_auth_con_getauthenticator(bsd_context, 1519 0 stevel auth_context, &authenticator))) 1520 0 stevel return (status); 1521 0 stevel 1522 0 stevel if (authenticator->checksum && checksum_required) { 1523 0 stevel struct sockaddr_in adr; 1524 0 stevel int adr_length = sizeof (adr); 1525 0 stevel int chksumsize = strlen(cmdbuf) + strlen(locuser) + 32; 1526 0 stevel krb5_data input; 1527 0 stevel krb5_keyblock key; 1528 0 stevel 1529 0 stevel char *chksumbuf = (char *)malloc(chksumsize); 1530 0 stevel 1531 0 stevel if (chksumbuf == 0) 1532 0 stevel goto error_cleanup; 1533 0 stevel if (getsockname(netf, (struct sockaddr *)&adr, 1534 0 stevel &adr_length) != 0) 1535 0 stevel goto error_cleanup; 1536 0 stevel 1537 0 stevel (void) snprintf(chksumbuf, chksumsize, "%u:", 1538 0 stevel ntohs(adr.sin_port)); 1539 0 stevel if (strlcat(chksumbuf, cmdbuf, 1540 0 stevel chksumsize) >= chksumsize) { 1541 0 stevel syslog(LOG_ERR, "cmd buffer too long."); 1542 0 stevel free(chksumbuf); 1543 0 stevel return (-1); 1544 0 stevel } 1545 0 stevel if (strlcat(chksumbuf, locuser, 1546 0 stevel chksumsize) >= chksumsize) { 1547 0 stevel syslog(LOG_ERR, "locuser too long."); 1548 0 stevel free(chksumbuf); 1549 0 stevel return (-1); 1550 0 stevel } 1551 0 stevel 1552 0 stevel input.data = chksumbuf; 1553 0 stevel input.length = strlen(chksumbuf); 1554 0 stevel key.magic = ticket->enc_part2->session->magic; 1555 0 stevel key.enctype = ticket->enc_part2->session->enctype; 1556 0 stevel key.contents = ticket->enc_part2->session->contents; 1557 0 stevel key.length = ticket->enc_part2->session->length; 1558 0 stevel 1559 0 stevel status = krb5_c_verify_checksum(bsd_context, 1560 0 stevel &key, 0, &input, authenticator->checksum, 1561 0 stevel (unsigned int *)valid_checksum); 1562 0 stevel 1563 0 stevel if (status == 0 && *valid_checksum == 0) 1564 0 stevel status = KRB5KRB_AP_ERR_BAD_INTEGRITY; 1565 0 stevel error_cleanup: 1566 0 stevel if (chksumbuf) 1567 0 stevel krb5_xfree(chksumbuf); 1568 0 stevel if (status) { 1569 0 stevel krb5_free_authenticator(bsd_context, 1570 0 stevel authenticator); 1571 0 stevel return (status); 1572 0 stevel } 1573 0 stevel } 1574 0 stevel krb5_free_authenticator(bsd_context, authenticator); 1575 0 stevel } 1576 0 stevel 1577 0 stevel 1578 0 stevel if ((strncmp(cmdbuf, "-x ", 3) == 0)) { 1579 0 stevel if (krb5_privacy_allowed()) { 1580 0 stevel do_encrypt = 1; 1581 0 stevel } else { 1582 0 stevel syslog(LOG_ERR, "rshd: Encryption not supported"); 1583 0 stevel error("rshd: Encryption not supported. \n"); 1584 0 stevel exit(2); 1585 0 stevel } 1586 0 stevel 1587 0 stevel status = krb5_auth_con_getremotesubkey(bsd_context, 1588 0 stevel auth_context, 1589 0 stevel &sessionkey); 1590 0 stevel if (status) { 1591 0 stevel syslog(LOG_ERR, "Error getting KRB5 session subkey"); 1592 0 stevel error(gettext("Error getting KRB5 session subkey")); 1593 0 stevel exit(1); 1594 0 stevel } 1595 0 stevel /* 1596 0 stevel * The "new" protocol requires that a subkey be sent. 1597 0 stevel */ 1598 0 stevel if (sessionkey == NULL && kcmd_protocol == KCMD_NEW_PROTOCOL) { 1599 0 stevel syslog(LOG_ERR, "No KRB5 session subkey sent"); 1600 0 stevel error(gettext("No KRB5 session subkey sent")); 1601 0 stevel exit(1); 1602 0 stevel } 1603 0 stevel /* 1604 0 stevel * The "old" protocol does not permit an authenticator subkey. 1605 0 stevel * The key is taken from the ticket instead (see below). 1606 0 stevel */ 1607 0 stevel if (sessionkey != NULL && kcmd_protocol == KCMD_OLD_PROTOCOL) { 1608 0 stevel syslog(LOG_ERR, "KRB5 session subkey not permitted " 1609 0 stevel "with old KCMD protocol"); 1610 0 stevel error(gettext("KRB5 session subkey not permitted " 1611 0 stevel "with old KCMD protocol")); 1612 0 stevel exit(1); 1613 0 stevel } 1614 0 stevel /* 1615 0 stevel * If no key at this point, use the session key from 1616 0 stevel * the ticket. 1617 0 stevel */ 1618 0 stevel if (sessionkey == NULL) { 1619 0 stevel /* 1620 0 stevel * Save the session key so we can configure the crypto 1621 0 stevel * module later. 1622 0 stevel */ 1623 0 stevel status = krb5_copy_keyblock(bsd_context, 1624 0 stevel ticket->enc_part2->session, 1625 0 stevel &sessionkey); 1626 0 stevel if (status) { 1627 0 stevel syslog(LOG_ERR, "krb5_copy_keyblock failed"); 1628 0 stevel error(gettext("krb5_copy_keyblock failed")); 1629 0 stevel exit(1); 1630 0 stevel } 1631 0 stevel } 1632 0 stevel /* 1633 0 stevel * If session key still cannot be found, we must 1634 0 stevel * exit because encryption is required here 1635 0 stevel * when encr_flag (-x) is set. 1636 0 stevel */ 1637 0 stevel if (sessionkey == NULL) { 1638 0 stevel syslog(LOG_ERR, "Could not find an encryption key"); 1639 0 stevel error(gettext("Could not find an encryption key")); 1640 0 stevel exit(1); 1641 0 stevel } 1642 0 stevel 1643 0 stevel /* 1644 0 stevel * Initialize parameters/buffers for desread & deswrite here. 1645 0 stevel */ 1646 0 stevel desinbuf.data = des_inbuf; 1647 0 stevel desoutbuf.data = des_outbuf; 1648 0 stevel desinbuf.length = sizeof (des_inbuf); 1649 0 stevel desoutbuf.length = sizeof (des_outbuf); 1650 0 stevel 1651 0 stevel eblock.crypto_entry = sessionkey->enctype; 1652 0 stevel eblock.key = (krb5_keyblock *)sessionkey; 1653 0 stevel 1654 0 stevel init_encrypt(do_encrypt, bsd_context, kcmd_protocol, 1655 0 stevel &desinbuf, &desoutbuf, SERVER, &eblock); 1656 0 stevel } 1657 0 stevel 1658 0 stevel ticket->enc_part2->session = 0; 1659 0 stevel 1660 0 stevel if ((status = krb5_read_message(bsd_context, (krb5_pointer) & netf, 1661 0 stevel &inbuf))) { 1662 0 stevel error(gettext("Error reading message: %s\n"), 1663 0 stevel error_message(status)); 1664 0 stevel exit(1); 1665 0 stevel } 1666 0 stevel 1667 0 stevel if (inbuf.length) { 1668 6536 gtb krb5_creds **creds = NULL; 1669 6536 gtb 1670 0 stevel /* Forwarding being done, read creds */ 1671 6536 gtb if ((status = krb5_rd_cred(bsd_context, 1672 6536 gtb auth_context, &inbuf, &creds, 1673 6536 gtb NULL))) { 1674 0 stevel error("Can't get forwarded credentials: %s\n", 1675 0 stevel error_message(status)); 1676 0 stevel exit(1); 1677 0 stevel } 1678 0 stevel 1679 6536 gtb /* Store the forwarded creds in the ccache */ 1680 6536 gtb if ((status = store_forw_creds(bsd_context, 1681 6536 gtb creds, ticket, locuser, 1682 6536 gtb &ccache))) { 1683 6536 gtb error("Can't store forwarded credentials: %s\n", 1684 6536 gtb error_message(status)); 1685 6536 gtb exit(1); 1686 6536 gtb } 1687 6536 gtb krb5_free_creds(bsd_context, *creds); 1688 0 stevel } 1689 6536 gtb 1690 0 stevel krb5_free_ticket(bsd_context, ticket); 1691 0 stevel return (0); 1692 0 stevel } 1693 0 stevel 1694 0 stevel static void 1695 0 stevel usage(void) 1696 0 stevel { 1697 0 stevel (void) fprintf(stderr, gettext("%s: rshd [-k5eciU] " 1698 0 stevel "[-P path] [-M realm] [-s tos] " 1699 0 stevel #ifdef DEBUG 1700 0 stevel "[-D port] " 1701 0 stevel #endif /* DEBUG */ 1702 0 stevel "[-S keytab]"), gettext("usage")); 1703 0 stevel 1704 0 stevel syslog(LOG_ERR, "%s: rshd [-k5eciU] [-P path] [-M realm] [-s tos] " 1705 0 stevel #ifdef DEBUG 1706 0 stevel "[-D port] " 1707 0 stevel #endif /* DEBUG */ 1708 0 stevel "[-S keytab]", gettext("usage")); 1709 0 stevel } 1710