10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 23*620Ssm26363 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #define BSD_COMP 300Sstevel@tonic-gate #include <errno.h> 310Sstevel@tonic-gate #include <fcntl.h> 320Sstevel@tonic-gate #include <pwd.h> 330Sstevel@tonic-gate #include <signal.h> 340Sstevel@tonic-gate #include <stdio.h> 350Sstevel@tonic-gate #include <stdlib.h> 360Sstevel@tonic-gate #include <unistd.h> 370Sstevel@tonic-gate 380Sstevel@tonic-gate #include <sac.h> /* for SC_WILDC */ 390Sstevel@tonic-gate #include <utmpx.h> 400Sstevel@tonic-gate 410Sstevel@tonic-gate #include <rpc/rpc.h> 420Sstevel@tonic-gate #include <sys/file.h> 430Sstevel@tonic-gate #include <sys/filio.h> 440Sstevel@tonic-gate #include <sys/ioctl.h> 450Sstevel@tonic-gate #include <sys/signal.h> 460Sstevel@tonic-gate #include <sys/stat.h> 470Sstevel@tonic-gate #include <sys/types.h> 480Sstevel@tonic-gate #include <sys/wait.h> 490Sstevel@tonic-gate 500Sstevel@tonic-gate /* 510Sstevel@tonic-gate * # include <sys/label.h> 520Sstevel@tonic-gate * # include <sys/audit.h> 530Sstevel@tonic-gate * 540Sstevel@tonic-gate * 550Sstevel@tonic-gate * 560Sstevel@tonic-gate * # include <pwdadj.h> 570Sstevel@tonic-gate */ 580Sstevel@tonic-gate 590Sstevel@tonic-gate #include <sys/ttold.h> 600Sstevel@tonic-gate #include <stropts.h> 610Sstevel@tonic-gate #include <sys/stream.h> 620Sstevel@tonic-gate 630Sstevel@tonic-gate 640Sstevel@tonic-gate 650Sstevel@tonic-gate #include "rex.h" 660Sstevel@tonic-gate 670Sstevel@tonic-gate #include <security/pam_appl.h> 680Sstevel@tonic-gate pam_handle_t *pamh; 690Sstevel@tonic-gate 700Sstevel@tonic-gate #define NTTYDISC 2 /* New ttydiscipline: stolen from ttold.h */ 710Sstevel@tonic-gate 720Sstevel@tonic-gate /* 730Sstevel@tonic-gate * unix_login - hairy junk to simulate logins for Unix 740Sstevel@tonic-gate */ 750Sstevel@tonic-gate 760Sstevel@tonic-gate int Master, Slave; /* sides of the pty */ 770Sstevel@tonic-gate int Slave_is_closed_on_master_side; 780Sstevel@tonic-gate 790Sstevel@tonic-gate static char *slavename; 800Sstevel@tonic-gate extern char *ptsname(); 810Sstevel@tonic-gate 820Sstevel@tonic-gate 830Sstevel@tonic-gate int InputSocket, /* Network sockets */ 840Sstevel@tonic-gate OutputSocket; 850Sstevel@tonic-gate int Helper1, /* pids of the helpers */ 860Sstevel@tonic-gate Helper2; 870Sstevel@tonic-gate char UserName[256]; /* saves the user name for loging */ 880Sstevel@tonic-gate char HostName[256]; /* saves the host name for loging */ 890Sstevel@tonic-gate 900Sstevel@tonic-gate static int TtySlot; /* slot number in Utmpx */ 910Sstevel@tonic-gate 920Sstevel@tonic-gate /* 930Sstevel@tonic-gate * pseudo-xprts used to add pty fds to svc_pollfd[]. This allows the 940Sstevel@tonic-gate * polling for all i/o in one poll(). 950Sstevel@tonic-gate */ 960Sstevel@tonic-gate SVCXPRT uxprt[2]; 970Sstevel@tonic-gate 980Sstevel@tonic-gate #define INPUTSOCKET 0 /* InputSocket xprt */ 990Sstevel@tonic-gate #define MASTER 1 /* Master xprt */ 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate extern int child; /* pid of the executed process */ 1030Sstevel@tonic-gate extern int ChildDied; /* flag */ 1040Sstevel@tonic-gate extern int HasHelper; /* flag */ 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate extern void setproctitle(char *user, char *host); 1070Sstevel@tonic-gate extern int Debug; 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate extern void audit_rexd_fail(char *, char *, char *, uid_t, gid_t, 1100Sstevel@tonic-gate char *, char **); 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate #define bzero(s, n) memset((s), 0, (n)) 1130Sstevel@tonic-gate #define bcopy(a, b, c) memcpy((b), (a), (c)) 1140Sstevel@tonic-gate 115*620Ssm26363 static void LogoutUser(void); 1160Sstevel@tonic-gate 1170Sstevel@tonic-gate /* 1180Sstevel@tonic-gate * Check for user being able to run on this machine. 1190Sstevel@tonic-gate * returns 0 if OK, TRUE if problem, error message in "error" 1200Sstevel@tonic-gate * copies name of shell and home directory if user is valid. 1210Sstevel@tonic-gate */ 1220Sstevel@tonic-gate int 1230Sstevel@tonic-gate ValidUser(host, uid, gid, error, shell, dir, rst) 1240Sstevel@tonic-gate char *host; /* passed in */ 1250Sstevel@tonic-gate uid_t uid; 1260Sstevel@tonic-gate gid_t gid; 1270Sstevel@tonic-gate char *error; /* filled in on return */ 1280Sstevel@tonic-gate char *shell; /* filled in on return */ 1290Sstevel@tonic-gate char *dir; /* filled in on return */ 1300Sstevel@tonic-gate struct rex_start *rst; /* passed in */ 1310Sstevel@tonic-gate { 1320Sstevel@tonic-gate struct passwd *pw, *getpwuid(); 1330Sstevel@tonic-gate int v; 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate pw = getpwuid(uid); 1360Sstevel@tonic-gate if (pw == NULL || pw->pw_name == NULL) 1370Sstevel@tonic-gate { 1380Sstevel@tonic-gate errprintf(error, "rexd: User id %d not valid\n", uid); 1390Sstevel@tonic-gate audit_rexd_fail("user id is not valid", 1400Sstevel@tonic-gate host, 1410Sstevel@tonic-gate NULL, 1420Sstevel@tonic-gate uid, 1430Sstevel@tonic-gate gid, 1440Sstevel@tonic-gate NULL, 1450Sstevel@tonic-gate rst->rst_cmd); /* BSM */ 1460Sstevel@tonic-gate return (1); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate strncpy(UserName, pw->pw_name, sizeof (UserName) - 1); 1490Sstevel@tonic-gate strncpy(HostName, host, sizeof (HostName) - 1); 1500Sstevel@tonic-gate strcpy(shell, pw->pw_shell); 1510Sstevel@tonic-gate strcpy(dir, pw->pw_dir); 1520Sstevel@tonic-gate setproctitle(pw->pw_name, host); 1530Sstevel@tonic-gate 1540Sstevel@tonic-gate if (pam_start("rexd", pw->pw_name, NULL, &pamh) != PAM_SUCCESS || 1550Sstevel@tonic-gate pam_set_item(pamh, PAM_RHOST, host) != PAM_SUCCESS) { 1560Sstevel@tonic-gate audit_rexd_fail("user id is not valid", 1570Sstevel@tonic-gate host, 1580Sstevel@tonic-gate pw->pw_name, 1590Sstevel@tonic-gate uid, 1600Sstevel@tonic-gate gid, 1610Sstevel@tonic-gate shell, 1620Sstevel@tonic-gate rst->rst_cmd); /* BSM */ 1630Sstevel@tonic-gate errprintf(error, "rexd: User id %d not valid\n", uid); 1640Sstevel@tonic-gate if (pamh) { 1650Sstevel@tonic-gate pam_end(pamh, PAM_ABORT); 1660Sstevel@tonic-gate pamh = NULL; 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate return (1); 1690Sstevel@tonic-gate } 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate if ((v = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) { 1720Sstevel@tonic-gate switch (v) { 1730Sstevel@tonic-gate case PAM_NEW_AUTHTOK_REQD: 1740Sstevel@tonic-gate errprintf(error, 1750Sstevel@tonic-gate "rexd: User id %d Password Expired\n", uid); 1760Sstevel@tonic-gate break; 1770Sstevel@tonic-gate case PAM_PERM_DENIED: 1780Sstevel@tonic-gate errprintf(error, 1790Sstevel@tonic-gate "rexd: User id %d Account Expired\n", uid); 1800Sstevel@tonic-gate break; 1810Sstevel@tonic-gate case PAM_AUTHTOK_EXPIRED: 1820Sstevel@tonic-gate errprintf(error, 1830Sstevel@tonic-gate "rexd: User id %d Password Expired\n", uid); 1840Sstevel@tonic-gate break; 1850Sstevel@tonic-gate default: 1860Sstevel@tonic-gate errprintf(error, 1870Sstevel@tonic-gate "rexd: User id %d not valid\n", uid); 1880Sstevel@tonic-gate break; 1890Sstevel@tonic-gate } 1900Sstevel@tonic-gate pam_end(pamh, PAM_ABORT); 1910Sstevel@tonic-gate pamh = NULL; 1920Sstevel@tonic-gate 1930Sstevel@tonic-gate audit_rexd_fail("user account expired", 1940Sstevel@tonic-gate host, 1950Sstevel@tonic-gate pw->pw_name, 1960Sstevel@tonic-gate uid, 1970Sstevel@tonic-gate gid, 1980Sstevel@tonic-gate shell, 1990Sstevel@tonic-gate rst->rst_cmd); /* BSM */ 2000Sstevel@tonic-gate return (1); 2010Sstevel@tonic-gate } 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate return (0); 2040Sstevel@tonic-gate } 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate /* 2070Sstevel@tonic-gate * Add an audit record with argv that was pre-set, plus the given string 2080Sstevel@tonic-gate */ 2090Sstevel@tonic-gate 2100Sstevel@tonic-gate /* 2110Sstevel@tonic-gate * Allocate a pseudo-terminal 2120Sstevel@tonic-gate * sets the global variables Master and Slave. 2130Sstevel@tonic-gate * returns 1 on error, 0 if OK 2140Sstevel@tonic-gate */ 2150Sstevel@tonic-gate int 2160Sstevel@tonic-gate AllocatePty(socket0, socket1) 2170Sstevel@tonic-gate int socket0, socket1; 2180Sstevel@tonic-gate { 2190Sstevel@tonic-gate 2200Sstevel@tonic-gate int on = 1; 2210Sstevel@tonic-gate 2220Sstevel@tonic-gate sigset(SIGHUP, SIG_IGN); 2230Sstevel@tonic-gate sigset(SIGTTOU, SIG_IGN); 2240Sstevel@tonic-gate sigset(SIGTTIN, SIG_IGN); 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate if ((Master = open("/dev/ptmx", O_RDWR)) == -1) { 2270Sstevel@tonic-gate if (Debug) 2280Sstevel@tonic-gate printf("open-ptmx-failure\n"); 2290Sstevel@tonic-gate perror("AloocatePtyMaster fails"); 2300Sstevel@tonic-gate return (1); /* error could not open /dev/ptmx */ 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate if (Debug) 2330Sstevel@tonic-gate printf("open-ptmx success Master =%d\n", Master); 2340Sstevel@tonic-gate if (Debug) 2350Sstevel@tonic-gate printf("Before grantpt...Master=%d\n", Master); 2360Sstevel@tonic-gate 2370Sstevel@tonic-gate if (grantpt(Master) == -1) { 2380Sstevel@tonic-gate perror("could not grant slave pty"); 2390Sstevel@tonic-gate exit(1); 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate if (unlockpt(Master) == -1) { 2420Sstevel@tonic-gate perror("could not unlock slave pty"); 2430Sstevel@tonic-gate exit(1); 2440Sstevel@tonic-gate } 2450Sstevel@tonic-gate if ((slavename = ptsname(Master)) == NULL) { 2460Sstevel@tonic-gate perror("could not enable slave pty"); 2470Sstevel@tonic-gate exit(1); 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate if ((Slave = open(slavename, O_RDWR)) == -1) { 2500Sstevel@tonic-gate perror("could not open slave pty"); 2510Sstevel@tonic-gate exit(1); 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate if (ioctl(Slave, I_PUSH, "ptem") == -1) { 2540Sstevel@tonic-gate perror("ioctl I_PUSH ptem"); 2550Sstevel@tonic-gate exit(1); 2560Sstevel@tonic-gate } 2570Sstevel@tonic-gate if (ioctl(Slave, I_PUSH, "ldterm") == -1) { 2580Sstevel@tonic-gate perror("ioctl I_PUSH ldterm"); 2590Sstevel@tonic-gate exit(1); 2600Sstevel@tonic-gate } 2610Sstevel@tonic-gate if (ioctl(Slave, I_PUSH, "ttcompat") == -1) { 2620Sstevel@tonic-gate perror("ioctl I_PUSH ttcompat"); 2630Sstevel@tonic-gate exit(1); 2640Sstevel@tonic-gate } 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate Slave_is_closed_on_master_side = FALSE; 2670Sstevel@tonic-gate setsid(); /* get rid of controlling terminal */ 2680Sstevel@tonic-gate /* LoginUser(); */ 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate InputSocket = socket0; 2710Sstevel@tonic-gate OutputSocket = socket1; 2720Sstevel@tonic-gate ioctl(Master, FIONBIO, &on); 2730Sstevel@tonic-gate uxprt[INPUTSOCKET].xp_fd = InputSocket; 2740Sstevel@tonic-gate xprt_register(&uxprt[INPUTSOCKET]); 2750Sstevel@tonic-gate uxprt[MASTER].xp_fd = Master; 2760Sstevel@tonic-gate xprt_register(&uxprt[MASTER]); 2770Sstevel@tonic-gate return (0); 2780Sstevel@tonic-gate 2790Sstevel@tonic-gate } 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate void 2820Sstevel@tonic-gate OpenPtySlave() 2830Sstevel@tonic-gate { 2840Sstevel@tonic-gate close(Slave); 2850Sstevel@tonic-gate Slave = open(slavename, O_RDWR); 2860Sstevel@tonic-gate if (Slave < 0) { 2870Sstevel@tonic-gate perror(slavename); 2880Sstevel@tonic-gate exit(1); 2890Sstevel@tonic-gate } 2900Sstevel@tonic-gate } 2910Sstevel@tonic-gate 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate 2940Sstevel@tonic-gate /* 2950Sstevel@tonic-gate * Special processing for interactive operation. 2960Sstevel@tonic-gate * Given pointers to three standard file descriptors, 2970Sstevel@tonic-gate * which get set to point to the pty. 2980Sstevel@tonic-gate */ 2990Sstevel@tonic-gate void 3000Sstevel@tonic-gate DoHelper(pfd0, pfd1, pfd2) 3010Sstevel@tonic-gate int *pfd0, *pfd1, *pfd2; 3020Sstevel@tonic-gate { 3030Sstevel@tonic-gate int pgrp; 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate sigset(SIGINT, SIG_IGN); 3070Sstevel@tonic-gate close(Master); 3080Sstevel@tonic-gate close(InputSocket); 3090Sstevel@tonic-gate close(OutputSocket); 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate *pfd0 = Slave; 3120Sstevel@tonic-gate *pfd1 = Slave; 3130Sstevel@tonic-gate *pfd2 = Slave; 3140Sstevel@tonic-gate } 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate /* 3180Sstevel@tonic-gate * destroy the helpers when the executing process dies 3190Sstevel@tonic-gate */ 320*620Ssm26363 void 321*620Ssm26363 KillHelper(int grp) 3220Sstevel@tonic-gate { 3230Sstevel@tonic-gate if (Debug) 3240Sstevel@tonic-gate printf("Enter KillHelper\n"); 3250Sstevel@tonic-gate close(Master); 3260Sstevel@tonic-gate xprt_unregister(&uxprt[MASTER]); 3270Sstevel@tonic-gate close(InputSocket); 3280Sstevel@tonic-gate xprt_unregister(&uxprt[INPUTSOCKET]); 3290Sstevel@tonic-gate close(OutputSocket); 3300Sstevel@tonic-gate LogoutUser(); 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate if (grp) 3330Sstevel@tonic-gate kill((-grp), SIGKILL); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate 3370Sstevel@tonic-gate /* 3380Sstevel@tonic-gate * edit the Unix traditional data files that tell who is logged 3390Sstevel@tonic-gate * into "the system" 3400Sstevel@tonic-gate */ 3410Sstevel@tonic-gate unsigned char utid[] = {'o', 'n', SC_WILDC, SC_WILDC}; 3420Sstevel@tonic-gate 343*620Ssm26363 void 344*620Ssm26363 LoginUser(void) 3450Sstevel@tonic-gate { 3460Sstevel@tonic-gate 3470Sstevel@tonic-gate char *user; 3480Sstevel@tonic-gate char *rhost; 3490Sstevel@tonic-gate /* the next 4 variables are needed for utmpx mgmt */ 3500Sstevel@tonic-gate int tmplen; 3510Sstevel@tonic-gate struct utmpx *u = NULL; 3520Sstevel@tonic-gate struct utmpx set_utmp; 3530Sstevel@tonic-gate char *ttyntail; 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate /* We're pretty drastic here, exiting if an error is detected */ 3560Sstevel@tonic-gate if (pam_set_item(pamh, PAM_TTY, slavename) != PAM_SUCCESS || 3570Sstevel@tonic-gate pam_get_item(pamh, PAM_USER, (void **) &user) != PAM_SUCCESS || 3580Sstevel@tonic-gate pam_get_item(pamh, PAM_RHOST, (void **) &rhost) != PAM_SUCCESS || 3590Sstevel@tonic-gate pam_open_session(pamh, 0) != PAM_SUCCESS) { 3600Sstevel@tonic-gate /* 3610Sstevel@tonic-gate * XXX should print something but for now we exit 3620Sstevel@tonic-gate */ 3630Sstevel@tonic-gate exit(1); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate (void) memset((void *)&set_utmp, 0, sizeof (set_utmp)); 3670Sstevel@tonic-gate (void) time(&set_utmp.ut_tv.tv_sec); 3680Sstevel@tonic-gate set_utmp.ut_pid = getpid(); 3690Sstevel@tonic-gate if (rhost != NULL && rhost[0] != '\0') { 3700Sstevel@tonic-gate (void) strcpy(set_utmp.ut_host, rhost); 3710Sstevel@tonic-gate tmplen = strlen(rhost) + 1; 3720Sstevel@tonic-gate if (tmplen < sizeof (set_utmp.ut_host)) 3730Sstevel@tonic-gate set_utmp.ut_syslen = tmplen; 3740Sstevel@tonic-gate else 3750Sstevel@tonic-gate set_utmp.ut_syslen = sizeof (set_utmp.ut_host); 3760Sstevel@tonic-gate } else { 3770Sstevel@tonic-gate (void) memset(set_utmp.ut_host, 0, sizeof (set_utmp.ut_host)); 3780Sstevel@tonic-gate set_utmp.ut_syslen = 0; 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate (void) strcpy(set_utmp.ut_user, user); 3810Sstevel@tonic-gate 3820Sstevel@tonic-gate /* 3830Sstevel@tonic-gate * Copy in the name of the tty minus the "/dev/" if a /dev/ is 3840Sstevel@tonic-gate * in the path name. 3850Sstevel@tonic-gate */ 3860Sstevel@tonic-gate ttyntail = slavename; 3870Sstevel@tonic-gate if (strstr(ttyntail, "/dev/") != 0) 3880Sstevel@tonic-gate ttyntail = ttyntail + strlen("/dev/"); 3890Sstevel@tonic-gate (void) strcpy(set_utmp.ut_line, ttyntail); 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate set_utmp.ut_type = USER_PROCESS; 3920Sstevel@tonic-gate if (utid != NULL) 3930Sstevel@tonic-gate (void) memcpy(set_utmp.ut_id, utid, sizeof (set_utmp.ut_id)); 3940Sstevel@tonic-gate /* 3950Sstevel@tonic-gate * Go through each entry one by one, looking only at INIT, 3960Sstevel@tonic-gate * LOGIN or USER Processes. Use the entry found if flags == 0 3970Sstevel@tonic-gate * and the line name matches, or if the process ID matches if 3980Sstevel@tonic-gate * the UPDATE_ENTRY flag is set. The UPDATE_ENTRY flag is mainly 3990Sstevel@tonic-gate * for login which normally only wants to update an entry if 4000Sstevel@tonic-gate * the pid fields matches. 4010Sstevel@tonic-gate */ 4020Sstevel@tonic-gate 4030Sstevel@tonic-gate if (u == (struct utmpx *)NULL) { 4040Sstevel@tonic-gate (void) makeutx(&set_utmp); 4050Sstevel@tonic-gate } else 4060Sstevel@tonic-gate updwtmpx(WTMPX_FILE, &set_utmp); 4070Sstevel@tonic-gate 4080Sstevel@tonic-gate } 4090Sstevel@tonic-gate 4100Sstevel@tonic-gate /* 4110Sstevel@tonic-gate * edit the Unix traditional data files that tell who is logged 4120Sstevel@tonic-gate * into "the system". 4130Sstevel@tonic-gate */ 414*620Ssm26363 static void 415*620Ssm26363 LogoutUser(void) 4160Sstevel@tonic-gate { 4170Sstevel@tonic-gate struct utmpx *up; 4180Sstevel@tonic-gate struct utmpx ut; 4190Sstevel@tonic-gate int pid; 4200Sstevel@tonic-gate char user[sizeof (ut.ut_user) + 1]; 4210Sstevel@tonic-gate char ttyn[sizeof (ut.ut_line) + 1]; 4220Sstevel@tonic-gate char rhost[sizeof (ut.ut_host) + 1]; 4230Sstevel@tonic-gate 4240Sstevel@tonic-gate sighold(SIGCHLD); /* no disruption during cleanup */ 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate if (pamh) { 4270Sstevel@tonic-gate pam_end(pamh, PAM_SUCCESS); 4280Sstevel@tonic-gate pamh = NULL; 4290Sstevel@tonic-gate } 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate /* BEGIN RESET UTMP */ 4320Sstevel@tonic-gate pid = child; 4330Sstevel@tonic-gate setutxent(); 4340Sstevel@tonic-gate while (up = getutxent()) { 4350Sstevel@tonic-gate if (up->ut_pid == pid) { 4360Sstevel@tonic-gate if (up->ut_type == DEAD_PROCESS) { 4370Sstevel@tonic-gate /* 4380Sstevel@tonic-gate * Cleaned up elsewhere. 4390Sstevel@tonic-gate */ 4400Sstevel@tonic-gate break; 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate strncpy(user, up->ut_user, sizeof (up->ut_user)); 4440Sstevel@tonic-gate user[sizeof (up->ut_user)] = '\0'; 4450Sstevel@tonic-gate strncpy(ttyn, up->ut_line, sizeof (up->ut_line)); 4460Sstevel@tonic-gate ttyn[sizeof (up->ut_line)] = '\0'; 4470Sstevel@tonic-gate strncpy(rhost, up->ut_host, sizeof (up->ut_host)); 4480Sstevel@tonic-gate rhost[sizeof (up->ut_host)] = '\0'; 4490Sstevel@tonic-gate 4500Sstevel@tonic-gate if ((pam_start("rexd", user, NULL, &pamh)) 4510Sstevel@tonic-gate == PAM_SUCCESS) { 4520Sstevel@tonic-gate (void) pam_set_item(pamh, PAM_TTY, ttyn); 4530Sstevel@tonic-gate (void) pam_set_item(pamh, PAM_RHOST, rhost); 4540Sstevel@tonic-gate (void) pam_close_session(pamh, 0); 4550Sstevel@tonic-gate (void) pam_end(pamh, PAM_SUCCESS); 4560Sstevel@tonic-gate pamh = NULL; 4570Sstevel@tonic-gate } 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate up->ut_type = DEAD_PROCESS; 4600Sstevel@tonic-gate up->ut_exit.e_termination = WTERMSIG(0); 4610Sstevel@tonic-gate up->ut_exit.e_exit = WEXITSTATUS(0); 4620Sstevel@tonic-gate (void) time(&up->ut_tv.tv_sec); 4630Sstevel@tonic-gate if (modutx(up) == NULL) { 4640Sstevel@tonic-gate /* 4650Sstevel@tonic-gate * Since modutx failed we'll 4660Sstevel@tonic-gate * write out the new entry 4670Sstevel@tonic-gate * ourselves. 4680Sstevel@tonic-gate */ 4690Sstevel@tonic-gate (void) pututxline(up); 4700Sstevel@tonic-gate updwtmpx("wtmpx", up); 4710Sstevel@tonic-gate } 4720Sstevel@tonic-gate break; 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate } 4750Sstevel@tonic-gate endutxent(); 4760Sstevel@tonic-gate /* END RESET UTMP */ 4770Sstevel@tonic-gate sigrelse(SIGCHLD); 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate /* 4810Sstevel@tonic-gate * set the pty modes to the given values 4820Sstevel@tonic-gate */ 483*620Ssm26363 void 4840Sstevel@tonic-gate SetPtyMode(mode) 4850Sstevel@tonic-gate struct rex_ttymode *mode; 4860Sstevel@tonic-gate { 4870Sstevel@tonic-gate struct sgttyb svr4_sgttyb_var; 4880Sstevel@tonic-gate int ldisc = NTTYDISC; 4890Sstevel@tonic-gate 4900Sstevel@tonic-gate if (Debug) 4910Sstevel@tonic-gate printf("Enter SetPtyMode\n"); 4920Sstevel@tonic-gate if (Debug) 4930Sstevel@tonic-gate printf("SetPtyMode:opened slave\n"); 4940Sstevel@tonic-gate ioctl(Slave, TIOCSETD, &ldisc); 4950Sstevel@tonic-gate if (Debug) 4960Sstevel@tonic-gate printf("SetPtyMode:Slave TIOCSETD done\n"); 4970Sstevel@tonic-gate 4980Sstevel@tonic-gate /* 4990Sstevel@tonic-gate * Copy from over-the-net(bsd) to SVR4 format 5000Sstevel@tonic-gate */ 5010Sstevel@tonic-gate svr4_sgttyb_var.sg_ispeed = mode->basic.sg_ispeed; 5020Sstevel@tonic-gate svr4_sgttyb_var.sg_ospeed = mode->basic.sg_ospeed; 5030Sstevel@tonic-gate svr4_sgttyb_var.sg_erase = mode->basic.sg_erase; 5040Sstevel@tonic-gate svr4_sgttyb_var.sg_kill = mode->basic.sg_kill; 5050Sstevel@tonic-gate svr4_sgttyb_var.sg_flags = (int)mode->basic.sg_flags; 5060Sstevel@tonic-gate /* 5070Sstevel@tonic-gate * Clear any possible sign extension caused by (int) 5080Sstevel@tonic-gate * typecast 5090Sstevel@tonic-gate */ 5100Sstevel@tonic-gate svr4_sgttyb_var.sg_flags &= 0xFFFF; 5110Sstevel@tonic-gate 5120Sstevel@tonic-gate ioctl(Slave, TIOCSETN, &svr4_sgttyb_var); 5130Sstevel@tonic-gate if (Debug) 5140Sstevel@tonic-gate printf("SetPtyMode:Slave TIOCSETN done\n"); 5150Sstevel@tonic-gate ioctl(Slave, TIOCSETC, &mode->more); 5160Sstevel@tonic-gate if (Debug) 5170Sstevel@tonic-gate printf("SetPtyMode:Slave TIOCSETC done\n"); 5180Sstevel@tonic-gate ioctl(Slave, TIOCSLTC, &mode->yetmore); 5190Sstevel@tonic-gate if (Debug) 5200Sstevel@tonic-gate printf("SetPtyMode:Slave TIOCSLTC done\n"); 5210Sstevel@tonic-gate ioctl(Slave, TIOCLSET, &mode->andmore); 5220Sstevel@tonic-gate if (Debug) 5230Sstevel@tonic-gate printf("SetPtyMode:Slave TIOCSET done\n"); 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate /* Opened in AllocPty for parent, still open in child */ 5260Sstevel@tonic-gate if (Slave_is_closed_on_master_side == FALSE) { 5270Sstevel@tonic-gate close(Slave); 5280Sstevel@tonic-gate Slave_is_closed_on_master_side = TRUE; 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate /* 5330Sstevel@tonic-gate * set the pty window size to the given value 5340Sstevel@tonic-gate */ 535*620Ssm26363 void 536*620Ssm26363 SetPtySize(struct rex_ttysize *sizep) 5370Sstevel@tonic-gate { 5380Sstevel@tonic-gate struct winsize newsize; 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate /* if size has changed, this ioctl changes it */ 5410Sstevel@tonic-gate /* *and* sends SIGWINCH to process group */ 5420Sstevel@tonic-gate 5430Sstevel@tonic-gate newsize.ws_row = (unsigned short) sizep->ts_lines; 5440Sstevel@tonic-gate newsize.ws_col = (unsigned short) sizep->ts_cols; 5450Sstevel@tonic-gate 5460Sstevel@tonic-gate (void) ioctl(Master, TIOCSWINSZ, &newsize); 5470Sstevel@tonic-gate if (Slave_is_closed_on_master_side == FALSE) { 5480Sstevel@tonic-gate close(Slave); 5490Sstevel@tonic-gate Slave_is_closed_on_master_side = TRUE; 5500Sstevel@tonic-gate } 5510Sstevel@tonic-gate } 5520Sstevel@tonic-gate 5530Sstevel@tonic-gate 5540Sstevel@tonic-gate /* 5550Sstevel@tonic-gate * send the given signal to the group controlling the terminal 5560Sstevel@tonic-gate */ 557*620Ssm26363 void 558*620Ssm26363 SendSignal(int sig) 5590Sstevel@tonic-gate { 5600Sstevel@tonic-gate pid_t pgrp; 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate pgrp = getpgid(child); 5630Sstevel@tonic-gate if (pgrp != (pid_t)-1) 5640Sstevel@tonic-gate (void) kill((-pgrp), sig); 5650Sstevel@tonic-gate } 5660Sstevel@tonic-gate 5670Sstevel@tonic-gate /* 5680Sstevel@tonic-gate * called when the main select loop detects that we might want to 5690Sstevel@tonic-gate * read something. 5700Sstevel@tonic-gate */ 5710Sstevel@tonic-gate void 5720Sstevel@tonic-gate HelperRead(pollfd_t *fdp, int nfds, int *pollretval) 5730Sstevel@tonic-gate { 5740Sstevel@tonic-gate char buf[128]; 5750Sstevel@tonic-gate int retval; 5760Sstevel@tonic-gate extern int errno; 5770Sstevel@tonic-gate int mask; 5780Sstevel@tonic-gate int master = -1; 5790Sstevel@tonic-gate int inputsocket = -1; 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate /* 5820Sstevel@tonic-gate * fdp pollset may be compressed. Search for Master and 5830Sstevel@tonic-gate * InputSocket fds. 5840Sstevel@tonic-gate */ 5850Sstevel@tonic-gate int i; 5860Sstevel@tonic-gate for (i = 0; i < nfds; i++) { 5870Sstevel@tonic-gate if (fdp[i].fd == Master && fdp[i].revents != 0) 5880Sstevel@tonic-gate master = i; 5890Sstevel@tonic-gate if (fdp[i].fd == InputSocket && fdp[i].revents != 0) 5900Sstevel@tonic-gate inputsocket = i; 5910Sstevel@tonic-gate } 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate /* mask = sigsetmask (sigmask (SIGCHLD)); */ 5940Sstevel@tonic-gate mask = sighold(SIGCHLD); 5950Sstevel@tonic-gate retval = 0; 5960Sstevel@tonic-gate if (master != -1) { 5970Sstevel@tonic-gate if (!(fdp[master].revents & (POLLERR | POLLHUP | POLLNVAL))) { 5980Sstevel@tonic-gate retval = read(Master, buf, sizeof (buf)); 5990Sstevel@tonic-gate if (retval > 0) { 6000Sstevel@tonic-gate (void) write(OutputSocket, buf, retval); 6010Sstevel@tonic-gate } else { 6020Sstevel@tonic-gate if (errno != EINTR && errno != EIO && 6030Sstevel@tonic-gate errno != EWOULDBLOCK) 6040Sstevel@tonic-gate perror("pty read"); 6050Sstevel@tonic-gate /* 1 => further sends disallowed */ 6060Sstevel@tonic-gate shutdown(OutputSocket, 1); 6070Sstevel@tonic-gate xprt_unregister(&uxprt[MASTER]); 6080Sstevel@tonic-gate } 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate /* clear this event for svc_getreq_poll */ 6120Sstevel@tonic-gate fdp[master].revents = 0; 6130Sstevel@tonic-gate *pollretval = *pollretval - 1; 6140Sstevel@tonic-gate 6150Sstevel@tonic-gate if (retval <= 0 && ChildDied) { 6160Sstevel@tonic-gate KillHelper(child); 6170Sstevel@tonic-gate HasHelper = 0; 6180Sstevel@tonic-gate if (inputsocket != -1) { 6190Sstevel@tonic-gate fdp[inputsocket].revents = 0; 6200Sstevel@tonic-gate *pollretval = *pollretval - 1; 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate goto done; 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate } 6250Sstevel@tonic-gate 6260Sstevel@tonic-gate if (inputsocket != -1) { 6270Sstevel@tonic-gate if (!(fdp[inputsocket].revents & (POLLERR | POLLHUP | 6280Sstevel@tonic-gate POLLNVAL))) { 6290Sstevel@tonic-gate retval = read(InputSocket, buf, sizeof (buf)); 6300Sstevel@tonic-gate if (retval > 0) { 6310Sstevel@tonic-gate (void) write(Master, buf, retval); 6320Sstevel@tonic-gate } else { 6330Sstevel@tonic-gate if (errno != EINTR && errno != EWOULDBLOCK) 6340Sstevel@tonic-gate perror("socket read"); 6350Sstevel@tonic-gate xprt_unregister(&uxprt[INPUTSOCKET]); 6360Sstevel@tonic-gate } 6370Sstevel@tonic-gate } 6380Sstevel@tonic-gate 6390Sstevel@tonic-gate /* clear this event for svc_getreq_poll */ 6400Sstevel@tonic-gate fdp[inputsocket].revents = 0; 6410Sstevel@tonic-gate *pollretval = *pollretval - 1; 6420Sstevel@tonic-gate } 6430Sstevel@tonic-gate 6440Sstevel@tonic-gate done: 6450Sstevel@tonic-gate /* sigsetmask (mask); */ 6460Sstevel@tonic-gate sigrelse(SIGCHLD); 6470Sstevel@tonic-gate } 648