17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*df83bc5eSpaulson * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983-1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 327c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate #include <sys/types.h> 387c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 397c478bd9Sstevel@tonic-gate #include <sys/param.h> 407c478bd9Sstevel@tonic-gate #include <sys/socket.h> 417c478bd9Sstevel@tonic-gate #include <sys/time.h> 427c478bd9Sstevel@tonic-gate #include <sys/filio.h> 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #include <netinet/in.h> 457c478bd9Sstevel@tonic-gate #include <arpa/inet.h> 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #include <unistd.h> 487c478bd9Sstevel@tonic-gate #include <string.h> 497c478bd9Sstevel@tonic-gate #include <stdlib.h> 507c478bd9Sstevel@tonic-gate #include <stdio.h> 517c478bd9Sstevel@tonic-gate #include <stdarg.h> 527c478bd9Sstevel@tonic-gate #include <errno.h> 537c478bd9Sstevel@tonic-gate #include <pwd.h> 547c478bd9Sstevel@tonic-gate #include <grp.h> 557c478bd9Sstevel@tonic-gate #include <signal.h> 567c478bd9Sstevel@tonic-gate #include <netdb.h> 577c478bd9Sstevel@tonic-gate #include <syslog.h> 58*df83bc5eSpaulson #include <nss_dbdefs.h> 597c478bd9Sstevel@tonic-gate #include <security/pam_appl.h> 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate #ifdef SYSV 627c478bd9Sstevel@tonic-gate #include <shadow.h> 637c478bd9Sstevel@tonic-gate #endif /* SYSV */ 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate #ifndef NCARGS 667c478bd9Sstevel@tonic-gate #define NCARGS 5120 677c478bd9Sstevel@tonic-gate #endif /* NCARGS */ 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #ifdef SYSV 707c478bd9Sstevel@tonic-gate #define rindex strrchr 717c478bd9Sstevel@tonic-gate #define killpg(a, b) kill(-(a), (b)) 727c478bd9Sstevel@tonic-gate #else 737c478bd9Sstevel@tonic-gate char *sprintf(); 747c478bd9Sstevel@tonic-gate #endif /* SYSV */ 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate #define MAXFD(A, B) ((A) > (B) ? (A) : (B)) 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate static void error(char *fmt, ...); 797c478bd9Sstevel@tonic-gate static void doit(int f, struct sockaddr_storage *fromp); 807c478bd9Sstevel@tonic-gate static void getstr(char *buf, int cnt, char *err); 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate static int legalenvvar(char *s); 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate /* Function decls. for functions not in any header file. (Grrrr.) */ 857c478bd9Sstevel@tonic-gate extern int audit_rexecd_setup(void); 867c478bd9Sstevel@tonic-gate extern int audit_rexecd_success(char *, char *, char *); 877c478bd9Sstevel@tonic-gate extern int audit_rexecd_fail(char *, char *, char *, char *); 887c478bd9Sstevel@tonic-gate extern int audit_settid(int); /* set termnal ID */ 897c478bd9Sstevel@tonic-gate 907c478bd9Sstevel@tonic-gate /* PAM conversation function */ 917c478bd9Sstevel@tonic-gate static int rexec_conv(int, struct pam_message **, 927c478bd9Sstevel@tonic-gate struct pam_response **, void *); 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate static pam_handle_t *pamh; /* authentication handle */ 957c478bd9Sstevel@tonic-gate static struct pam_conv conv = { 967c478bd9Sstevel@tonic-gate rexec_conv, 977c478bd9Sstevel@tonic-gate NULL 987c478bd9Sstevel@tonic-gate }; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* 1017c478bd9Sstevel@tonic-gate * remote execute server: 1027c478bd9Sstevel@tonic-gate * username\0 1037c478bd9Sstevel@tonic-gate * password\0 1047c478bd9Sstevel@tonic-gate * command\0 1057c478bd9Sstevel@tonic-gate * data 1067c478bd9Sstevel@tonic-gate * 1077c478bd9Sstevel@tonic-gate * in.rexecd has been modified to run as the user invoking it. Hence there is no 1087c478bd9Sstevel@tonic-gate * need to limit any privileges. 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 111740638c8Sbw int 1127c478bd9Sstevel@tonic-gate main(int argc, char **argv) 1137c478bd9Sstevel@tonic-gate { 1147c478bd9Sstevel@tonic-gate struct sockaddr_storage from; 1157c478bd9Sstevel@tonic-gate socklen_t fromlen; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate openlog("rexec", LOG_PID | LOG_ODELAY, LOG_DAEMON); 1187c478bd9Sstevel@tonic-gate (void) audit_rexecd_setup(); /* BSM */ 1197c478bd9Sstevel@tonic-gate fromlen = (socklen_t)sizeof (from); 1207c478bd9Sstevel@tonic-gate if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) { 1217c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", argv[0]); 1227c478bd9Sstevel@tonic-gate perror("getpeername"); 1237c478bd9Sstevel@tonic-gate exit(1); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate 1267c478bd9Sstevel@tonic-gate if (audit_settid(0) != 0) { 1277c478bd9Sstevel@tonic-gate perror("settid"); 1287c478bd9Sstevel@tonic-gate exit(1); 1297c478bd9Sstevel@tonic-gate } 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate doit(0, &from); 132740638c8Sbw return (0); 1337c478bd9Sstevel@tonic-gate } 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate static char username[20] = "USER="; 1367c478bd9Sstevel@tonic-gate static char homedir[64] = "HOME="; 1377c478bd9Sstevel@tonic-gate static char shell[64] = "SHELL="; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate static char *envinit[] = 1407c478bd9Sstevel@tonic-gate #ifdef SYSV 1417c478bd9Sstevel@tonic-gate {homedir, shell, (char *)0, username, 1427c478bd9Sstevel@tonic-gate (char *)0, (char *)0, (char *)0, (char *)0, 1437c478bd9Sstevel@tonic-gate (char *)0, (char *)0, (char *)0, (char *)0, 1447c478bd9Sstevel@tonic-gate (char *)0, (char *)0, (char *)0, (char *)0, 1457c478bd9Sstevel@tonic-gate (char *)0, (char *)0, (char *)0, (char *)0, 1467c478bd9Sstevel@tonic-gate (char *)0}; 1477c478bd9Sstevel@tonic-gate #define ENVINIT_PATH 2 /* position of PATH in envinit[] */ 1487c478bd9Sstevel@tonic-gate #define PAM_ENV_ELIM 16 /* max PAM environment variables */ 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* 1517c478bd9Sstevel@tonic-gate * See PSARC opinion 1992/025 1527c478bd9Sstevel@tonic-gate */ 1537c478bd9Sstevel@tonic-gate static char userpath[] = "PATH=/usr/bin:"; 1547c478bd9Sstevel@tonic-gate static char rootpath[] = "PATH=/usr/sbin:/usr/bin"; 1557c478bd9Sstevel@tonic-gate #else 1567c478bd9Sstevel@tonic-gate {homedir, shell, "PATH=:/usr/ucb:/bin:/usr/bin", username, 0}; 1577c478bd9Sstevel@tonic-gate #endif /* SYSV */ 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate static struct sockaddr_storage asin; 1607c478bd9Sstevel@tonic-gate static char pass[16]; 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate static void 1637c478bd9Sstevel@tonic-gate doit(int f, struct sockaddr_storage *fromp) 1647c478bd9Sstevel@tonic-gate { 1657c478bd9Sstevel@tonic-gate char cmdbuf[NCARGS+1], *cp; 1667c478bd9Sstevel@tonic-gate char user[16]; 1677c478bd9Sstevel@tonic-gate char hostname [MAXHOSTNAMELEN + 1]; 168*df83bc5eSpaulson struct passwd *pwd, pw_data; 169*df83bc5eSpaulson char pwdbuf[NSS_BUFLEN_PASSWD]; 1707c478bd9Sstevel@tonic-gate int s; 1717c478bd9Sstevel@tonic-gate ushort_t port; 1727c478bd9Sstevel@tonic-gate pid_t pid; 1737c478bd9Sstevel@tonic-gate int pv[2], cc; 1747c478bd9Sstevel@tonic-gate fd_set readfrom, ready; 1757c478bd9Sstevel@tonic-gate char buf[BUFSIZ], sig; 1767c478bd9Sstevel@tonic-gate int one = 1; 1777c478bd9Sstevel@tonic-gate int idx = 0, end_env = 0; 1787c478bd9Sstevel@tonic-gate char **pam_env; 1797c478bd9Sstevel@tonic-gate int status = PAM_AUTH_ERR; 1807c478bd9Sstevel@tonic-gate char abuf[INET6_ADDRSTRLEN]; 1817c478bd9Sstevel@tonic-gate struct in_addr v4dst; 1827c478bd9Sstevel@tonic-gate socklen_t fromplen; 1837c478bd9Sstevel@tonic-gate struct sockaddr_in *sin; 1847c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin6; 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate (void) signal(SIGINT, SIG_DFL); 1877c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_DFL); 1887c478bd9Sstevel@tonic-gate (void) signal(SIGTERM, SIG_DFL); 1897c478bd9Sstevel@tonic-gate #ifdef DEBUG 1907c478bd9Sstevel@tonic-gate { 1917c478bd9Sstevel@tonic-gate int t = open("/dev/tty", 2); 1927c478bd9Sstevel@tonic-gate if (t >= 0) { 1937c478bd9Sstevel@tonic-gate #ifdef SYSV 1947c478bd9Sstevel@tonic-gate (void) setsid(); 1957c478bd9Sstevel@tonic-gate #else 1967c478bd9Sstevel@tonic-gate (void) ioctl(t, TIOCNOTTY, (char *)0); 1977c478bd9Sstevel@tonic-gate #endif /* SYSV */ 1987c478bd9Sstevel@tonic-gate (void) close(t); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate #endif 2027c478bd9Sstevel@tonic-gate if (fromp->ss_family == AF_INET) { 2037c478bd9Sstevel@tonic-gate sin = (struct sockaddr_in *)fromp; 2047c478bd9Sstevel@tonic-gate fromplen = sizeof (struct sockaddr_in); 2057c478bd9Sstevel@tonic-gate asin.ss_family = AF_INET; /* used for bind */ 2067c478bd9Sstevel@tonic-gate } else if (fromp->ss_family == AF_INET6) { 2077c478bd9Sstevel@tonic-gate sin6 = (struct sockaddr_in6 *)fromp; 2087c478bd9Sstevel@tonic-gate fromplen = sizeof (struct sockaddr_in6); 2097c478bd9Sstevel@tonic-gate asin.ss_family = AF_INET6; /* used for bind */ 2107c478bd9Sstevel@tonic-gate } else { 2117c478bd9Sstevel@tonic-gate syslog(LOG_ERR, "unknown address family %d\n", 2127c478bd9Sstevel@tonic-gate fromp->ss_family); 2137c478bd9Sstevel@tonic-gate exit(1); 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * store common info. for audit record 2177c478bd9Sstevel@tonic-gate */ 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate if (getnameinfo((const struct sockaddr *) fromp, fromplen, hostname, 2207c478bd9Sstevel@tonic-gate sizeof (hostname), NULL, 0, 0) != 0) { 2217c478bd9Sstevel@tonic-gate if (fromp->ss_family == AF_INET6) { 2227c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 2237c478bd9Sstevel@tonic-gate struct in_addr ipv4_addr; 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate IN6_V4MAPPED_TO_INADDR(&sin6->sin6_addr, 2267c478bd9Sstevel@tonic-gate &ipv4_addr); 2277c478bd9Sstevel@tonic-gate inet_ntop(AF_INET, &ipv4_addr, abuf, 2287c478bd9Sstevel@tonic-gate sizeof (abuf)); 2297c478bd9Sstevel@tonic-gate } else { 2307c478bd9Sstevel@tonic-gate inet_ntop(AF_INET6, &sin6->sin6_addr, 2317c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate } else if (fromp->ss_family == AF_INET) { 2347c478bd9Sstevel@tonic-gate inet_ntop(AF_INET, &sin->sin_addr, 2357c478bd9Sstevel@tonic-gate abuf, sizeof (abuf)); 2367c478bd9Sstevel@tonic-gate } 2377c478bd9Sstevel@tonic-gate (void) strncpy(hostname, abuf, sizeof (hostname)); 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate (void) dup2(f, 0); 2407c478bd9Sstevel@tonic-gate (void) dup2(f, 1); 2417c478bd9Sstevel@tonic-gate (void) dup2(f, 2); 2427c478bd9Sstevel@tonic-gate (void) alarm(60); 2437c478bd9Sstevel@tonic-gate port = 0; 2447c478bd9Sstevel@tonic-gate for (;;) { 2457c478bd9Sstevel@tonic-gate char c; 2467c478bd9Sstevel@tonic-gate if (read(f, &c, 1) != 1) 2477c478bd9Sstevel@tonic-gate exit(1); 2487c478bd9Sstevel@tonic-gate if (c == 0) 2497c478bd9Sstevel@tonic-gate break; 2507c478bd9Sstevel@tonic-gate port = port * 10 + c - '0'; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate (void) alarm(0); 2537c478bd9Sstevel@tonic-gate if (port != 0) { 2547c478bd9Sstevel@tonic-gate s = socket(fromp->ss_family, SOCK_STREAM, 0); 2557c478bd9Sstevel@tonic-gate if (s < 0) 2567c478bd9Sstevel@tonic-gate exit(1); 2577c478bd9Sstevel@tonic-gate if (bind(s, (struct sockaddr *)&asin, fromplen) < 0) 2587c478bd9Sstevel@tonic-gate exit(1); 2597c478bd9Sstevel@tonic-gate (void) alarm(60); 2607c478bd9Sstevel@tonic-gate if (fromp->ss_family == AF_INET) { 2617c478bd9Sstevel@tonic-gate sin->sin_port = htons((ushort_t)port); 2627c478bd9Sstevel@tonic-gate } else if (fromp->ss_family == AF_INET6) { 2637c478bd9Sstevel@tonic-gate sin6->sin6_port = htons((ushort_t)port); 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate if (connect(s, (struct sockaddr *)fromp, fromplen) < 0) 2667c478bd9Sstevel@tonic-gate exit(1); 2677c478bd9Sstevel@tonic-gate (void) alarm(0); 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate getstr(user, sizeof (user), "username"); 2707c478bd9Sstevel@tonic-gate getstr(pass, sizeof (pass), "password"); 2717c478bd9Sstevel@tonic-gate getstr(cmdbuf, sizeof (cmdbuf), "command"); 2727c478bd9Sstevel@tonic-gate 273*df83bc5eSpaulson pwd = getpwnam_r(user, &pw_data, pwdbuf, sizeof (pwdbuf)); 2747c478bd9Sstevel@tonic-gate if (pwd == NULL) { 2757c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Login incorrect", hostname, user, 2767c478bd9Sstevel@tonic-gate cmdbuf); /* BSM */ 2777c478bd9Sstevel@tonic-gate error("Login incorrect.\n"); 2787c478bd9Sstevel@tonic-gate exit(1); 2797c478bd9Sstevel@tonic-gate } 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate if (pam_start("rexec", user, &conv, &pamh) != PAM_SUCCESS) { 2827c478bd9Sstevel@tonic-gate exit(1); 2837c478bd9Sstevel@tonic-gate } 2847c478bd9Sstevel@tonic-gate if (pam_set_item(pamh, PAM_RHOST, hostname) != PAM_SUCCESS) { 2857c478bd9Sstevel@tonic-gate exit(1); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate if ((status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) { 2897c478bd9Sstevel@tonic-gate switch (status) { 2907c478bd9Sstevel@tonic-gate case PAM_USER_UNKNOWN: 2917c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Login incorrect", hostname, 2927c478bd9Sstevel@tonic-gate user, cmdbuf); /* BSM */ 2937c478bd9Sstevel@tonic-gate error("Login incorrect.\n"); 2947c478bd9Sstevel@tonic-gate break; 2957c478bd9Sstevel@tonic-gate default: 2967c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Password incorrect", hostname, 2977c478bd9Sstevel@tonic-gate user, cmdbuf); /* BSM */ 2987c478bd9Sstevel@tonic-gate error("Password incorrect.\n"); 2997c478bd9Sstevel@tonic-gate } 3007c478bd9Sstevel@tonic-gate pam_end(pamh, status); 3017c478bd9Sstevel@tonic-gate exit(1); 3027c478bd9Sstevel@tonic-gate } 3037c478bd9Sstevel@tonic-gate if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) { 3047c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Account or Password Expired", 3057c478bd9Sstevel@tonic-gate hostname, user, cmdbuf); 3067c478bd9Sstevel@tonic-gate switch (status) { 3077c478bd9Sstevel@tonic-gate case PAM_NEW_AUTHTOK_REQD: 3087c478bd9Sstevel@tonic-gate error("Password Expired.\n"); 3097c478bd9Sstevel@tonic-gate break; 3107c478bd9Sstevel@tonic-gate case PAM_PERM_DENIED: 3117c478bd9Sstevel@tonic-gate error("Account Expired.\n"); 3127c478bd9Sstevel@tonic-gate break; 3137c478bd9Sstevel@tonic-gate case PAM_AUTHTOK_EXPIRED: 3147c478bd9Sstevel@tonic-gate error("Password Expired.\n"); 3157c478bd9Sstevel@tonic-gate break; 3167c478bd9Sstevel@tonic-gate default: 3177c478bd9Sstevel@tonic-gate error("Login incorrect.\n"); 3187c478bd9Sstevel@tonic-gate break; 3197c478bd9Sstevel@tonic-gate } 3207c478bd9Sstevel@tonic-gate pam_end(pamh, status); 3217c478bd9Sstevel@tonic-gate exit(1); 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate (void) write(2, "\0", 1); 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate if (setgid((gid_t)pwd->pw_gid) < 0) { 3277c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Can't setgid", hostname, 3287c478bd9Sstevel@tonic-gate user, cmdbuf); /* BSM */ 3297c478bd9Sstevel@tonic-gate error("setgid"); 3307c478bd9Sstevel@tonic-gate pam_end(pamh, PAM_ABORT); 3317c478bd9Sstevel@tonic-gate exit(1); 3327c478bd9Sstevel@tonic-gate } 3337c478bd9Sstevel@tonic-gate (void) initgroups(pwd->pw_name, pwd->pw_gid); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate if ((status = pam_setcred(pamh, PAM_ESTABLISH_CRED)) != PAM_SUCCESS) { 3367c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Unable to establish credentials", 3377c478bd9Sstevel@tonic-gate hostname, user, cmdbuf); /* BSM */ 3387c478bd9Sstevel@tonic-gate error("Unable to establish credentials.\n"); 3397c478bd9Sstevel@tonic-gate pam_end(pamh, PAM_SUCCESS); 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate (void) audit_rexecd_success(hostname, user, cmdbuf); /* BSM */ 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate if (setuid((uid_t)pwd->pw_uid) < 0) { 3457c478bd9Sstevel@tonic-gate (void) audit_rexecd_fail("Can't setuid", hostname, 3467c478bd9Sstevel@tonic-gate user, cmdbuf); /* BSM */ 3477c478bd9Sstevel@tonic-gate error("setuid"); 3487c478bd9Sstevel@tonic-gate pam_end(pamh, PAM_ABORT); 3497c478bd9Sstevel@tonic-gate exit(1); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate if (port) { 3547c478bd9Sstevel@tonic-gate (void) pipe(pv); 3557c478bd9Sstevel@tonic-gate pid = fork(); 3567c478bd9Sstevel@tonic-gate if (pid == (pid_t)-1) { 3577c478bd9Sstevel@tonic-gate error("Try again.\n"); 3587c478bd9Sstevel@tonic-gate pam_end(pamh, PAM_ABORT); 3597c478bd9Sstevel@tonic-gate exit(1); 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate if (pid) { 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * since the daemon is running as the user no need 3647c478bd9Sstevel@tonic-gate * to prune privileges. 3657c478bd9Sstevel@tonic-gate */ 3667c478bd9Sstevel@tonic-gate (void) close(0); (void) close(1); (void) close(2); 3677c478bd9Sstevel@tonic-gate (void) close(f); (void) close(pv[1]); 3687c478bd9Sstevel@tonic-gate FD_ZERO(&readfrom); 3697c478bd9Sstevel@tonic-gate FD_SET(s, &readfrom); 3707c478bd9Sstevel@tonic-gate FD_SET(pv[0], &readfrom); 3717c478bd9Sstevel@tonic-gate (void) ioctl(pv[0], FIONBIO, (char *)&one); 3727c478bd9Sstevel@tonic-gate /* should set s nbio! */ 3737c478bd9Sstevel@tonic-gate do { 3747c478bd9Sstevel@tonic-gate ready = readfrom; 3757c478bd9Sstevel@tonic-gate if (select(MAXFD(s, pv[0])+1, &ready, NULL, 3767c478bd9Sstevel@tonic-gate NULL, NULL) < 0) { 3777c478bd9Sstevel@tonic-gate perror("select:"); 3787c478bd9Sstevel@tonic-gate exit(1); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate if (FD_ISSET(s, &ready)) { 3817c478bd9Sstevel@tonic-gate if (read(s, &sig, 1) <= 0) 3827c478bd9Sstevel@tonic-gate FD_CLR(s, &readfrom); 3837c478bd9Sstevel@tonic-gate else 3847c478bd9Sstevel@tonic-gate (void) killpg(pid, sig); 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate if (FD_ISSET(pv[0], &ready)) { 3877c478bd9Sstevel@tonic-gate cc = read(pv[0], buf, sizeof (buf)); 3887c478bd9Sstevel@tonic-gate if (cc <= 0) { 3897c478bd9Sstevel@tonic-gate (void) shutdown(s, 1+1); 3907c478bd9Sstevel@tonic-gate FD_CLR(pv[0], &readfrom); 3917c478bd9Sstevel@tonic-gate } else 3927c478bd9Sstevel@tonic-gate (void) write(s, buf, cc); 3937c478bd9Sstevel@tonic-gate } 3947c478bd9Sstevel@tonic-gate } while (FD_ISSET(s, &readfrom) || 3957c478bd9Sstevel@tonic-gate FD_ISSET(pv[0], &readfrom)); 3967c478bd9Sstevel@tonic-gate exit(0); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate /* setpgrp(0, getpid()); */ 3997c478bd9Sstevel@tonic-gate (void) setsid(); /* Should be the same as above. */ 4007c478bd9Sstevel@tonic-gate (void) close(s); (void)close(pv[0]); 4017c478bd9Sstevel@tonic-gate (void) dup2(pv[1], 2); 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate 4047c478bd9Sstevel@tonic-gate if (*pwd->pw_shell == '\0') 4057c478bd9Sstevel@tonic-gate pwd->pw_shell = "/bin/sh"; 4067c478bd9Sstevel@tonic-gate if (f > 2) 4077c478bd9Sstevel@tonic-gate (void) close(f); 4087c478bd9Sstevel@tonic-gate /* Change directory only after becoming the appropriate user. */ 4097c478bd9Sstevel@tonic-gate if (chdir(pwd->pw_dir) < 0) { 4107c478bd9Sstevel@tonic-gate error("No remote directory.\n"); 4117c478bd9Sstevel@tonic-gate pam_end(pamh, PAM_ABORT); 4127c478bd9Sstevel@tonic-gate exit(1); 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate #ifdef SYSV 4157c478bd9Sstevel@tonic-gate if (pwd->pw_uid) 4167c478bd9Sstevel@tonic-gate envinit[ENVINIT_PATH] = userpath; 4177c478bd9Sstevel@tonic-gate else 4187c478bd9Sstevel@tonic-gate envinit[ENVINIT_PATH] = rootpath; 4197c478bd9Sstevel@tonic-gate #endif /* SYSV */ 4207c478bd9Sstevel@tonic-gate (void) strncat(homedir, pwd->pw_dir, sizeof (homedir) - 6); 4217c478bd9Sstevel@tonic-gate (void) strncat(shell, pwd->pw_shell, sizeof (shell) - 7); 4227c478bd9Sstevel@tonic-gate (void) strncat(username, pwd->pw_name, sizeof (username) - 6); 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * add PAM environment variables set by modules 4267c478bd9Sstevel@tonic-gate * -- only allowed 16 (PAM_ENV_ELIM) 4277c478bd9Sstevel@tonic-gate * -- check to see if the environment variable is legal 4287c478bd9Sstevel@tonic-gate */ 4297c478bd9Sstevel@tonic-gate for (end_env = 0; envinit[end_env] != 0; end_env++) 4307c478bd9Sstevel@tonic-gate ; 4317c478bd9Sstevel@tonic-gate if ((pam_env = pam_getenvlist(pamh)) != 0) { 4327c478bd9Sstevel@tonic-gate while (pam_env[idx] != 0) { 4337c478bd9Sstevel@tonic-gate if (idx < PAM_ENV_ELIM && 4347c478bd9Sstevel@tonic-gate legalenvvar(pam_env[idx])) { 4357c478bd9Sstevel@tonic-gate envinit[end_env + idx] = pam_env[idx]; 4367c478bd9Sstevel@tonic-gate } 4377c478bd9Sstevel@tonic-gate idx++; 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate pam_end(pamh, PAM_SUCCESS); 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate cp = rindex(pwd->pw_shell, '/'); 4447c478bd9Sstevel@tonic-gate if (cp) 4457c478bd9Sstevel@tonic-gate cp++; 4467c478bd9Sstevel@tonic-gate else 4477c478bd9Sstevel@tonic-gate cp = pwd->pw_shell; 4487c478bd9Sstevel@tonic-gate (void) execle(pwd->pw_shell, cp, "-c", cmdbuf, (char *)0, envinit); 4497c478bd9Sstevel@tonic-gate perror(pwd->pw_shell); 4507c478bd9Sstevel@tonic-gate exit(1); 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate 4537c478bd9Sstevel@tonic-gate static void 4547c478bd9Sstevel@tonic-gate getstr(char *buf, int cnt, char *err) 4557c478bd9Sstevel@tonic-gate { 4567c478bd9Sstevel@tonic-gate char c; 4577c478bd9Sstevel@tonic-gate 4587c478bd9Sstevel@tonic-gate do { 4597c478bd9Sstevel@tonic-gate if (read(0, &c, 1) != 1) 4607c478bd9Sstevel@tonic-gate exit(1); 4617c478bd9Sstevel@tonic-gate *buf++ = c; 4627c478bd9Sstevel@tonic-gate if (--cnt == 0) { 4637c478bd9Sstevel@tonic-gate error("%s too long\n", err); 4647c478bd9Sstevel@tonic-gate exit(1); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate } while (c != 0); 4677c478bd9Sstevel@tonic-gate } 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate static void 4707c478bd9Sstevel@tonic-gate error(char *fmt, ...) 4717c478bd9Sstevel@tonic-gate { 4727c478bd9Sstevel@tonic-gate va_list ap; 4737c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate buf[0] = 1; 4767c478bd9Sstevel@tonic-gate va_start(ap, fmt); 4777c478bd9Sstevel@tonic-gate (void) vsprintf(buf+1, fmt, ap); 4787c478bd9Sstevel@tonic-gate va_end(ap); 4797c478bd9Sstevel@tonic-gate (void) write(2, buf, strlen(buf)); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate static char *illegal[] = { 4837c478bd9Sstevel@tonic-gate "SHELL=", 4847c478bd9Sstevel@tonic-gate "HOME=", 4857c478bd9Sstevel@tonic-gate "LOGNAME=", 4867c478bd9Sstevel@tonic-gate #ifndef NO_MAIL 4877c478bd9Sstevel@tonic-gate "MAIL=", 4887c478bd9Sstevel@tonic-gate #endif 4897c478bd9Sstevel@tonic-gate "CDPATH=", 4907c478bd9Sstevel@tonic-gate "IFS=", 4917c478bd9Sstevel@tonic-gate "PATH=", 4927c478bd9Sstevel@tonic-gate "USER=", 4937c478bd9Sstevel@tonic-gate 0 4947c478bd9Sstevel@tonic-gate }; 4957c478bd9Sstevel@tonic-gate 4967c478bd9Sstevel@tonic-gate /* 4977c478bd9Sstevel@tonic-gate * legalenvvar - can PAM insert this environmental variable? 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate static int 5017c478bd9Sstevel@tonic-gate legalenvvar(char *s) 5027c478bd9Sstevel@tonic-gate { 5037c478bd9Sstevel@tonic-gate register char **p; 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate for (p = illegal; *p; p++) 5067c478bd9Sstevel@tonic-gate if (strncmp(s, *p, strlen(*p)) == 0) 5077c478bd9Sstevel@tonic-gate return (0); 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate if (s[0] == 'L' && s[1] == 'D' && s[2] == '_') 5107c478bd9Sstevel@tonic-gate return (0); 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate return (1); 5137c478bd9Sstevel@tonic-gate } 5147c478bd9Sstevel@tonic-gate 5157c478bd9Sstevel@tonic-gate /* 5167c478bd9Sstevel@tonic-gate * rexec_conv - This is the conv (conversation) function called from 5177c478bd9Sstevel@tonic-gate * a PAM authentication module to print error messages 5187c478bd9Sstevel@tonic-gate * or garner information from the user. 5197c478bd9Sstevel@tonic-gate */ 5207c478bd9Sstevel@tonic-gate 5217c478bd9Sstevel@tonic-gate /* ARGSUSED3 */ 5227c478bd9Sstevel@tonic-gate static int 5237c478bd9Sstevel@tonic-gate rexec_conv(int num_msg, struct pam_message **msg, 5247c478bd9Sstevel@tonic-gate struct pam_response **response, void *appdata_ptr) 5257c478bd9Sstevel@tonic-gate { 5267c478bd9Sstevel@tonic-gate struct pam_message *m; 5277c478bd9Sstevel@tonic-gate struct pam_response *r; 5287c478bd9Sstevel@tonic-gate int i; 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate if (num_msg <= 0) 5317c478bd9Sstevel@tonic-gate return (PAM_CONV_ERR); 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate *response = calloc(num_msg, sizeof (struct pam_response)); 5347c478bd9Sstevel@tonic-gate if (*response == NULL) 5357c478bd9Sstevel@tonic-gate return (PAM_BUF_ERR); 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate m = *msg; 5387c478bd9Sstevel@tonic-gate r = *response; 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate if (m->msg_style == PAM_PROMPT_ECHO_OFF) { 5417c478bd9Sstevel@tonic-gate if (pass[0] != '\0') { 5427c478bd9Sstevel@tonic-gate r->resp = strdup(pass); 5437c478bd9Sstevel@tonic-gate if (r->resp == NULL) { 5447c478bd9Sstevel@tonic-gate /* free responses */ 5457c478bd9Sstevel@tonic-gate r = *response; 5467c478bd9Sstevel@tonic-gate for (i = 0; i < num_msg; i++, r++) { 5477c478bd9Sstevel@tonic-gate if (r->resp) 5487c478bd9Sstevel@tonic-gate free(r->resp); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate free(*response); 5517c478bd9Sstevel@tonic-gate *response = NULL; 5527c478bd9Sstevel@tonic-gate return (PAM_BUF_ERR); 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate } 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate return (PAM_SUCCESS); 5587c478bd9Sstevel@tonic-gate } 559