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