1 /*
2 ** openpty.c for zssh
3 **
4 ** Made by Matthieu Lucotte
5 ** Login <gounter@users.sourceforge.net>
6 **
7 ** Started on Thu Jun 29 19:10:25 2000 Matthieu Lucotte
8 ** Last update Wed Sep 24 00:05:06 2003
9 */
10
11 #include "zssh.h"
12
13 #define GL_SLAVENAMELEN 50
14 static char gl_slavename[GL_SLAVENAMELEN + 1] = {0};
15
16 #define NEEDED
17
18 /****************************************************************************/
19 #if defined(HAVE_OPENPTY) && defined(NEEDED)
20 /****************************************************************************/
21 #undef NEEDED
22 /* openpty exists in MacOS X */
23
24 #ifdef HAVE_UTIL_H
25 #include <util.h>
26 #endif
27
getmaster()28 void getmaster()
29 {
30 #ifdef DEBUG
31 printf("Using openpty() for tty allocation\n");
32 #endif
33 if (openpty(&gl_master, &gl_slave, gl_slavename, &gl_tt, &gl_win) < 0)
34 error(0,"openpty");
35 }
36
getslave()37 void getslave()
38 {
39 testslave(gl_slavename);
40 }
41
42 /****************************************************************************/
43 #endif /* HAVE_OPENPTY */
44 /****************************************************************************/
45
46
47 /****************************************************************************/
48 #if defined(HAVE__GETPTY) && defined(NEEDED)
49 /****************************************************************************/
50 #undef NEEDED
51 /* _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
52 pty's automagically when needed */
53
getmaster()54 void getmaster()
55 {
56 char *name;
57
58 #ifdef DEBUG
59 printf("Using _getpty() to allocate pty\n");
60 #endif
61 name = _getpty(&gl_master, O_RDWR, 0620, 0);
62 if (!name)
63 error(0, "_getpty");
64 strncpy(gl_slavename, name, GL_SLAVENAMELEN);
65 }
66
67 /* Open the slave side. */
getslave()68 void getslave()
69 {
70 #ifdef DEBUG
71 printf("Allocated tty: %s\n", gl_slavename);
72 #endif
73 if ((gl_slave = open(gl_slavename, O_RDWR | O_NOCTTY)) < 0)
74 error(0, "gl_slavename");
75
76 testslave(gl_slavename);
77
78 if (tcsetattr(gl_slave, TCSAFLUSH, &gl_tt) < 0)
79 error(0, "tcsetattr slave");
80 if (ioctl(gl_slave, TIOCSWINSZ, (char *)&gl_win) < 0)
81 error(0, "ioctl TIOCSWINSZ slave");
82 }
83
84 /****************************************************************************/
85 #endif /* HAVE__GETPTY */
86 /****************************************************************************/
87
88
89
90
91 /****************************************************************************/
92 #if defined(HAVE_DEV_PTMX) && defined(NEEDED)
93 /****************************************************************************/
94 #undef NEEDED
95
96 /* System V.4 pty routines from W. Richard Stevens */
97
98 #ifdef HAVE_STROPTS_H
99 #include <stropts.h>
100 #endif /* HAVE_STROPTS_H */
101 #define DEV_CLONE "/dev/ptmx"
102
103
getmaster()104 void getmaster()
105 {
106 char *ttyptr;
107
108 #ifdef DEBUG
109 printf("Using SYSTEM V style tty allocation routine\n");
110 #endif
111 #ifdef HAVE_GETPT
112 gl_master = getpt();
113 #else
114 gl_master = open(DEV_CLONE, O_RDWR);
115 #endif /* HAVE_GETPT */
116 if (gl_master < 0)
117 error(0, DEV_CLONE);
118 if (!(ttyptr = ptsname(gl_master)))
119 error(0, "ptsname");
120 strncpy(gl_slavename, ttyptr, GL_SLAVENAMELEN);
121 #ifdef HAVE_GRANTPT
122 call_grantpt();
123 #endif /* HAVE_GRANTPT */
124 #ifdef HAVE_UNLOCKPT
125 if ( unlockpt(gl_master) < 0 ) /* clear slave's lock flag */
126 error(0,"unlockpt");
127 #endif /* HAVE_UNLOCKPT */
128 }
129
130 /*
131 * Open the slave half of a pseudo-terminal.
132 */
getslave()133 void getslave()
134 {
135 if ( (gl_slave = open(gl_slavename, O_RDWR | O_NOCTTY)) < 0 ) /* open the slave */
136 error(0, "open slave");
137 #ifdef DEBUG
138 printf("Allocated tty: %s\n", gl_slavename);
139 #endif
140 testslave(gl_slavename);
141
142
143 #ifdef HAVE_ISASTREAM
144 if (isastream(gl_slave))
145 {
146 #ifdef DEBUG
147 printf("Now calling ioctls to push term emulation modules:\n");
148 printf(" ioctl I_PUSH ptem\n");
149 printf(" ioctl I_PUSH ldterm\n");
150 printf(" ioctl I_PUSH ttcompat\n");
151 #endif
152 if ( ioctl(gl_slave, I_PUSH, "ptem") < 0 )
153 error(0,"ioctl I_PUSH ptem");
154 if ( ioctl(gl_slave, I_PUSH, "ldterm") < 0 )
155 error(0,"ioctl I_PUSH ldterm");
156 /* Allow ttcompat to fail silently */
157 ioctl(gl_slave, I_PUSH, "ttcompat");
158 }
159 #endif /* HAVE_ISASTREAM */
160
161 if (tcsetattr(gl_slave, TCSAFLUSH, &gl_tt) < 0)
162 error(0, "tcsetattr slave");
163 if (ioctl(gl_slave, TIOCSWINSZ, (char *)&gl_win) < 0)
164 error(0, "ioctl TIOCSWINSZ slave");
165 }
166
167 /****************************************************************************/
168 #endif /* HAVE_DEV_PTMX */
169 /****************************************************************************/
170
171
172
173
174
175 /****************************************************************************/
176 #ifdef NEEDED
177 /****************************************************************************/
178
179 /* BSD style tty/pty allocation routines */
180
181 static char gl_line[] = "/dev/ptyXX";
182
getmaster()183 void getmaster()
184 {
185 char *pty, *bank, *cp;
186 struct stat stb;
187 int ok;
188
189 #ifdef DEBUG
190 printf("Using BSD style tty allocation routine\n");
191 #endif
192 pty = &gl_line[strlen("/dev/ptyp")];
193 for (bank = "pqrs"; *bank; bank++)
194 {
195 gl_line[strlen("/dev/pty")] = *bank;
196 *pty = '0';
197 if (stat(gl_line, &stb) < 0)
198 break;
199 for (cp = "0123456789abcdef"; *cp; cp++)
200 {
201 *pty = *cp;
202 gl_master = open(gl_line, O_RDWR);
203 if (gl_master >= 0)
204 {
205 strncpy(gl_slavename, gl_line, GL_SLAVENAMELEN);
206 gl_slavename[strlen("/dev/")] = 't';
207 #ifdef HAVE_GRANTPT
208 call_grantpt();
209 #endif /* HAVE_GRANTPT */
210 #ifdef HAVE_UNLOCKPT
211 if (unlockpt(gl_master) < 0)
212 error(0,"unlockpt");
213 #endif /* HAVE_UNLOCKPT */
214
215 /* verify slave side is usable */
216 ok = access(gl_slavename, R_OK | W_OK) == 0;
217 if (ok)
218 return;
219 close(gl_master);
220 }
221 }
222 }
223 error("out of pty's\n", "");
224 }
225
226
getslave()227 void getslave()
228 {
229 if ( (gl_slave = open(gl_slavename, O_RDWR | O_NOCTTY)) < 0)
230 error(0, gl_slavename);
231 #ifdef DEBUG
232 printf("Allocated tty: %s\n", gl_slavename);
233 #endif
234 testslave(gl_slavename);
235 if (tcsetattr(gl_slave, TCSAFLUSH, &gl_tt) < 0)
236 error(0, "tcsetattr slave");
237 if (ioctl(gl_slave, TIOCSWINSZ, (char *)&gl_win) < 0)
238 error(0, "ioctl TIOCSWINSZ slave");
239 }
240
241 /****************************************************************************/
242 #endif /* BSD style ptys */
243 /****************************************************************************/
244
my_tcsetpgrp(int fd,int pgrpid)245 void my_tcsetpgrp(int fd, int pgrpid)
246 {
247 int ret;
248
249 #ifdef HAVE_TCSETPGRP
250 ret = tcsetpgrp(fd, pgrpid);
251 #else
252 ret = ioctl(fd, TIOCSPGRP, &pgrpid);
253 #endif /* HAVE_TCSETPGRP */
254
255 if (ret < 0)
256 error(0, "my_tcsetpgrp");
257 }
258
259 /* set raw mode */
my_cfmakeraw(struct termios * pt)260 void my_cfmakeraw(struct termios *pt)
261 {
262 /* beginning of 'official' cfmakeraw function */
263 pt->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
264 |INLCR|IGNCR|ICRNL|IXON);
265 pt->c_oflag &= ~OPOST;
266 pt->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
267 pt->c_cflag &= ~(CSIZE|PARENB);
268 pt->c_cflag |= CS8;
269 /* end of 'official' cfmakeraw function */
270
271 pt->c_cc[VMIN] = 1;
272 pt->c_cc[VTIME] = 0;
273 /* pt->c_oflag |= OPOST; */
274 /* pt->c_lflag &= ~ECHO; */
275 }
276
277
278 /* called by getslave()
279 * test tty permissions and warn user if insecure
280 */
testslave(char * ttyname)281 void testslave(char *ttyname)
282 {
283 struct stat st;
284 struct passwd *pwd;
285 int ask = 0;
286
287 if (fstat(gl_slave, &st) < 0)
288 error(0, "fstat tty");
289 if (st.st_uid != getuid())
290 { /* tty is not owned by the user, this can be a security issue so prompt the user */
291 if ( (pwd = getpwuid(st.st_uid)) )
292 printf("*** %s: This tty is owned by someone else (%s) !\n", ttyname, pwd->pw_name);
293 else
294 printf("*** %s: This tty is owned by someone else (uid %lu) !\n", ttyname, (long) st.st_uid);
295 ask = 1;
296 }
297 if (st.st_mode & S_IWOTH)
298 /* tty is world writeable: this can be abused but there is no serious security issue here
299 * so just print a warning. */
300 printf("*** %s: this tty is world writeable !\n", ttyname);
301 if (st.st_mode & S_IROTH)
302 { /* tty is world readable: this is very insecure so prompt the user */
303 printf("*** %s: this tty is world readable !\n", ttyname);
304 ask = 1;
305 }
306 if (ask)
307 {
308 printf("*** This is a security issue\n");
309 if (!ask_user("Do you want to continue anyway ?", 0, 1))
310 error("aborting\n", "");
311 }
312 }
313
314
315 /* init slave after call to getslave
316 * make slave the controlling tty for current process
317 */
initslave()318 void initslave()
319 {
320 close(gl_master);
321 setsid();
322
323 /* by now we should have dropped the controlling tty
324 * make sure it is indeed the case
325 */
326 if (open("/dev/tty", O_RDWR) >= 0)
327 error("Couldn't drop controlling tty\n","");
328
329 #ifdef TIOCSCTTY
330 if (ioctl(gl_slave, TIOCSCTTY, 0) < 0)
331 perror("ioctl(slave, TIOCSCTTY, 0)");
332 #else /* re-open the tty so that it becomes the controlling tty */
333 close(gl_slave);
334 if ( (gl_slave = open(gl_slavename, O_RDWR)) < 0 )
335 error(0, gl_slavename);
336 #endif /* TIOCSCTTY */
337
338 if (dup2(gl_slave, 0) < 0)
339 error(0, "dup2(slave, 0)");
340 dup2(gl_slave, 1);
341 dup2(gl_slave, 2);
342 close(gl_slave);
343 }
344
345
346 #ifdef HAVE_GRANTPT
347 /* Call grantpt(). If it fails, prompt the user whether
348 * to continue anyway despite the security issue.
349 */
call_grantpt()350 void call_grantpt()
351 {
352 static int answered = 0;
353
354 /* SIGCHLD should NOT be handled at this point otherwise it
355 * may interfere with grantpt
356 */
357 signal(SIGCHLD, SIG_DFL);
358
359 if (grantpt(gl_master) < 0 && !answered)
360 {
361 perror("grantpt");
362 printf("*** Calling grantpt() failed. This can be a security issue\n"
363 "*** as another user may be able to spy on this session\n");
364 if (!ask_user("Do you want to continue anyway ?", 0, 1))
365 error("aborting\n", "");
366 answered = 1;
367 }
368 }
369 #endif /* HAVE_GRANTPT */
370
371