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