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 2005 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 #include <sys/types.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/filio.h> 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 45*7c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate #include <unistd.h> 48*7c478bd9Sstevel@tonic-gate #include <string.h> 49*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 50*7c478bd9Sstevel@tonic-gate #include <stdio.h> 51*7c478bd9Sstevel@tonic-gate #include <stdarg.h> 52*7c478bd9Sstevel@tonic-gate #include <errno.h> 53*7c478bd9Sstevel@tonic-gate #include <pwd.h> 54*7c478bd9Sstevel@tonic-gate #include <grp.h> 55*7c478bd9Sstevel@tonic-gate #include <signal.h> 56*7c478bd9Sstevel@tonic-gate #include <netdb.h> 57*7c478bd9Sstevel@tonic-gate #include <syslog.h> 58*7c478bd9Sstevel@tonic-gate #include <security/pam_appl.h> 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate #ifdef SYSV 61*7c478bd9Sstevel@tonic-gate #include <shadow.h> 62*7c478bd9Sstevel@tonic-gate #endif /* SYSV */ 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate #ifndef NCARGS 65*7c478bd9Sstevel@tonic-gate #define NCARGS 5120 66*7c478bd9Sstevel@tonic-gate #endif /* NCARGS */ 67*7c478bd9Sstevel@tonic-gate 68*7c478bd9Sstevel@tonic-gate #ifdef SYSV 69*7c478bd9Sstevel@tonic-gate #define rindex strrchr 70*7c478bd9Sstevel@tonic-gate #define killpg(a, b) kill(-(a), (b)) 71*7c478bd9Sstevel@tonic-gate #else 72*7c478bd9Sstevel@tonic-gate char *sprintf(); 73*7c478bd9Sstevel@tonic-gate #endif /* SYSV */ 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate #define MAXFD(A, B) ((A) > (B) ? (A) : (B)) 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate static void error(char *fmt, ...); 78*7c478bd9Sstevel@tonic-gate static void doit(int f, struct sockaddr_storage *fromp); 79*7c478bd9Sstevel@tonic-gate static void getstr(char *buf, int cnt, char *err); 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate static int legalenvvar(char *s); 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate /* Function decls. for functions not in any header file. (Grrrr.) */ 84*7c478bd9Sstevel@tonic-gate extern int audit_rexecd_setup(void); 85*7c478bd9Sstevel@tonic-gate extern int audit_rexecd_success(char *, char *, char *); 86*7c478bd9Sstevel@tonic-gate extern int audit_rexecd_fail(char *, char *, char *, char *); 87*7c478bd9Sstevel@tonic-gate extern int audit_settid(int); /* set termnal ID */ 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate /* PAM conversation function */ 90*7c478bd9Sstevel@tonic-gate static int rexec_conv(int, struct pam_message **, 91*7c478bd9Sstevel@tonic-gate struct pam_response **, void *); 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate static pam_handle_t *pamh; /* authentication handle */ 94*7c478bd9Sstevel@tonic-gate static struct pam_conv conv = { 95*7c478bd9Sstevel@tonic-gate rexec_conv, 96*7c478bd9Sstevel@tonic-gate NULL 97*7c478bd9Sstevel@tonic-gate }; 98*7c478bd9Sstevel@tonic-gate 99*7c478bd9Sstevel@tonic-gate /* 100*7c478bd9Sstevel@tonic-gate * remote execute server: 101*7c478bd9Sstevel@tonic-gate * username\0 102*7c478bd9Sstevel@tonic-gate * password\0 103*7c478bd9Sstevel@tonic-gate * command\0 104*7c478bd9Sstevel@tonic-gate * data 105*7c478bd9Sstevel@tonic-gate * 106*7c478bd9Sstevel@tonic-gate * in.rexecd has been modified to run as the user invoking it. Hence there is no 107*7c478bd9Sstevel@tonic-gate * need to limit any privileges. 108*7c478bd9Sstevel@tonic-gate */ 109*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 110*7c478bd9Sstevel@tonic-gate void 111*7c478bd9Sstevel@tonic-gate main(int argc, char **argv) 112*7c478bd9Sstevel@tonic-gate { 113*7c478bd9Sstevel@tonic-gate struct sockaddr_storage from; 114*7c478bd9Sstevel@tonic-gate socklen_t fromlen; 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate openlog("rexec", LOG_PID | LOG_ODELAY, LOG_DAEMON); 117*7c478bd9Sstevel@tonic-gate (void) audit_rexecd_setup(); /* BSM */ 118*7c478bd9Sstevel@tonic-gate fromlen = (socklen_t)sizeof (from); 119*7c478bd9Sstevel@tonic-gate if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 120*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", argv[0]); 121*7c478bd9Sstevel@tonic-gate perror("getpeername"); 122*7c478bd9Sstevel@tonic-gate exit(1); 123*7c478bd9Sstevel@tonic-gate } 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate if (audit_settid(0) != 0) { 126*7c478bd9Sstevel@tonic-gate perror("settid"); 127*7c478bd9Sstevel@tonic-gate exit(1); 128*7c478bd9Sstevel@tonic-gate } 129*7c478bd9Sstevel@tonic-gate 130*7c478bd9Sstevel@tonic-gate doit(0, &from); 131*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 132*7c478bd9Sstevel@tonic-gate } 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate static char username[20] = "USER="; 135*7c478bd9Sstevel@tonic-gate static char homedir[64] = "HOME="; 136*7c478bd9Sstevel@tonic-gate static char shell[64] = "SHELL="; 137*7c478bd9Sstevel@tonic-gate 138*7c478bd9Sstevel@tonic-gate static char *envinit[] = 139*7c478bd9Sstevel@tonic-gate #ifdef SYSV 140*7c478bd9Sstevel@tonic-gate {homedir, shell, (char *)0, username, 141*7c478bd9Sstevel@tonic-gate (char *)0, (char *)0, (char *)0, (char *)0, 142*7c478bd9Sstevel@tonic-gate (char *)0, (char *)0, (char *)0, (char *)0, 143*7c478bd9Sstevel@tonic-gate (char *)0, (char *)0, (char *)0, (char *)0, 144*7c478bd9Sstevel@tonic-gate (char *)0, (char *)0, (char *)0, (char *)0, 145*7c478bd9Sstevel@tonic-gate (char *)0}; 146*7c478bd9Sstevel@tonic-gate #define ENVINIT_PATH 2 /* position of PATH in envinit[] */ 147*7c478bd9Sstevel@tonic-gate #define PAM_ENV_ELIM 16 /* max PAM environment variables */ 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate /* 150*7c478bd9Sstevel@tonic-gate * See PSARC opinion 1992/025 151*7c478bd9Sstevel@tonic-gate */ 152*7c478bd9Sstevel@tonic-gate static char userpath[] = "PATH=/usr/bin:"; 153*7c478bd9Sstevel@tonic-gate static char rootpath[] = "PATH=/usr/sbin:/usr/bin"; 154*7c478bd9Sstevel@tonic-gate #else 155*7c478bd9Sstevel@tonic-gate {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0}; 156*7c478bd9Sstevel@tonic-gate #endif /* SYSV */ 157*7c478bd9Sstevel@tonic-gate 158*7c478bd9Sstevel@tonic-gate static struct sockaddr_storage asin; 159*7c478bd9Sstevel@tonic-gate static char pass[16]; 160*7c478bd9Sstevel@tonic-gate 161*7c478bd9Sstevel@tonic-gate static void 162*7c478bd9Sstevel@tonic-gate doit(int f, struct sockaddr_storage *fromp) 163*7c478bd9Sstevel@tonic-gate { 164*7c478bd9Sstevel@tonic-gate char cmdbuf[NCARGS+1], *cp; 165*7c478bd9Sstevel@tonic-gate char user[16]; 166*7c478bd9Sstevel@tonic-gate char hostname [MAXHOSTNAMELEN + 1]; 167*7c478bd9Sstevel@tonic-gate struct passwd *pwd; 168*7c478bd9Sstevel@tonic-gate int s; 169*7c478bd9Sstevel@tonic-gate ushort_t port; 170*7c478bd9Sstevel@tonic-gate pid_t pid; 171*7c478bd9Sstevel@tonic-gate int pv[2], cc; 172*7c478bd9Sstevel@tonic-gate fd_set readfrom, ready; 173*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ], sig; 174*7c478bd9Sstevel@tonic-gate int one = 1; 175*7c478bd9Sstevel@tonic-gate int idx = 0, end_env = 0; 176*7c478bd9Sstevel@tonic-gate char **pam_env; 177*7c478bd9Sstevel@tonic-gate int status = PAM_AUTH_ERR; 178*7c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 179*7c478bd9Sstevel@tonic-gate struct in_addr v4dst; 180*7c478bd9Sstevel@tonic-gate socklen_t fromplen; 181*7c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 182*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate (void) signal(SIGINT, SIG_DFL); 185*7c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_DFL); 186*7c478bd9Sstevel@tonic-gate (void) signal(SIGTERM, SIG_DFL); 187*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 188*7c478bd9Sstevel@tonic-gate { 189*7c478bd9Sstevel@tonic-gate int t = open("/dev/tty", 2); 190*7c478bd9Sstevel@tonic-gate if (t >= 0) { 191*7c478bd9Sstevel@tonic-gate #ifdef SYSV 192*7c478bd9Sstevel@tonic-gate (void) setsid(); 193*7c478bd9Sstevel@tonic-gate #else 194*7c478bd9Sstevel@tonic-gate (void) ioctl(t, TIOCNOTTY, (char *)0); 195*7c478bd9Sstevel@tonic-gate #endif /* SYSV */ 196*7c478bd9Sstevel@tonic-gate (void) close(t); 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate } 199*7c478bd9Sstevel@tonic-gate #endif 200*7c478bd9Sstevel@tonic-gate if (fromp->ss_family == AF_INET) { 201*7c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)fromp; 202*7c478bd9Sstevel@tonic-gate fromplen = sizeof (struct sockaddr_in); 203*7c478bd9Sstevel@tonic-gate asin.ss_family = AF_INET; /* used for bind */ 204*7c478bd9Sstevel@tonic-gate } else if (fromp->ss_family == AF_INET6) { 205*7c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)fromp; 206*7c478bd9Sstevel@tonic-gate fromplen = sizeof (struct sockaddr_in6); 207*7c478bd9Sstevel@tonic-gate asin.ss_family = AF_INET6; /* used for bind */ 208*7c478bd9Sstevel@tonic-gate } else { 209*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "unknown address family %d\n", 210*7c478bd9Sstevel@tonic-gate fromp->ss_family); 211*7c478bd9Sstevel@tonic-gate exit(1); 212*7c478bd9Sstevel@tonic-gate } 213*7c478bd9Sstevel@tonic-gate /* 214*7c478bd9Sstevel@tonic-gate * store common info. for audit record 215*7c478bd9Sstevel@tonic-gate */ 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate if (getnameinfo((const struct sockaddr *) fromp, fromplen, hostname, 218*7c478bd9Sstevel@tonic-gate sizeof (hostname), NULL, 0, 0) != 0) { 219*7c478bd9Sstevel@tonic-gate if (fromp->ss_family == AF_INET6) { 220*7c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 221*7c478bd9Sstevel@tonic-gate struct in_addr ipv4_addr; 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, 224*7c478bd9Sstevel@tonic-gate &ipv4_addr); 225*7c478bd9Sstevel@tonic-gate inet_ntop(AF_INET, &ipv4_addr, abuf, 226*7c478bd9Sstevel@tonic-gate sizeof (abuf)); 227*7c478bd9Sstevel@tonic-gate } else { 228*7c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, &sin6->sin6_addr, 229*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate } else if (fromp->ss_family == AF_INET) { 232*7c478bd9Sstevel@tonic-gate inet_ntop(AF_INET, &sin->sin_addr, 233*7c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate (void) strncpy(hostname, abuf, sizeof (hostname)); 236*7c478bd9Sstevel@tonic-gate } 237*7c478bd9Sstevel@tonic-gate (void) dup2(f, 0); 238*7c478bd9Sstevel@tonic-gate (void) dup2(f, 1); 239*7c478bd9Sstevel@tonic-gate (void) dup2(f, 2); 240*7c478bd9Sstevel@tonic-gate (void) alarm(60); 241*7c478bd9Sstevel@tonic-gate port = 0; 242*7c478bd9Sstevel@tonic-gate for (;;) { 243*7c478bd9Sstevel@tonic-gate char c; 244*7c478bd9Sstevel@tonic-gate if (read(f, &c, 1) != 1) 245*7c478bd9Sstevel@tonic-gate exit(1); 246*7c478bd9Sstevel@tonic-gate if (c == 0) 247*7c478bd9Sstevel@tonic-gate break; 248*7c478bd9Sstevel@tonic-gate port = port * 10 + c - '0'; 249*7c478bd9Sstevel@tonic-gate } 250*7c478bd9Sstevel@tonic-gate (void) alarm(0); 251*7c478bd9Sstevel@tonic-gate if (port != 0) { 252*7c478bd9Sstevel@tonic-gate s = socket(fromp->ss_family, SOCK_STREAM, 0); 253*7c478bd9Sstevel@tonic-gate if (s < 0) 254*7c478bd9Sstevel@tonic-gate exit(1); 255*7c478bd9Sstevel@tonic-gate if (bind(s, (struct sockaddr *)&asin, fromplen) < 0) 256*7c478bd9Sstevel@tonic-gate exit(1); 257*7c478bd9Sstevel@tonic-gate (void) alarm(60); 258*7c478bd9Sstevel@tonic-gate if (fromp->ss_family == AF_INET) { 259*7c478bd9Sstevel@tonic-gate sin->sin_port = htons((ushort_t)port); 260*7c478bd9Sstevel@tonic-gate } else if (fromp->ss_family == AF_INET6) { 261*7c478bd9Sstevel@tonic-gate sin6->sin6_port = htons((ushort_t)port); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate if (connect(s, (struct sockaddr *)fromp, fromplen) < 0) 264*7c478bd9Sstevel@tonic-gate exit(1); 265*7c478bd9Sstevel@tonic-gate (void) alarm(0); 266*7c478bd9Sstevel@tonic-gate } 267*7c478bd9Sstevel@tonic-gate getstr(user, sizeof (user), "username"); 268*7c478bd9Sstevel@tonic-gate getstr(pass, sizeof (pass), "password"); 269*7c478bd9Sstevel@tonic-gate getstr(cmdbuf, sizeof (cmdbuf), "command"); 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate setpwent(); 272*7c478bd9Sstevel@tonic-gate pwd = getpwnam(user); 273*7c478bd9Sstevel@tonic-gate if (pwd == NULL) { 274*7c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Login incorrect", hostname, user, 275*7c478bd9Sstevel@tonic-gate cmdbuf); /* BSM */ 276*7c478bd9Sstevel@tonic-gate error("Login incorrect.\n"); 277*7c478bd9Sstevel@tonic-gate exit(1); 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate endpwent(); 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate if (pam_start("rexec", user, &conv, &pamh) != PAM_SUCCESS) { 282*7c478bd9Sstevel@tonic-gate exit(1); 283*7c478bd9Sstevel@tonic-gate } 284*7c478bd9Sstevel@tonic-gate if (pam_set_item(pamh, PAM_RHOST, hostname) != PAM_SUCCESS) { 285*7c478bd9Sstevel@tonic-gate exit(1); 286*7c478bd9Sstevel@tonic-gate } 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate if ((status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) { 289*7c478bd9Sstevel@tonic-gate switch (status) { 290*7c478bd9Sstevel@tonic-gate case PAM_USER_UNKNOWN: 291*7c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Login incorrect", hostname, 292*7c478bd9Sstevel@tonic-gate user, cmdbuf); /* BSM */ 293*7c478bd9Sstevel@tonic-gate error("Login incorrect.\n"); 294*7c478bd9Sstevel@tonic-gate break; 295*7c478bd9Sstevel@tonic-gate default: 296*7c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Password incorrect", hostname, 297*7c478bd9Sstevel@tonic-gate user, cmdbuf); /* BSM */ 298*7c478bd9Sstevel@tonic-gate error("Password incorrect.\n"); 299*7c478bd9Sstevel@tonic-gate } 300*7c478bd9Sstevel@tonic-gate pam_end(pamh, status); 301*7c478bd9Sstevel@tonic-gate exit(1); 302*7c478bd9Sstevel@tonic-gate } 303*7c478bd9Sstevel@tonic-gate if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) { 304*7c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Account or Password Expired", 305*7c478bd9Sstevel@tonic-gate hostname, user, cmdbuf); 306*7c478bd9Sstevel@tonic-gate switch (status) { 307*7c478bd9Sstevel@tonic-gate case PAM_NEW_AUTHTOK_REQD: 308*7c478bd9Sstevel@tonic-gate error("Password Expired.\n"); 309*7c478bd9Sstevel@tonic-gate break; 310*7c478bd9Sstevel@tonic-gate case PAM_PERM_DENIED: 311*7c478bd9Sstevel@tonic-gate error("Account Expired.\n"); 312*7c478bd9Sstevel@tonic-gate break; 313*7c478bd9Sstevel@tonic-gate case PAM_AUTHTOK_EXPIRED: 314*7c478bd9Sstevel@tonic-gate error("Password Expired.\n"); 315*7c478bd9Sstevel@tonic-gate break; 316*7c478bd9Sstevel@tonic-gate default: 317*7c478bd9Sstevel@tonic-gate error("Login incorrect.\n"); 318*7c478bd9Sstevel@tonic-gate break; 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate pam_end(pamh, status); 321*7c478bd9Sstevel@tonic-gate exit(1); 322*7c478bd9Sstevel@tonic-gate } 323*7c478bd9Sstevel@tonic-gate 324*7c478bd9Sstevel@tonic-gate (void) write(2, "\0", 1); 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate if (setgid((gid_t)pwd->pw_gid) < 0) { 327*7c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Can't setgid", hostname, 328*7c478bd9Sstevel@tonic-gate user, cmdbuf); /* BSM */ 329*7c478bd9Sstevel@tonic-gate error("setgid"); 330*7c478bd9Sstevel@tonic-gate pam_end(pamh, PAM_ABORT); 331*7c478bd9Sstevel@tonic-gate exit(1); 332*7c478bd9Sstevel@tonic-gate } 333*7c478bd9Sstevel@tonic-gate (void) initgroups(pwd->pw_name, pwd->pw_gid); 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate if ((status = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { 336*7c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Unable to establish credentials", 337*7c478bd9Sstevel@tonic-gate hostname, user, cmdbuf); /* BSM */ 338*7c478bd9Sstevel@tonic-gate error("Unable to establish credentials.\n"); 339*7c478bd9Sstevel@tonic-gate pam_end(pamh, PAM_SUCCESS); 340*7c478bd9Sstevel@tonic-gate } 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate (void) audit_rexecd_success(hostname, user, cmdbuf); /* BSM */ 343*7c478bd9Sstevel@tonic-gate 344*7c478bd9Sstevel@tonic-gate if (setuid((uid_t)pwd->pw_uid) < 0) { 345*7c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Can't setuid", hostname, 346*7c478bd9Sstevel@tonic-gate user, cmdbuf); /* BSM */ 347*7c478bd9Sstevel@tonic-gate error("setuid"); 348*7c478bd9Sstevel@tonic-gate pam_end(pamh, PAM_ABORT); 349*7c478bd9Sstevel@tonic-gate exit(1); 350*7c478bd9Sstevel@tonic-gate } 351*7c478bd9Sstevel@tonic-gate 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate if (port) { 354*7c478bd9Sstevel@tonic-gate (void) pipe(pv); 355*7c478bd9Sstevel@tonic-gate pid = fork(); 356*7c478bd9Sstevel@tonic-gate if (pid == (pid_t)-1) { 357*7c478bd9Sstevel@tonic-gate error("Try again.\n"); 358*7c478bd9Sstevel@tonic-gate pam_end(pamh, PAM_ABORT); 359*7c478bd9Sstevel@tonic-gate exit(1); 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate if (pid) { 362*7c478bd9Sstevel@tonic-gate /* 363*7c478bd9Sstevel@tonic-gate * since the daemon is running as the user no need 364*7c478bd9Sstevel@tonic-gate * to prune privileges. 365*7c478bd9Sstevel@tonic-gate */ 366*7c478bd9Sstevel@tonic-gate (void) close(0); (void) close(1); (void) close(2); 367*7c478bd9Sstevel@tonic-gate (void) close(f); (void) close(pv[1]); 368*7c478bd9Sstevel@tonic-gate FD_ZERO(&readfrom); 369*7c478bd9Sstevel@tonic-gate FD_SET(s, &readfrom); 370*7c478bd9Sstevel@tonic-gate FD_SET(pv[0], &readfrom); 371*7c478bd9Sstevel@tonic-gate (void) ioctl(pv[0], FIONBIO, (char *)&one); 372*7c478bd9Sstevel@tonic-gate /* should set s nbio! */ 373*7c478bd9Sstevel@tonic-gate do { 374*7c478bd9Sstevel@tonic-gate ready = readfrom; 375*7c478bd9Sstevel@tonic-gate if (select(MAXFD(s, pv[0])+1, &ready, NULL, 376*7c478bd9Sstevel@tonic-gate NULL, NULL) < 0) { 377*7c478bd9Sstevel@tonic-gate perror("select:"); 378*7c478bd9Sstevel@tonic-gate exit(1); 379*7c478bd9Sstevel@tonic-gate } 380*7c478bd9Sstevel@tonic-gate if (FD_ISSET(s, &ready)) { 381*7c478bd9Sstevel@tonic-gate if (read(s, &sig, 1) <= 0) 382*7c478bd9Sstevel@tonic-gate FD_CLR(s, &readfrom); 383*7c478bd9Sstevel@tonic-gate else 384*7c478bd9Sstevel@tonic-gate (void) killpg(pid, sig); 385*7c478bd9Sstevel@tonic-gate } 386*7c478bd9Sstevel@tonic-gate if (FD_ISSET(pv[0], &ready)) { 387*7c478bd9Sstevel@tonic-gate cc = read(pv[0], buf, sizeof (buf)); 388*7c478bd9Sstevel@tonic-gate if (cc <= 0) { 389*7c478bd9Sstevel@tonic-gate (void) shutdown(s, 1+1); 390*7c478bd9Sstevel@tonic-gate FD_CLR(pv[0], &readfrom); 391*7c478bd9Sstevel@tonic-gate } else 392*7c478bd9Sstevel@tonic-gate (void) write(s, buf, cc); 393*7c478bd9Sstevel@tonic-gate } 394*7c478bd9Sstevel@tonic-gate } while (FD_ISSET(s, &readfrom) || 395*7c478bd9Sstevel@tonic-gate FD_ISSET(pv[0], &readfrom)); 396*7c478bd9Sstevel@tonic-gate exit(0); 397*7c478bd9Sstevel@tonic-gate } 398*7c478bd9Sstevel@tonic-gate /* setpgrp(0, getpid()); */ 399*7c478bd9Sstevel@tonic-gate (void) setsid(); /* Should be the same as above. */ 400*7c478bd9Sstevel@tonic-gate (void) close(s); (void)close(pv[0]); 401*7c478bd9Sstevel@tonic-gate (void) dup2(pv[1], 2); 402*7c478bd9Sstevel@tonic-gate } 403*7c478bd9Sstevel@tonic-gate 404*7c478bd9Sstevel@tonic-gate if (*pwd->pw_shell == '\0') 405*7c478bd9Sstevel@tonic-gate pwd->pw_shell = "/bin/sh"; 406*7c478bd9Sstevel@tonic-gate if (f > 2) 407*7c478bd9Sstevel@tonic-gate (void) close(f); 408*7c478bd9Sstevel@tonic-gate /* Change directory only after becoming the appropriate user. */ 409*7c478bd9Sstevel@tonic-gate if (chdir(pwd->pw_dir) < 0) { 410*7c478bd9Sstevel@tonic-gate error("No remote directory.\n"); 411*7c478bd9Sstevel@tonic-gate pam_end(pamh, PAM_ABORT); 412*7c478bd9Sstevel@tonic-gate exit(1); 413*7c478bd9Sstevel@tonic-gate } 414*7c478bd9Sstevel@tonic-gate #ifdef SYSV 415*7c478bd9Sstevel@tonic-gate if (pwd->pw_uid) 416*7c478bd9Sstevel@tonic-gate envinit[ENVINIT_PATH] = userpath; 417*7c478bd9Sstevel@tonic-gate else 418*7c478bd9Sstevel@tonic-gate envinit[ENVINIT_PATH] = rootpath; 419*7c478bd9Sstevel@tonic-gate #endif /* SYSV */ 420*7c478bd9Sstevel@tonic-gate (void) strncat(homedir, pwd->pw_dir, sizeof (homedir) - 6); 421*7c478bd9Sstevel@tonic-gate (void) strncat(shell, pwd->pw_shell, sizeof (shell) - 7); 422*7c478bd9Sstevel@tonic-gate (void) strncat(username, pwd->pw_name, sizeof (username) - 6); 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate /* 425*7c478bd9Sstevel@tonic-gate * add PAM environment variables set by modules 426*7c478bd9Sstevel@tonic-gate * -- only allowed 16 (PAM_ENV_ELIM) 427*7c478bd9Sstevel@tonic-gate * -- check to see if the environment variable is legal 428*7c478bd9Sstevel@tonic-gate */ 429*7c478bd9Sstevel@tonic-gate for (end_env = 0; envinit[end_env] != 0; end_env++) 430*7c478bd9Sstevel@tonic-gate ; 431*7c478bd9Sstevel@tonic-gate if ((pam_env = pam_getenvlist(pamh)) != 0) { 432*7c478bd9Sstevel@tonic-gate while (pam_env[idx] != 0) { 433*7c478bd9Sstevel@tonic-gate if (idx < PAM_ENV_ELIM && 434*7c478bd9Sstevel@tonic-gate legalenvvar(pam_env[idx])) { 435*7c478bd9Sstevel@tonic-gate envinit[end_env + idx] = pam_env[idx]; 436*7c478bd9Sstevel@tonic-gate } 437*7c478bd9Sstevel@tonic-gate idx++; 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate } 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate pam_end(pamh, PAM_SUCCESS); 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate cp = rindex(pwd->pw_shell, '/'); 444*7c478bd9Sstevel@tonic-gate if (cp) 445*7c478bd9Sstevel@tonic-gate cp++; 446*7c478bd9Sstevel@tonic-gate else 447*7c478bd9Sstevel@tonic-gate cp = pwd->pw_shell; 448*7c478bd9Sstevel@tonic-gate (void) execle(pwd->pw_shell, cp, "-c", cmdbuf, (char *)0, envinit); 449*7c478bd9Sstevel@tonic-gate perror(pwd->pw_shell); 450*7c478bd9Sstevel@tonic-gate exit(1); 451*7c478bd9Sstevel@tonic-gate } 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate static void 454*7c478bd9Sstevel@tonic-gate getstr(char *buf, int cnt, char *err) 455*7c478bd9Sstevel@tonic-gate { 456*7c478bd9Sstevel@tonic-gate char c; 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate do { 459*7c478bd9Sstevel@tonic-gate if (read(0, &c, 1) != 1) 460*7c478bd9Sstevel@tonic-gate exit(1); 461*7c478bd9Sstevel@tonic-gate *buf++ = c; 462*7c478bd9Sstevel@tonic-gate if (--cnt == 0) { 463*7c478bd9Sstevel@tonic-gate error("%s too long\n", err); 464*7c478bd9Sstevel@tonic-gate exit(1); 465*7c478bd9Sstevel@tonic-gate } 466*7c478bd9Sstevel@tonic-gate } while (c != 0); 467*7c478bd9Sstevel@tonic-gate } 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate static void 470*7c478bd9Sstevel@tonic-gate error(char *fmt, ...) 471*7c478bd9Sstevel@tonic-gate { 472*7c478bd9Sstevel@tonic-gate va_list ap; 473*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 474*7c478bd9Sstevel@tonic-gate 475*7c478bd9Sstevel@tonic-gate buf[0] = 1; 476*7c478bd9Sstevel@tonic-gate va_start(ap, fmt); 477*7c478bd9Sstevel@tonic-gate (void) vsprintf(buf+1, fmt, ap); 478*7c478bd9Sstevel@tonic-gate va_end(ap); 479*7c478bd9Sstevel@tonic-gate (void) write(2, buf, strlen(buf)); 480*7c478bd9Sstevel@tonic-gate } 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate static char *illegal[] = { 483*7c478bd9Sstevel@tonic-gate "SHELL=", 484*7c478bd9Sstevel@tonic-gate "HOME=", 485*7c478bd9Sstevel@tonic-gate "LOGNAME=", 486*7c478bd9Sstevel@tonic-gate #ifndef NO_MAIL 487*7c478bd9Sstevel@tonic-gate "MAIL=", 488*7c478bd9Sstevel@tonic-gate #endif 489*7c478bd9Sstevel@tonic-gate "CDPATH=", 490*7c478bd9Sstevel@tonic-gate "IFS=", 491*7c478bd9Sstevel@tonic-gate "PATH=", 492*7c478bd9Sstevel@tonic-gate "USER=", 493*7c478bd9Sstevel@tonic-gate 0 494*7c478bd9Sstevel@tonic-gate }; 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate /* 497*7c478bd9Sstevel@tonic-gate * legalenvvar - can PAM insert this environmental variable? 498*7c478bd9Sstevel@tonic-gate */ 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate static int 501*7c478bd9Sstevel@tonic-gate legalenvvar(char *s) 502*7c478bd9Sstevel@tonic-gate { 503*7c478bd9Sstevel@tonic-gate register char **p; 504*7c478bd9Sstevel@tonic-gate 505*7c478bd9Sstevel@tonic-gate for (p = illegal; *p; p++) 506*7c478bd9Sstevel@tonic-gate if (strncmp(s, *p, strlen(*p)) == 0) 507*7c478bd9Sstevel@tonic-gate return (0); 508*7c478bd9Sstevel@tonic-gate 509*7c478bd9Sstevel@tonic-gate if (s[0] == 'L' && s[1] == 'D' && s[2] == '_') 510*7c478bd9Sstevel@tonic-gate return (0); 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate return (1); 513*7c478bd9Sstevel@tonic-gate } 514*7c478bd9Sstevel@tonic-gate 515*7c478bd9Sstevel@tonic-gate /* 516*7c478bd9Sstevel@tonic-gate * rexec_conv - This is the conv (conversation) function called from 517*7c478bd9Sstevel@tonic-gate * a PAM authentication module to print error messages 518*7c478bd9Sstevel@tonic-gate * or garner information from the user. 519*7c478bd9Sstevel@tonic-gate */ 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate /* ARGSUSED3 */ 522*7c478bd9Sstevel@tonic-gate static int 523*7c478bd9Sstevel@tonic-gate rexec_conv(int num_msg, struct pam_message **msg, 524*7c478bd9Sstevel@tonic-gate struct pam_response **response, void *appdata_ptr) 525*7c478bd9Sstevel@tonic-gate { 526*7c478bd9Sstevel@tonic-gate struct pam_message *m; 527*7c478bd9Sstevel@tonic-gate struct pam_response *r; 528*7c478bd9Sstevel@tonic-gate int i; 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate if (num_msg <= 0) 531*7c478bd9Sstevel@tonic-gate return (PAM_CONV_ERR); 532*7c478bd9Sstevel@tonic-gate 533*7c478bd9Sstevel@tonic-gate *response = calloc(num_msg, sizeof (struct pam_response)); 534*7c478bd9Sstevel@tonic-gate if (*response == NULL) 535*7c478bd9Sstevel@tonic-gate return (PAM_BUF_ERR); 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate m = *msg; 538*7c478bd9Sstevel@tonic-gate r = *response; 539*7c478bd9Sstevel@tonic-gate 540*7c478bd9Sstevel@tonic-gate if (m->msg_style == PAM_PROMPT_ECHO_OFF) { 541*7c478bd9Sstevel@tonic-gate if (pass[0] != '\0') { 542*7c478bd9Sstevel@tonic-gate r->resp = strdup(pass); 543*7c478bd9Sstevel@tonic-gate if (r->resp == NULL) { 544*7c478bd9Sstevel@tonic-gate /* free responses */ 545*7c478bd9Sstevel@tonic-gate r = *response; 546*7c478bd9Sstevel@tonic-gate for (i = 0; i < num_msg; i++, r++) { 547*7c478bd9Sstevel@tonic-gate if (r->resp) 548*7c478bd9Sstevel@tonic-gate free(r->resp); 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate free(*response); 551*7c478bd9Sstevel@tonic-gate *response = NULL; 552*7c478bd9Sstevel@tonic-gate return (PAM_BUF_ERR); 553*7c478bd9Sstevel@tonic-gate } 554*7c478bd9Sstevel@tonic-gate } 555*7c478bd9Sstevel@tonic-gate } 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate return (PAM_SUCCESS); 558*7c478bd9Sstevel@tonic-gate } 559