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