146
|
1 /*****************************************************************************/
|
|
2 /* pty.c - general purpose routines */
|
|
3 /* Copyright (C) 1998-2003 Brian Masney <masneyb@gftp.org> */
|
|
4 /* */
|
|
5 /* This program is free software; you can redistribute it and/or modify */
|
|
6 /* it under the terms of the GNU General Public License as published by */
|
|
7 /* the Free Software Foundation; either version 2 of the License, or */
|
|
8 /* (at your option) any later version. */
|
|
9 /* */
|
|
10 /* This program is distributed in the hope that it will be useful, */
|
|
11 /* but WITHOUT ANY WARRANTY; without even the implied warranty of */
|
|
12 /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */
|
|
13 /* GNU General Public License for more details. */
|
|
14 /* */
|
|
15 /* You should have received a copy of the GNU General Public License */
|
|
16 /* along with this program; if not, write to the Free Software */
|
|
17 /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA */
|
|
18 /*****************************************************************************/
|
|
19
|
516
|
20 #include "gftp.h"
|
146
|
21 static const char cvsid[] = "$Id$";
|
|
22
|
179
|
23 #ifdef __sgi
|
146
|
24
|
179
|
25 char *
|
210
|
26 gftp_get_pty_impl (void)
|
179
|
27 {
|
|
28 return ("sgi");
|
|
29 }
|
|
30
|
146
|
31
|
210
|
32 static int
|
|
33 _gftp_ptym_open (char *pts_name, size_t len, int *fds)
|
146
|
34 {
|
210
|
35 char *new_pts_name;
|
|
36 int fdm;
|
146
|
37
|
210
|
38 if ((new_pts_name = _getpty (&fdm, O_RDWR, 0600, 0)) == NULL)
|
146
|
39 return (GFTP_ERETRYABLE);
|
|
40
|
210
|
41 strncpy (pts_name, new_pts_name, len);
|
249
|
42 pts_name[len - 1] = '\0';
|
210
|
43
|
|
44 return (fdm);
|
|
45 }
|
|
46
|
|
47
|
|
48 static int
|
|
49 _gftp_ptys_open (int fdm, int fds, char *pts_name)
|
|
50 {
|
|
51 int new_fds;
|
|
52
|
|
53 if ((new_fds = open (pts_name, O_RDWR)) < 0)
|
146
|
54 {
|
210
|
55 close (fdm);
|
|
56 return (-1);
|
146
|
57 }
|
|
58
|
210
|
59 return (new_fds);
|
146
|
60 }
|
|
61
|
178
|
62 #elif HAVE_GRANTPT
|
146
|
63
|
235
|
64 #include <stropts.h>
|
|
65
|
179
|
66 char *
|
210
|
67 gftp_get_pty_impl (void)
|
179
|
68 {
|
|
69 return ("unix98");
|
|
70 }
|
|
71
|
|
72
|
210
|
73 static int
|
|
74 _gftp_ptym_open (char *pts_name, size_t len, int *fds)
|
146
|
75 {
|
210
|
76 char *new_pts_name;
|
|
77 int fdm;
|
146
|
78
|
210
|
79 if ((fdm = open ("/dev/ptmx", O_RDWR)) < 0)
|
146
|
80 return (GFTP_ERETRYABLE);
|
|
81
|
210
|
82 if (grantpt (fdm) < 0)
|
146
|
83 {
|
210
|
84 close (fdm);
|
|
85 return (GFTP_ERETRYABLE);
|
|
86 }
|
|
87
|
|
88 if (unlockpt (fdm) < 0)
|
|
89 {
|
|
90 close (fdm);
|
146
|
91 return (GFTP_ERETRYABLE);
|
|
92 }
|
|
93
|
210
|
94 if ((new_pts_name = ptsname (fdm)) == NULL)
|
146
|
95 {
|
210
|
96 close (fdm);
|
146
|
97 return (GFTP_ERETRYABLE);
|
|
98 }
|
|
99
|
210
|
100 strncpy (pts_name, new_pts_name, len);
|
249
|
101 pts_name[len - 1] = '\0';
|
210
|
102
|
|
103 return (fdm);
|
|
104 }
|
|
105
|
|
106
|
|
107 static int
|
|
108 _gftp_ptys_open (int fdm, int fds, char *pts_name)
|
|
109 {
|
|
110 int new_fds;
|
|
111
|
|
112 if ((new_fds = open (pts_name, O_RDWR)) < 0)
|
146
|
113 {
|
210
|
114 close (fdm);
|
|
115 return (-1);
|
146
|
116 }
|
|
117
|
179
|
118 #ifdef SYSV
|
146
|
119 /* I intentionally ignore these errors */
|
210
|
120 ioctl (new_fds, I_PUSH, "ptem");
|
|
121 ioctl (new_fds, I_PUSH, "ldterm");
|
|
122 ioctl (new_fds, I_PUSH, "ttcompat");
|
179
|
123 #endif
|
146
|
124
|
210
|
125 return (new_fds);
|
146
|
126 }
|
|
127
|
515
|
128 #elif HAVE_OPENPTY
|
|
129
|
|
130 #ifdef HAVE_PTY_H
|
|
131 #include <pty.h>
|
|
132 #include <utmp.h> /* for login_tty */
|
|
133 #elif HAVE_LIBUTIL_H
|
|
134 #include <libutil.h>
|
|
135 #include <utmp.h> /* for login_tty */
|
|
136 #else
|
|
137 extern int openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize * winp);
|
|
138 extern int login_tty(int fd);
|
|
139 #endif
|
|
140
|
|
141 char *
|
|
142 gftp_get_pty_impl (void)
|
|
143 {
|
|
144 return ("openpty");
|
|
145 }
|
|
146
|
|
147
|
|
148 static int
|
|
149 _gftp_ptym_open (char *pts_name, size_t len, int *fds)
|
|
150 {
|
|
151 int fdm;
|
|
152
|
|
153 if (openpty (&fdm, fds, pts_name, NULL, NULL) < 0)
|
|
154 return (GFTP_ERETRYABLE);
|
|
155
|
|
156 ioctl (*fds, TIOCSCTTY, NULL);
|
|
157
|
|
158 return (fdm);
|
|
159 }
|
|
160
|
|
161
|
|
162 static int
|
|
163 _gftp_ptys_open (int fdm, int fds, char *pts_name)
|
|
164 {
|
|
165 if (login_tty (fds) < 0)
|
|
166 return (GFTP_EFATAL);
|
|
167
|
|
168 return (fds);
|
|
169 }
|
|
170
|
|
171 #else
|
146
|
172
|
|
173 /* Fall back to *BSD... */
|
|
174
|
179
|
175 char *
|
210
|
176 gftp_get_pty_impl (void)
|
179
|
177 {
|
|
178 return ("bsd");
|
|
179 }
|
|
180
|
|
181
|
210
|
182 static int
|
|
183 _gftp_ptym_open (char *pts_name, size_t len, int *fds)
|
146
|
184 {
|
210
|
185 char *pos1, *pos2;
|
|
186 int fdm;
|
146
|
187
|
210
|
188 g_return_val_if_fail (len >= 10, GFTP_EFATAL);
|
|
189
|
|
190 strncpy (pts_name, "/dev/ptyXY", len);
|
249
|
191 pts_name[len - 1] = '\0';
|
|
192
|
146
|
193 for (pos1 = "pqrstuvwxyzPQRST"; *pos1 != '\0'; pos1++)
|
|
194 {
|
|
195 pts_name[8] = *pos1;
|
|
196 for (pos2 = "0123456789abcdef"; *pos2 != '\0'; pos2++)
|
|
197 {
|
|
198 pts_name[9] = *pos2;
|
210
|
199 if ((fdm = open (pts_name, O_RDWR)) < 0)
|
146
|
200 continue;
|
|
201
|
|
202 pts_name[5] = 't';
|
|
203 chmod (pts_name, S_IRUSR | S_IWUSR);
|
|
204 chown (pts_name, getuid (), -1);
|
|
205
|
210
|
206 return (fdm);
|
146
|
207 }
|
|
208 }
|
|
209
|
|
210 return (GFTP_ERETRYABLE);
|
|
211 }
|
|
212
|
210
|
213
|
|
214 static int
|
|
215 _gftp_ptys_open (int fdm, int fds, char *pts_name)
|
|
216 {
|
|
217 int new_fds;
|
|
218
|
|
219 if ((new_fds = open (pts_name, O_RDWR)) < 0)
|
|
220 {
|
|
221 close (fdm);
|
|
222 return (-1);
|
|
223 }
|
|
224
|
|
225 #if defined(TIOCSCTTY) && !defined(CIBAUD)
|
|
226 ioctl (new_fds, TIOCSCTTY, NULL);
|
|
227 #endif
|
|
228
|
|
229 return (new_fds);
|
|
230 }
|
|
231
|
146
|
232 #endif /* __sgi */
|
|
233
|
|
234
|
210
|
235 static int
|
|
236 _gftp_tty_raw (int fd)
|
146
|
237 {
|
|
238 struct termios buf;
|
|
239
|
|
240 if (tcgetattr (fd, &buf) < 0)
|
|
241 return (-1);
|
|
242
|
|
243 buf.c_iflag |= IGNPAR;
|
|
244 buf.c_iflag &= ~(ICRNL | ISTRIP | IXON | IGNCR | IXANY | IXOFF | INLCR);
|
|
245 buf.c_lflag &= ~(ECHO | ICANON | ISIG | ECHOE | ECHOK | ECHONL);
|
|
246 #ifdef IEXTEN
|
|
247 buf.c_lflag &= ~(IEXTEN);
|
|
248 #endif
|
|
249
|
|
250 buf.c_oflag &= ~(OPOST);
|
|
251 buf.c_cc[VMIN] = 1;
|
|
252 buf.c_cc[VTIME] = 0;
|
|
253
|
|
254 if (tcsetattr (fd, TCSADRAIN, &buf) < 0)
|
|
255 return (-1);
|
|
256 return (0);
|
|
257 }
|
|
258
|
|
259
|
210
|
260 static void
|
458
|
261 _gftp_close_all_fds (int ptysfd)
|
210
|
262 {
|
|
263 int i, maxfds;
|
|
264
|
|
265 #ifdef HAVE_GETDTABLESIZE
|
|
266 maxfds = getdtablesize () - 1;
|
|
267 #elif defined (OPEN_MAX)
|
|
268 maxfds = OPEN_MAX;
|
|
269 #else
|
|
270 maxfds = -1;
|
|
271 #endif
|
|
272
|
|
273 for (i=3; i<maxfds; i++)
|
458
|
274 {
|
|
275 if (i == ptysfd)
|
|
276 continue;
|
|
277
|
|
278 close (i);
|
|
279 }
|
210
|
280 }
|
|
281
|
|
282
|
|
283 pid_t
|
458
|
284 gftp_exec (gftp_request * request, int *fdm, int *ptymfd, char **args)
|
210
|
285 {
|
458
|
286 char pts_name[64];
|
210
|
287 pid_t child;
|
458
|
288 int ptysfd;
|
210
|
289 int s[2];
|
|
290
|
458
|
291 *pts_name = '\0';
|
|
292 if ((*ptymfd = _gftp_ptym_open (pts_name, sizeof (pts_name), &ptysfd)) < 0)
|
|
293 {
|
|
294 request->logging_function (gftp_logging_error, request->user_data,
|
|
295 _("Cannot open master pty %s: %s\n"), pts_name,
|
|
296 g_strerror (errno));
|
|
297 return (-1);
|
|
298 }
|
|
299
|
210
|
300 if (socketpair (AF_LOCAL, SOCK_STREAM, 0, s) < 0)
|
|
301 {
|
|
302 request->logging_function (gftp_logging_error, request,
|
|
303 _("Cannot create a socket pair: %s\n"),
|
|
304 g_strerror (errno));
|
|
305 return (-1);
|
|
306 }
|
|
307
|
|
308 if ((child = fork ()) == 0)
|
|
309 {
|
|
310 setsid ();
|
|
311
|
458
|
312 if ((ptysfd = _gftp_ptys_open (*ptymfd, ptysfd, pts_name)) < 0)
|
|
313 {
|
|
314 printf ("Cannot open slave pts %s: %s\n", pts_name,
|
|
315 g_strerror (errno));
|
|
316 return (-1);
|
|
317 }
|
|
318
|
210
|
319 close (s[0]);
|
458
|
320 close (*ptymfd);
|
210
|
321
|
|
322 _gftp_tty_raw (s[1]);
|
458
|
323 _gftp_tty_raw (ptysfd);
|
|
324
|
210
|
325 dup2 (s[1], 0);
|
|
326 dup2 (s[1], 1);
|
541
|
327 dup2 (ptysfd, 2);
|
458
|
328 _gftp_close_all_fds (ptysfd);
|
210
|
329
|
|
330 execvp (args[0], args);
|
|
331
|
|
332 printf (_("Error: Cannot execute ssh: %s\n"), g_strerror (errno));
|
458
|
333 _exit (1);
|
210
|
334 }
|
|
335 else if (child > 0)
|
|
336 {
|
|
337 close (s[1]);
|
458
|
338
|
|
339 *fdm = s[0];
|
210
|
340 _gftp_tty_raw (s[0]);
|
458
|
341 _gftp_tty_raw (*ptymfd);
|
|
342
|
210
|
343 return (child);
|
|
344 }
|
|
345 else
|
|
346 {
|
|
347 request->logging_function (gftp_logging_error, request->user_data,
|
|
348 _("Cannot fork another process: %s\n"),
|
|
349 g_strerror (errno));
|
|
350 return (-1);
|
|
351 }
|
|
352 }
|
|
353
|