xref: /freebsd/crypto/openssh/openbsd-compat/bsd-openpty.c (revision 1323ec571215a77ddd21294f0871979d5ad6b992)
1efcad6b7SDag-Erling Smørgrav /*
2efcad6b7SDag-Erling Smørgrav  * Please note: this implementation of openpty() is far from complete.
3efcad6b7SDag-Erling Smørgrav  * it is just enough for portable OpenSSH's needs.
4efcad6b7SDag-Erling Smørgrav  */
5efcad6b7SDag-Erling Smørgrav 
6efcad6b7SDag-Erling Smørgrav /*
7efcad6b7SDag-Erling Smørgrav  * Copyright (c) 2004 Damien Miller <djm@mindrot.org>
8efcad6b7SDag-Erling Smørgrav  *
9efcad6b7SDag-Erling Smørgrav  * Permission to use, copy, modify, and distribute this software for any
10efcad6b7SDag-Erling Smørgrav  * purpose with or without fee is hereby granted, provided that the above
11efcad6b7SDag-Erling Smørgrav  * copyright notice and this permission notice appear in all copies.
12efcad6b7SDag-Erling Smørgrav  *
13efcad6b7SDag-Erling Smørgrav  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14efcad6b7SDag-Erling Smørgrav  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15efcad6b7SDag-Erling Smørgrav  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16efcad6b7SDag-Erling Smørgrav  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17efcad6b7SDag-Erling Smørgrav  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18efcad6b7SDag-Erling Smørgrav  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19efcad6b7SDag-Erling Smørgrav  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20efcad6b7SDag-Erling Smørgrav  */
21efcad6b7SDag-Erling Smørgrav 
22efcad6b7SDag-Erling Smørgrav /*
23efcad6b7SDag-Erling Smørgrav  * Author: Tatu Ylonen <ylo@cs.hut.fi>
24efcad6b7SDag-Erling Smørgrav  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
25efcad6b7SDag-Erling Smørgrav  *                    All rights reserved
26efcad6b7SDag-Erling Smørgrav  * Allocating a pseudo-terminal, and making it the controlling tty.
27efcad6b7SDag-Erling Smørgrav  *
28efcad6b7SDag-Erling Smørgrav  * As far as I am concerned, the code I have written for this software
29efcad6b7SDag-Erling Smørgrav  * can be used freely for any purpose.  Any derived versions of this
30efcad6b7SDag-Erling Smørgrav  * software must be clearly marked as such, and if the derived work is
31efcad6b7SDag-Erling Smørgrav  * incompatible with the protocol description in the RFC file, it must be
32efcad6b7SDag-Erling Smørgrav  * called by a name other than "ssh" or "Secure Shell".
33efcad6b7SDag-Erling Smørgrav  */
34efcad6b7SDag-Erling Smørgrav 
35efcad6b7SDag-Erling Smørgrav #include "includes.h"
36efcad6b7SDag-Erling Smørgrav #if !defined(HAVE_OPENPTY)
37efcad6b7SDag-Erling Smørgrav 
38761efaa7SDag-Erling Smørgrav #include <sys/types.h>
39761efaa7SDag-Erling Smørgrav 
40761efaa7SDag-Erling Smørgrav #include <stdlib.h>
41761efaa7SDag-Erling Smørgrav 
42761efaa7SDag-Erling Smørgrav #ifdef HAVE_SYS_STAT_H
43761efaa7SDag-Erling Smørgrav # include <sys/stat.h>
44761efaa7SDag-Erling Smørgrav #endif
45761efaa7SDag-Erling Smørgrav #ifdef HAVE_SYS_IOCTL_H
46761efaa7SDag-Erling Smørgrav # include <sys/ioctl.h>
47761efaa7SDag-Erling Smørgrav #endif
48761efaa7SDag-Erling Smørgrav 
49761efaa7SDag-Erling Smørgrav #ifdef HAVE_FCNTL_H
50761efaa7SDag-Erling Smørgrav # include <fcntl.h>
51761efaa7SDag-Erling Smørgrav #endif
52761efaa7SDag-Erling Smørgrav 
53efcad6b7SDag-Erling Smørgrav #ifdef HAVE_UTIL_H
54efcad6b7SDag-Erling Smørgrav # include <util.h>
55efcad6b7SDag-Erling Smørgrav #endif /* HAVE_UTIL_H */
56efcad6b7SDag-Erling Smørgrav 
57efcad6b7SDag-Erling Smørgrav #ifdef HAVE_PTY_H
58efcad6b7SDag-Erling Smørgrav # include <pty.h>
59efcad6b7SDag-Erling Smørgrav #endif
60efcad6b7SDag-Erling Smørgrav #if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
61efcad6b7SDag-Erling Smørgrav # include <sys/stropts.h>
62efcad6b7SDag-Erling Smørgrav #endif
63efcad6b7SDag-Erling Smørgrav 
64761efaa7SDag-Erling Smørgrav #include <signal.h>
65761efaa7SDag-Erling Smørgrav #include <string.h>
66761efaa7SDag-Erling Smørgrav #include <unistd.h>
67761efaa7SDag-Erling Smørgrav 
6819261079SEd Maste #include "misc.h"
69*1323ec57SEd Maste #include "log.h"
7019261079SEd Maste 
71efcad6b7SDag-Erling Smørgrav #ifndef O_NOCTTY
72efcad6b7SDag-Erling Smørgrav #define O_NOCTTY 0
73efcad6b7SDag-Erling Smørgrav #endif
74efcad6b7SDag-Erling Smørgrav 
75*1323ec57SEd Maste #if defined(HAVE_DEV_PTMX) && !defined(HAVE__GETPTY)
76*1323ec57SEd Maste static int
openpty_streams(int * amaster,int * aslave)77*1323ec57SEd Maste openpty_streams(int *amaster, int *aslave)
78efcad6b7SDag-Erling Smørgrav {
79efcad6b7SDag-Erling Smørgrav 	/*
80efcad6b7SDag-Erling Smørgrav 	 * This code is used e.g. on Solaris 2.x.  (Note that Solaris 2.3
81efcad6b7SDag-Erling Smørgrav 	 * also has bsd-style ptys, but they simply do not work.)
82efcad6b7SDag-Erling Smørgrav 	 */
83efcad6b7SDag-Erling Smørgrav 	int ptm;
84efcad6b7SDag-Erling Smørgrav 	char *pts;
8519261079SEd Maste 	sshsig_t old_signal;
86efcad6b7SDag-Erling Smørgrav 
87efcad6b7SDag-Erling Smørgrav 	if ((ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY)) == -1)
88efcad6b7SDag-Erling Smørgrav 		return (-1);
89efcad6b7SDag-Erling Smørgrav 
90efcad6b7SDag-Erling Smørgrav 	/* XXX: need to close ptm on error? */
9119261079SEd Maste 	old_signal = ssh_signal(SIGCHLD, SIG_DFL);
92efcad6b7SDag-Erling Smørgrav 	if (grantpt(ptm) < 0)
93efcad6b7SDag-Erling Smørgrav 		return (-1);
9419261079SEd Maste 	ssh_signal(SIGCHLD, old_signal);
95efcad6b7SDag-Erling Smørgrav 
96efcad6b7SDag-Erling Smørgrav 	if (unlockpt(ptm) < 0)
97efcad6b7SDag-Erling Smørgrav 		return (-1);
98efcad6b7SDag-Erling Smørgrav 
99efcad6b7SDag-Erling Smørgrav 	if ((pts = ptsname(ptm)) == NULL)
100efcad6b7SDag-Erling Smørgrav 		return (-1);
101efcad6b7SDag-Erling Smørgrav 	*amaster = ptm;
102efcad6b7SDag-Erling Smørgrav 
103efcad6b7SDag-Erling Smørgrav 	/* Open the slave side. */
104efcad6b7SDag-Erling Smørgrav 	if ((*aslave = open(pts, O_RDWR | O_NOCTTY)) == -1) {
105efcad6b7SDag-Erling Smørgrav 		close(*amaster);
106efcad6b7SDag-Erling Smørgrav 		return (-1);
107efcad6b7SDag-Erling Smørgrav 	}
108efcad6b7SDag-Erling Smørgrav 
10919261079SEd Maste # if defined(I_FIND) && defined(__SVR4)
11019261079SEd Maste 	/*
11119261079SEd Maste 	 * If the streams modules have already been pushed then there
11219261079SEd Maste 	 * is no more work to do here.
11319261079SEd Maste 	 */
11419261079SEd Maste 	if (ioctl(*aslave, I_FIND, "ptem") != 0)
11519261079SEd Maste 		return 0;
11619261079SEd Maste # endif
11719261079SEd Maste 
118efcad6b7SDag-Erling Smørgrav 	/*
119efcad6b7SDag-Erling Smørgrav 	 * Try to push the appropriate streams modules, as described
120efcad6b7SDag-Erling Smørgrav 	 * in Solaris pts(7).
121efcad6b7SDag-Erling Smørgrav 	 */
122efcad6b7SDag-Erling Smørgrav 	ioctl(*aslave, I_PUSH, "ptem");
123efcad6b7SDag-Erling Smørgrav 	ioctl(*aslave, I_PUSH, "ldterm");
124efcad6b7SDag-Erling Smørgrav # ifndef __hpux
125efcad6b7SDag-Erling Smørgrav 	ioctl(*aslave, I_PUSH, "ttcompat");
126efcad6b7SDag-Erling Smørgrav # endif /* __hpux */
127efcad6b7SDag-Erling Smørgrav 	return (0);
128*1323ec57SEd Maste }
129*1323ec57SEd Maste #endif
130*1323ec57SEd Maste 
131*1323ec57SEd Maste int
openpty(int * amaster,int * aslave,char * name,struct termios * termp,struct winsize * winp)132*1323ec57SEd Maste openpty(int *amaster, int *aslave, char *name, struct termios *termp,
133*1323ec57SEd Maste    struct winsize *winp)
134*1323ec57SEd Maste {
135*1323ec57SEd Maste #if defined(HAVE__GETPTY)
136*1323ec57SEd Maste 	/*
137*1323ec57SEd Maste 	 * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
138*1323ec57SEd Maste 	 * pty's automagically when needed
139*1323ec57SEd Maste 	 */
140*1323ec57SEd Maste 	char *slave;
141*1323ec57SEd Maste 
142*1323ec57SEd Maste 	if ((slave = _getpty(amaster, O_RDWR, 0622, 0)) == NULL)
143*1323ec57SEd Maste 		return (-1);
144*1323ec57SEd Maste 
145*1323ec57SEd Maste 	/* Open the slave side. */
146*1323ec57SEd Maste 	if ((*aslave = open(slave, O_RDWR | O_NOCTTY)) == -1) {
147*1323ec57SEd Maste 		close(*amaster);
148*1323ec57SEd Maste 		return (-1);
149*1323ec57SEd Maste 	}
150*1323ec57SEd Maste 	return (0);
151*1323ec57SEd Maste 
152*1323ec57SEd Maste #elif defined(HAVE_DEV_PTMX)
153*1323ec57SEd Maste 
154*1323ec57SEd Maste #ifdef SSHD_ACQUIRES_CTTY
155*1323ec57SEd Maste 	/*
156*1323ec57SEd Maste 	 * On some (most? all?) SysV based systems with STREAMS based terminals,
157*1323ec57SEd Maste 	 * sshd will acquire a controlling terminal when it pushes the "ptem"
158*1323ec57SEd Maste 	 * module.  On such platforms, first allocate a sacrificial pty so
159*1323ec57SEd Maste 	 * that sshd already has a controlling terminal before allocating the
160*1323ec57SEd Maste 	 * one that will be passed back to the user process.  This ensures
161*1323ec57SEd Maste 	 * the second pty is not already the controlling terminal for a
162*1323ec57SEd Maste 	 * different session and is available to become controlling terminal
163*1323ec57SEd Maste 	 * for the client's subprocess.  See bugzilla #245 for details.
164*1323ec57SEd Maste 	 */
165*1323ec57SEd Maste 	int r, fd;
166*1323ec57SEd Maste 	static int junk_ptyfd = -1, junk_ttyfd;
167*1323ec57SEd Maste 
168*1323ec57SEd Maste 	r = openpty_streams(amaster, aslave);
169*1323ec57SEd Maste 	if (junk_ptyfd == -1 && (fd = open(_PATH_TTY, O_RDWR|O_NOCTTY)) >= 0) {
170*1323ec57SEd Maste 		close(fd);
171*1323ec57SEd Maste 		junk_ptyfd = *amaster;
172*1323ec57SEd Maste 		junk_ttyfd = *aslave;
173*1323ec57SEd Maste 		debug("STREAMS bug workaround pty %d tty %d name %s",
174*1323ec57SEd Maste 		    junk_ptyfd, junk_ttyfd, ttyname(junk_ttyfd));
175*1323ec57SEd Maste         } else
176*1323ec57SEd Maste 		return r;
177*1323ec57SEd Maste #endif
178*1323ec57SEd Maste 
179*1323ec57SEd Maste 	return openpty_streams(amaster, aslave);
180efcad6b7SDag-Erling Smørgrav 
181efcad6b7SDag-Erling Smørgrav #elif defined(HAVE_DEV_PTS_AND_PTC)
182efcad6b7SDag-Erling Smørgrav 	/* AIX-style pty code. */
183efcad6b7SDag-Erling Smørgrav 	const char *ttname;
184efcad6b7SDag-Erling Smørgrav 
185efcad6b7SDag-Erling Smørgrav 	if ((*amaster = open("/dev/ptc", O_RDWR | O_NOCTTY)) == -1)
186efcad6b7SDag-Erling Smørgrav 		return (-1);
187efcad6b7SDag-Erling Smørgrav 	if ((ttname = ttyname(*amaster)) == NULL)
188efcad6b7SDag-Erling Smørgrav 		return (-1);
189efcad6b7SDag-Erling Smørgrav 	if ((*aslave = open(ttname, O_RDWR | O_NOCTTY)) == -1) {
190efcad6b7SDag-Erling Smørgrav 		close(*amaster);
191efcad6b7SDag-Erling Smørgrav 		return (-1);
192efcad6b7SDag-Erling Smørgrav 	}
193efcad6b7SDag-Erling Smørgrav 	return (0);
194efcad6b7SDag-Erling Smørgrav 
195efcad6b7SDag-Erling Smørgrav #else
196efcad6b7SDag-Erling Smørgrav 	/* BSD-style pty code. */
197efcad6b7SDag-Erling Smørgrav 	char ptbuf[64], ttbuf[64];
198efcad6b7SDag-Erling Smørgrav 	int i;
199efcad6b7SDag-Erling Smørgrav 	const char *ptymajors = "pqrstuvwxyzabcdefghijklmno"
200efcad6b7SDag-Erling Smørgrav 	    "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
201efcad6b7SDag-Erling Smørgrav 	const char *ptyminors = "0123456789abcdef";
202efcad6b7SDag-Erling Smørgrav 	int num_minors = strlen(ptyminors);
203efcad6b7SDag-Erling Smørgrav 	int num_ptys = strlen(ptymajors) * num_minors;
204efcad6b7SDag-Erling Smørgrav 	struct termios tio;
205efcad6b7SDag-Erling Smørgrav 
206efcad6b7SDag-Erling Smørgrav 	for (i = 0; i < num_ptys; i++) {
207efcad6b7SDag-Erling Smørgrav 		snprintf(ptbuf, sizeof(ptbuf), "/dev/pty%c%c",
208efcad6b7SDag-Erling Smørgrav 		    ptymajors[i / num_minors], ptyminors[i % num_minors]);
209efcad6b7SDag-Erling Smørgrav 		snprintf(ttbuf, sizeof(ttbuf), "/dev/tty%c%c",
210efcad6b7SDag-Erling Smørgrav 		    ptymajors[i / num_minors], ptyminors[i % num_minors]);
211efcad6b7SDag-Erling Smørgrav 
212efcad6b7SDag-Erling Smørgrav 		if ((*amaster = open(ptbuf, O_RDWR | O_NOCTTY)) == -1) {
213efcad6b7SDag-Erling Smørgrav 			/* Try SCO style naming */
214efcad6b7SDag-Erling Smørgrav 			snprintf(ptbuf, sizeof(ptbuf), "/dev/ptyp%d", i);
215efcad6b7SDag-Erling Smørgrav 			snprintf(ttbuf, sizeof(ttbuf), "/dev/ttyp%d", i);
216efcad6b7SDag-Erling Smørgrav 			if ((*amaster = open(ptbuf, O_RDWR | O_NOCTTY)) == -1)
217efcad6b7SDag-Erling Smørgrav 				continue;
218efcad6b7SDag-Erling Smørgrav 		}
219efcad6b7SDag-Erling Smørgrav 
220efcad6b7SDag-Erling Smørgrav 		/* Open the slave side. */
221efcad6b7SDag-Erling Smørgrav 		if ((*aslave = open(ttbuf, O_RDWR | O_NOCTTY)) == -1) {
222efcad6b7SDag-Erling Smørgrav 			close(*amaster);
223efcad6b7SDag-Erling Smørgrav 			return (-1);
224efcad6b7SDag-Erling Smørgrav 		}
225efcad6b7SDag-Erling Smørgrav 		/* set tty modes to a sane state for broken clients */
226efcad6b7SDag-Erling Smørgrav 		if (tcgetattr(*amaster, &tio) != -1) {
227efcad6b7SDag-Erling Smørgrav 			tio.c_lflag |= (ECHO | ISIG | ICANON);
228efcad6b7SDag-Erling Smørgrav 			tio.c_oflag |= (OPOST | ONLCR);
229efcad6b7SDag-Erling Smørgrav 			tio.c_iflag |= ICRNL;
230efcad6b7SDag-Erling Smørgrav 			tcsetattr(*amaster, TCSANOW, &tio);
231efcad6b7SDag-Erling Smørgrav 		}
232efcad6b7SDag-Erling Smørgrav 
233efcad6b7SDag-Erling Smørgrav 		return (0);
234efcad6b7SDag-Erling Smørgrav 	}
235efcad6b7SDag-Erling Smørgrav 	return (-1);
236efcad6b7SDag-Erling Smørgrav #endif
237efcad6b7SDag-Erling Smørgrav }
238efcad6b7SDag-Erling Smørgrav 
239efcad6b7SDag-Erling Smørgrav #endif /* !defined(HAVE_OPENPTY) */
240efcad6b7SDag-Erling Smørgrav 
241