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
|
629
|
64 #ifndef __FreeBSD__
|
235
|
65 #include <stropts.h>
|
629
|
66 #endif
|
235
|
67
|
179
|
68 char *
|
210
|
69 gftp_get_pty_impl (void)
|
179
|
70 {
|
|
71 return ("unix98");
|
|
72 }
|
|
73
|
|
74
|
210
|
75 static int
|
|
76 _gftp_ptym_open (char *pts_name, size_t len, int *fds)
|
146
|
77 {
|
210
|
78 char *new_pts_name;
|
|
79 int fdm;
|
146
|
80
|
210
|
81 if ((fdm = open ("/dev/ptmx", O_RDWR)) < 0)
|
146
|
82 return (GFTP_ERETRYABLE);
|
|
83
|
210
|
84 if (grantpt (fdm) < 0)
|
146
|
85 {
|
210
|
86 close (fdm);
|
|
87 return (GFTP_ERETRYABLE);
|
|
88 }
|
|
89
|
|
90 if (unlockpt (fdm) < 0)
|
|
91 {
|
|
92 close (fdm);
|
146
|
93 return (GFTP_ERETRYABLE);
|
|
94 }
|
|
95
|
210
|
96 if ((new_pts_name = ptsname (fdm)) == NULL)
|
146
|
97 {
|
210
|
98 close (fdm);
|
146
|
99 return (GFTP_ERETRYABLE);
|
|
100 }
|
|
101
|
210
|
102 strncpy (pts_name, new_pts_name, len);
|
249
|
103 pts_name[len - 1] = '\0';
|
210
|
104
|
|
105 return (fdm);
|
|
106 }
|
|
107
|
|
108
|
|
109 static int
|
|
110 _gftp_ptys_open (int fdm, int fds, char *pts_name)
|
|
111 {
|
|
112 int new_fds;
|
|
113
|
|
114 if ((new_fds = open (pts_name, O_RDWR)) < 0)
|
146
|
115 {
|
210
|
116 close (fdm);
|
|
117 return (-1);
|
146
|
118 }
|
|
119
|
179
|
120 #ifdef SYSV
|
146
|
121 /* I intentionally ignore these errors */
|
210
|
122 ioctl (new_fds, I_PUSH, "ptem");
|
|
123 ioctl (new_fds, I_PUSH, "ldterm");
|
|
124 ioctl (new_fds, I_PUSH, "ttcompat");
|
179
|
125 #endif
|
146
|
126
|
210
|
127 return (new_fds);
|
146
|
128 }
|
|
129
|
515
|
130 #elif HAVE_OPENPTY
|
|
131
|
|
132 #ifdef HAVE_PTY_H
|
|
133 #include <pty.h>
|
|
134 #include <utmp.h> /* for login_tty */
|
|
135 #elif HAVE_LIBUTIL_H
|
|
136 #include <libutil.h>
|
|
137 #include <utmp.h> /* for login_tty */
|
|
138 #else
|
|
139 extern int openpty(int *amaster, int *aslave, char *name, struct termios *termp, struct winsize * winp);
|
|
140 extern int login_tty(int fd);
|
|
141 #endif
|
|
142
|
|
143 char *
|
|
144 gftp_get_pty_impl (void)
|
|
145 {
|
|
146 return ("openpty");
|
|
147 }
|
|
148
|
|
149
|
|
150 static int
|
|
151 _gftp_ptym_open (char *pts_name, size_t len, int *fds)
|
|
152 {
|
|
153 int fdm;
|
|
154
|
|
155 if (openpty (&fdm, fds, pts_name, NULL, NULL) < 0)
|
|
156 return (GFTP_ERETRYABLE);
|
|
157
|
|
158 ioctl (*fds, TIOCSCTTY, NULL);
|
|
159
|
|
160 return (fdm);
|
|
161 }
|
|
162
|
|
163
|
|
164 static int
|
|
165 _gftp_ptys_open (int fdm, int fds, char *pts_name)
|
|
166 {
|
|
167 if (login_tty (fds) < 0)
|
|
168 return (GFTP_EFATAL);
|
|
169
|
|
170 return (fds);
|
|
171 }
|
|
172
|
|
173 #else
|
146
|
174
|
|
175 /* Fall back to *BSD... */
|
|
176
|
179
|
177 char *
|
210
|
178 gftp_get_pty_impl (void)
|
179
|
179 {
|
|
180 return ("bsd");
|
|
181 }
|
|
182
|
|
183
|
210
|
184 static int
|
|
185 _gftp_ptym_open (char *pts_name, size_t len, int *fds)
|
146
|
186 {
|
210
|
187 char *pos1, *pos2;
|
|
188 int fdm;
|
146
|
189
|
210
|
190 g_return_val_if_fail (len >= 10, GFTP_EFATAL);
|
|
191
|
|
192 strncpy (pts_name, "/dev/ptyXY", len);
|
249
|
193 pts_name[len - 1] = '\0';
|
|
194
|
146
|
195 for (pos1 = "pqrstuvwxyzPQRST"; *pos1 != '\0'; pos1++)
|
|
196 {
|
|
197 pts_name[8] = *pos1;
|
|
198 for (pos2 = "0123456789abcdef"; *pos2 != '\0'; pos2++)
|
|
199 {
|
|
200 pts_name[9] = *pos2;
|
210
|
201 if ((fdm = open (pts_name, O_RDWR)) < 0)
|
146
|
202 continue;
|
|
203
|
|
204 pts_name[5] = 't';
|
|
205 chmod (pts_name, S_IRUSR | S_IWUSR);
|
|
206 chown (pts_name, getuid (), -1);
|
|
207
|
210
|
208 return (fdm);
|
146
|
209 }
|
|
210 }
|
|
211
|
|
212 return (GFTP_ERETRYABLE);
|
|
213 }
|
|
214
|
210
|
215
|
|
216 static int
|
|
217 _gftp_ptys_open (int fdm, int fds, char *pts_name)
|
|
218 {
|
|
219 int new_fds;
|
|
220
|
|
221 if ((new_fds = open (pts_name, O_RDWR)) < 0)
|
|
222 {
|
|
223 close (fdm);
|
|
224 return (-1);
|
|
225 }
|
|
226
|
|
227 #if defined(TIOCSCTTY) && !defined(CIBAUD)
|
|
228 ioctl (new_fds, TIOCSCTTY, NULL);
|
|
229 #endif
|
|
230
|
|
231 return (new_fds);
|
|
232 }
|
|
233
|
146
|
234 #endif /* __sgi */
|
|
235
|
|
236
|
210
|
237 static int
|
|
238 _gftp_tty_raw (int fd)
|
146
|
239 {
|
|
240 struct termios buf;
|
|
241
|
|
242 if (tcgetattr (fd, &buf) < 0)
|
|
243 return (-1);
|
|
244
|
|
245 buf.c_iflag |= IGNPAR;
|
|
246 buf.c_iflag &= ~(ICRNL | ISTRIP | IXON | IGNCR | IXANY | IXOFF | INLCR);
|
|
247 buf.c_lflag &= ~(ECHO | ICANON | ISIG | ECHOE | ECHOK | ECHONL);
|
|
248 #ifdef IEXTEN
|
|
249 buf.c_lflag &= ~(IEXTEN);
|
|
250 #endif
|
|
251
|
|
252 buf.c_oflag &= ~(OPOST);
|
|
253 buf.c_cc[VMIN] = 1;
|
|
254 buf.c_cc[VTIME] = 0;
|
|
255
|
|
256 if (tcsetattr (fd, TCSADRAIN, &buf) < 0)
|
|
257 return (-1);
|
|
258 return (0);
|
|
259 }
|
|
260
|
|
261
|
210
|
262 static void
|
458
|
263 _gftp_close_all_fds (int ptysfd)
|
210
|
264 {
|
|
265 int i, maxfds;
|
|
266
|
|
267 #ifdef HAVE_GETDTABLESIZE
|
|
268 maxfds = getdtablesize () - 1;
|
|
269 #elif defined (OPEN_MAX)
|
|
270 maxfds = OPEN_MAX;
|
|
271 #else
|
|
272 maxfds = -1;
|
|
273 #endif
|
|
274
|
|
275 for (i=3; i<maxfds; i++)
|
458
|
276 {
|
|
277 if (i == ptysfd)
|
|
278 continue;
|
|
279
|
|
280 close (i);
|
|
281 }
|
210
|
282 }
|
|
283
|
|
284
|
|
285 pid_t
|
458
|
286 gftp_exec (gftp_request * request, int *fdm, int *ptymfd, char **args)
|
210
|
287 {
|
458
|
288 char pts_name[64];
|
210
|
289 pid_t child;
|
458
|
290 int ptysfd;
|
210
|
291 int s[2];
|
|
292
|
458
|
293 *pts_name = '\0';
|
|
294 if ((*ptymfd = _gftp_ptym_open (pts_name, sizeof (pts_name), &ptysfd)) < 0)
|
|
295 {
|
|
296 request->logging_function (gftp_logging_error, request->user_data,
|
|
297 _("Cannot open master pty %s: %s\n"), pts_name,
|
|
298 g_strerror (errno));
|
|
299 return (-1);
|
|
300 }
|
|
301
|
210
|
302 if (socketpair (AF_LOCAL, SOCK_STREAM, 0, s) < 0)
|
|
303 {
|
|
304 request->logging_function (gftp_logging_error, request,
|
|
305 _("Cannot create a socket pair: %s\n"),
|
|
306 g_strerror (errno));
|
|
307 return (-1);
|
|
308 }
|
|
309
|
|
310 if ((child = fork ()) == 0)
|
|
311 {
|
|
312 setsid ();
|
|
313
|
458
|
314 if ((ptysfd = _gftp_ptys_open (*ptymfd, ptysfd, pts_name)) < 0)
|
|
315 {
|
|
316 printf ("Cannot open slave pts %s: %s\n", pts_name,
|
|
317 g_strerror (errno));
|
|
318 return (-1);
|
|
319 }
|
|
320
|
210
|
321 close (s[0]);
|
458
|
322 close (*ptymfd);
|
210
|
323
|
|
324 _gftp_tty_raw (s[1]);
|
458
|
325 _gftp_tty_raw (ptysfd);
|
|
326
|
210
|
327 dup2 (s[1], 0);
|
|
328 dup2 (s[1], 1);
|
541
|
329 dup2 (ptysfd, 2);
|
458
|
330 _gftp_close_all_fds (ptysfd);
|
210
|
331
|
|
332 execvp (args[0], args);
|
|
333
|
|
334 printf (_("Error: Cannot execute ssh: %s\n"), g_strerror (errno));
|
458
|
335 _exit (1);
|
210
|
336 }
|
|
337 else if (child > 0)
|
|
338 {
|
|
339 close (s[1]);
|
458
|
340
|
|
341 *fdm = s[0];
|
210
|
342 _gftp_tty_raw (s[0]);
|
458
|
343 _gftp_tty_raw (*ptymfd);
|
|
344
|
210
|
345 return (child);
|
|
346 }
|
|
347 else
|
|
348 {
|
|
349 request->logging_function (gftp_logging_error, request->user_data,
|
|
350 _("Cannot fork another process: %s\n"),
|
|
351 g_strerror (errno));
|
|
352 return (-1);
|
|
353 }
|
|
354 }
|
|
355
|