xref: /onnv-gate/usr/src/cmd/rexd/unix_login.c (revision 620:70e88a3808c9)
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
ValidUser(host,uid,gid,error,shell,dir,rst)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
AllocatePty(socket0,socket1)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
OpenPtySlave()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
DoHelper(pfd0,pfd1,pfd2)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
KillHelper(int grp)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
LoginUser(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
LogoutUser(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
SetPtyMode(mode)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
SetPtySize(struct rex_ttysize * sizep)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
SendSignal(int sig)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
HelperRead(pollfd_t * fdp,int nfds,int * pollretval)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