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