import of openssh-5.8p1
[openssh.git] / openbsd-compat / bsd-openpty.c
1 /*
2  * Please note: this implementation of openpty() is far from complete.
3  * it is just enough for portable OpenSSH's needs.
4  */
5
6 /*
7  * Copyright (c) 2004 Damien Miller <djm@mindrot.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21
22 /*
23  * Author: Tatu Ylonen <ylo@cs.hut.fi>
24  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
25  *                    All rights reserved
26  * Allocating a pseudo-terminal, and making it the controlling tty.
27  *
28  * As far as I am concerned, the code I have written for this software
29  * can be used freely for any purpose.  Any derived versions of this
30  * software must be clearly marked as such, and if the derived work is
31  * incompatible with the protocol description in the RFC file, it must be
32  * called by a name other than "ssh" or "Secure Shell".
33  */
34
35 #include "includes.h"
36 #if !defined(HAVE_OPENPTY)
37
38 #include <sys/types.h>
39
40 #include <stdlib.h>
41
42 #ifdef HAVE_SYS_STAT_H
43 # include <sys/stat.h>
44 #endif
45 #ifdef HAVE_SYS_IOCTL_H
46 # include <sys/ioctl.h>
47 #endif
48
49 #ifdef HAVE_FCNTL_H
50 # include <fcntl.h>
51 #endif
52
53 #ifdef HAVE_UTIL_H
54 # include <util.h>
55 #endif /* HAVE_UTIL_H */
56
57 #ifdef HAVE_PTY_H
58 # include <pty.h>
59 #endif
60 #if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
61 # include <sys/stropts.h>
62 #endif
63
64 #include <signal.h>
65 #include <string.h>
66 #include <unistd.h>
67
68 #ifndef O_NOCTTY
69 #define O_NOCTTY 0
70 #endif
71
72 int
73 openpty(int *amaster, int *aslave, char *name, struct termios *termp,
74    struct winsize *winp)
75 {
76 #if defined(HAVE__GETPTY)
77         /*
78          * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
79          * pty's automagically when needed
80          */
81         char *slave;
82
83         if ((slave = _getpty(amaster, O_RDWR, 0622, 0)) == NULL)
84                 return (-1);
85
86         /* Open the slave side. */
87         if ((*aslave = open(slave, O_RDWR | O_NOCTTY)) == -1) {
88                 close(*amaster);
89                 return (-1);
90         }
91         return (0);
92
93 #elif defined(HAVE_DEV_PTMX)
94         /*
95          * This code is used e.g. on Solaris 2.x.  (Note that Solaris 2.3
96          * also has bsd-style ptys, but they simply do not work.)
97          */
98         int ptm;
99         char *pts;
100         mysig_t old_signal;
101
102         if ((ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY)) == -1)
103                 return (-1);
104
105         /* XXX: need to close ptm on error? */
106         old_signal = signal(SIGCHLD, SIG_DFL);
107         if (grantpt(ptm) < 0)
108                 return (-1);
109         signal(SIGCHLD, old_signal);
110
111         if (unlockpt(ptm) < 0)
112                 return (-1);
113
114         if ((pts = ptsname(ptm)) == NULL)
115                 return (-1);
116         *amaster = ptm;
117
118         /* Open the slave side. */
119         if ((*aslave = open(pts, O_RDWR | O_NOCTTY)) == -1) {
120                 close(*amaster);
121                 return (-1);
122         }
123
124         /*
125          * Try to push the appropriate streams modules, as described 
126          * in Solaris pts(7).
127          */
128         ioctl(*aslave, I_PUSH, "ptem");
129         ioctl(*aslave, I_PUSH, "ldterm");
130 # ifndef __hpux
131         ioctl(*aslave, I_PUSH, "ttcompat");
132 # endif /* __hpux */
133
134         return (0);
135
136 #elif defined(HAVE_DEV_PTS_AND_PTC)
137         /* AIX-style pty code. */
138         const char *ttname;
139
140         if ((*amaster = open("/dev/ptc", O_RDWR | O_NOCTTY)) == -1)
141                 return (-1);
142         if ((ttname = ttyname(*amaster)) == NULL)
143                 return (-1);
144         if ((*aslave = open(ttname, O_RDWR | O_NOCTTY)) == -1) {
145                 close(*amaster);
146                 return (-1);
147         }
148         return (0);
149
150 #elif defined(_UNICOS)
151         char ptbuf[64], ttbuf[64];
152         int i;
153         int highpty;
154
155         highpty = 128;
156 #ifdef _SC_CRAY_NPTY
157         if ((highpty = sysconf(_SC_CRAY_NPTY)) == -1)
158                 highpty = 128;
159 #endif /* _SC_CRAY_NPTY */
160
161         for (i = 0; i < highpty; i++) {
162                 snprintf(ptbuf, sizeof(ptbuf), "/dev/pty/%03d", i);
163                 snprintf(ttbuf, sizeof(ttbuf), "/dev/ttyp%03d", i);
164                 if ((*amaster = open(ptbuf, O_RDWR|O_NOCTTY)) == -1)
165                         continue;
166                 /* Open the slave side. */
167                 if ((*aslave = open(ttbuf, O_RDWR|O_NOCTTY)) == -1) {
168                         close(*amaster);
169                         return (-1);
170                 }
171                 return (0);
172         }
173         return (-1);
174
175 #else
176         /* BSD-style pty code. */
177         char ptbuf[64], ttbuf[64];
178         int i;
179         const char *ptymajors = "pqrstuvwxyzabcdefghijklmno"
180             "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
181         const char *ptyminors = "0123456789abcdef";
182         int num_minors = strlen(ptyminors);
183         int num_ptys = strlen(ptymajors) * num_minors;
184         struct termios tio;
185
186         for (i = 0; i < num_ptys; i++) {
187                 snprintf(ptbuf, sizeof(ptbuf), "/dev/pty%c%c", 
188                     ptymajors[i / num_minors], ptyminors[i % num_minors]);
189                 snprintf(ttbuf, sizeof(ttbuf), "/dev/tty%c%c",
190                     ptymajors[i / num_minors], ptyminors[i % num_minors]);
191
192                 if ((*amaster = open(ptbuf, O_RDWR | O_NOCTTY)) == -1) {
193                         /* Try SCO style naming */
194                         snprintf(ptbuf, sizeof(ptbuf), "/dev/ptyp%d", i);
195                         snprintf(ttbuf, sizeof(ttbuf), "/dev/ttyp%d", i);
196                         if ((*amaster = open(ptbuf, O_RDWR | O_NOCTTY)) == -1)
197                                 continue;
198                 }
199
200                 /* Open the slave side. */
201                 if ((*aslave = open(ttbuf, O_RDWR | O_NOCTTY)) == -1) {
202                         close(*amaster);
203                         return (-1);
204                 }
205                 /* set tty modes to a sane state for broken clients */
206                 if (tcgetattr(*amaster, &tio) != -1) {
207                         tio.c_lflag |= (ECHO | ISIG | ICANON);
208                         tio.c_oflag |= (OPOST | ONLCR);
209                         tio.c_iflag |= ICRNL;
210                         tcsetattr(*amaster, TCSANOW, &tio);
211                 }
212
213                 return (0);
214         }
215         return (-1);
216 #endif
217 }
218
219 #endif /* !defined(HAVE_OPENPTY) */
220