1
|
1 /*****************************************************************************/
|
|
2 /* ssh.c - functions that will use the ssh protocol */
|
|
3 /* Copyright (C) 1998-2002 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
|
|
20 /* This will use Brian Wellington <bwelling@xbill.org>'s sftpserv program */
|
|
21 /* on the remote. Some of this code is derived from the sftp client */
|
|
22
|
|
23 #include "gftp.h"
|
|
24
|
|
25 #define CHDIR 10
|
|
26 #define GETDIR 11
|
|
27 #define TELLDIR 12
|
|
28 #define SENDFILE 15
|
|
29 #define NOFILEMATCH 16
|
|
30 #define FILESIZE 20
|
|
31 #define FILEMODE 21
|
|
32 #define DATA 22
|
|
33 #define ENDDATA 23
|
|
34 #define FILEOK 24
|
|
35 #define STREAM 25
|
|
36 #define REQUEST 26
|
|
37 #define FILENAME 27
|
|
38 #define EXEC 28
|
|
39 #define SKIPBYTES 29
|
|
40 #define ERROR 30
|
|
41 #define SUCCESS 31
|
|
42 #define CLOSE 32
|
|
43 #define SSH_VERSION 33
|
|
44 #define CANCEL 34
|
|
45 #define FILETIME 40
|
|
46
|
|
47 typedef struct ssh_parms_tag
|
|
48 {
|
|
49 char *buffer, /* The buffer we are reading the data from */
|
|
50 *pos; /* Our position in this buffer */
|
|
51 int enddata; /* Are we done reading the data */
|
|
52 char channel; /* Data channel we are writing to */
|
|
53 } ssh_parms;
|
|
54
|
|
55
|
|
56 typedef struct ssh_message_tag
|
|
57 {
|
|
58 char channel,
|
|
59 command;
|
|
60 gint32 len;
|
|
61 void *data;
|
|
62 } ssh_message;
|
|
63
|
|
64
|
|
65 static void ssh_destroy ( gftp_request * request );
|
|
66 static int ssh_connect ( gftp_request * request );
|
|
67 static void ssh_disconnect ( gftp_request * request );
|
|
68 static long ssh_get_file ( gftp_request * request,
|
|
69 const char *filename,
|
|
70 FILE * fd,
|
|
71 off_t startsize );
|
|
72 static int ssh_put_file ( gftp_request * request,
|
|
73 const char *filename,
|
|
74 FILE * fd,
|
|
75 off_t startsize,
|
|
76 off_t totalsize );
|
|
77 static size_t ssh_get_next_file_chunk ( gftp_request * request,
|
|
78 char *buf,
|
|
79 size_t size );
|
|
80 static size_t ssh_put_next_file_chunk ( gftp_request * request,
|
|
81 char *buf,
|
|
82 size_t size );
|
|
83 static int ssh_end_transfer ( gftp_request * request );
|
|
84 static int ssh_list_files ( gftp_request * request );
|
|
85 static int ssh_get_next_file ( gftp_request * request,
|
|
86 gftp_file * fle,
|
|
87 FILE * fd );
|
|
88 static int ssh_chdir ( gftp_request * request,
|
|
89 const char *directory );
|
|
90 static char *ssh_exec ( gftp_request * request,
|
|
91 const char *command,
|
|
92 size_t len);
|
|
93 static int ssh_rmdir ( gftp_request * request,
|
|
94 const char *directory );
|
|
95 static int ssh_rmfile ( gftp_request * request,
|
|
96 const char *file );
|
|
97 static int ssh_mkdir ( gftp_request * request,
|
|
98 const char *newdir );
|
|
99 static int ssh_rename ( gftp_request * request,
|
|
100 const char *oldname,
|
|
101 const char *newname );
|
|
102 static int ssh_chmod ( gftp_request * request,
|
|
103 const char *file,
|
|
104 int mode );
|
|
105 static int ssh_send_command ( gftp_request * request,
|
|
106 int cmdnum,
|
|
107 const char *command,
|
|
108 size_t len );
|
|
109 static int ssh_read_response ( gftp_request * request,
|
|
110 ssh_message *message,
|
|
111 FILE * fd );
|
|
112 static char *ssh_read_message ( gftp_request * request,
|
|
113 char *buf,
|
|
114 size_t len,
|
|
115 FILE * fd );
|
|
116 static char *ssh_read_line ( gftp_request * request );
|
|
117 static void ssh_log_command ( gftp_request * request,
|
|
118 int channel,
|
|
119 int cmdnum,
|
|
120 const char *command,
|
|
121 size_t len,
|
|
122 int direction );
|
|
123 static size_t ssh_remove_spaces ( char *string );
|
|
124
|
|
125 void
|
|
126 ssh_init (gftp_request * request)
|
|
127 {
|
|
128 g_return_if_fail (request != NULL);
|
|
129
|
|
130 request->protonum = GFTP_SSH_NUM;
|
|
131 request->init = ssh_init;
|
|
132 request->destroy = ssh_destroy;
|
|
133 request->connect = ssh_connect;
|
|
134 request->disconnect = ssh_disconnect;
|
|
135 request->get_file = ssh_get_file;
|
|
136 request->put_file = ssh_put_file;
|
|
137 request->transfer_file = NULL;
|
|
138 request->get_next_file_chunk = ssh_get_next_file_chunk;
|
|
139 request->put_next_file_chunk = ssh_put_next_file_chunk;
|
|
140 request->end_transfer = ssh_end_transfer;
|
|
141 request->list_files = ssh_list_files;
|
|
142 request->get_next_file = ssh_get_next_file;
|
|
143 request->set_data_type = NULL;
|
|
144 request->get_file_size = NULL;
|
|
145 request->chdir = ssh_chdir;
|
|
146 request->rmdir = ssh_rmdir;
|
|
147 request->rmfile = ssh_rmfile;
|
|
148 request->mkdir = ssh_mkdir;
|
|
149 request->rename = ssh_rename;
|
|
150 request->chmod = ssh_chmod;
|
|
151 request->set_file_time = NULL;
|
|
152 request->site = NULL;
|
|
153 request->parse_url = NULL;
|
|
154 request->url_prefix = "ssh";
|
|
155 request->protocol_name = "SSH";
|
|
156 request->need_hostport = 1;
|
|
157 request->need_userpass = ssh_need_userpass;
|
|
158 request->use_cache = 1;
|
|
159 request->use_threads = 1;
|
|
160 request->always_connected = 0;
|
|
161 request->protocol_data = g_malloc0 (sizeof (ssh_parms));
|
|
162 gftp_set_config_options (request);
|
|
163 }
|
|
164
|
|
165
|
|
166 static void
|
|
167 ssh_destroy (gftp_request * request)
|
|
168 {
|
|
169 ssh_parms *params;
|
|
170
|
|
171 g_return_if_fail (request != NULL);
|
|
172 g_return_if_fail (request->protonum == GFTP_SSH_NUM);
|
|
173
|
|
174 params = request->protocol_data;
|
|
175 if (params->buffer)
|
|
176 {
|
|
177 g_free (params->buffer);
|
|
178 params->buffer = params->pos = NULL;
|
|
179 }
|
|
180 }
|
|
181
|
|
182
|
|
183 static int
|
|
184 ssh_connect (gftp_request * request)
|
|
185 {
|
|
186 char **args, *tempstr, pts_name[20], *p1, p2, *exepath, port[6];
|
|
187 int version, fdm, fds, s[2];
|
|
188 ssh_message message;
|
|
189 const gchar *errstr;
|
|
190 ssh_parms *params;
|
|
191 pid_t child;
|
|
192
|
|
193 g_return_val_if_fail (request != NULL, -2);
|
|
194 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
|
|
195 g_return_val_if_fail (request->hostname != NULL, -2);
|
|
196
|
|
197 params = request->protocol_data;
|
|
198 if (request->sockfd != NULL)
|
|
199 return (0);
|
|
200
|
|
201 request->logging_function (gftp_logging_misc, request->user_data,
|
|
202 _("Opening SSH connection to %s\n"),
|
|
203 request->hostname);
|
|
204
|
|
205 if (request->sftpserv_path == NULL ||
|
|
206 *request->sftpserv_path == '\0')
|
|
207 {
|
|
208 p1 = "";
|
|
209 p2 = ' ';
|
|
210 }
|
|
211 else
|
|
212 {
|
|
213 p1 = request->sftpserv_path;
|
|
214 p2 = '/';
|
|
215 }
|
|
216
|
|
217 *port = '\0';
|
|
218 exepath = g_strdup_printf ("%s%csftpserv", p1, p2);
|
|
219 args = make_ssh_exec_args (request, exepath, 0, port);
|
|
220
|
|
221 if (ssh_use_askpass)
|
|
222 {
|
|
223 fdm = fds = 0;
|
|
224 if (socketpair (AF_LOCAL, SOCK_STREAM, 0, s) < 0)
|
|
225 {
|
|
226 request->logging_function (gftp_logging_error, request->user_data,
|
|
227 _("Cannot create a socket pair: %s\n"),
|
|
228 g_strerror (errno));
|
|
229 return (-2);
|
|
230 }
|
|
231 }
|
|
232 else
|
|
233 {
|
|
234 s[0] = s[1] = 0;
|
|
235 if ((fdm = ptym_open (pts_name)) < 0)
|
|
236 {
|
|
237 request->logging_function (gftp_logging_error, request->user_data,
|
|
238 _("Cannot open master pty %s: %s\n"), pts_name,
|
|
239 g_strerror (errno));
|
|
240 return (-2);
|
|
241 }
|
|
242 }
|
|
243
|
|
244 if ((child = fork ()) == 0)
|
|
245 {
|
|
246 setsid ();
|
|
247 if (ssh_use_askpass)
|
|
248 {
|
|
249 close (s[0]);
|
|
250 fds = s[1];
|
|
251 }
|
|
252 else
|
|
253 {
|
|
254 if ((fds = ptys_open (fdm, pts_name)) < 0)
|
|
255 {
|
|
256 printf ("Cannot open slave pts %s: %s\n", pts_name,
|
|
257 g_strerror (errno));
|
|
258 return (-1);
|
|
259 }
|
|
260 close (fdm);
|
|
261 }
|
|
262
|
|
263 dup2 (fds, 0);
|
|
264 dup2 (fds, 1);
|
|
265 dup2 (fds, 2);
|
|
266 if (!ssh_use_askpass && fds > 2)
|
|
267 close (fds);
|
|
268 execvp (ssh_prog_name != NULL && *ssh_prog_name != '\0' ?
|
|
269 ssh_prog_name : "ssh", args);
|
|
270
|
|
271 tempstr = _("Error: Cannot execute ssh: ");
|
|
272 write (1, tempstr, strlen (tempstr));
|
|
273 errstr = g_strerror (errno);
|
|
274 write (1, errstr, strlen (errstr));
|
|
275 write (1, "\n", 1);
|
|
276 return (-1);
|
|
277 }
|
|
278 else if (child > 0)
|
|
279 {
|
|
280 if (ssh_use_askpass)
|
|
281 {
|
|
282 close (s[1]);
|
|
283 fdm = s[0];
|
|
284 }
|
|
285 tty_raw (fdm);
|
|
286 tempstr = ssh_start_login_sequence (request, fdm);
|
|
287 if (!tempstr ||
|
|
288 !(strlen (tempstr) > 4 && strcmp (tempstr + strlen (tempstr) - 5,
|
|
289 "xsftp") == 0))
|
|
290 {
|
|
291 request->logging_function (gftp_logging_error, request->user_data,
|
|
292 _("Error: Received wrong init string from server\n"));
|
|
293 g_free (args);
|
|
294 g_free (exepath);
|
|
295 return (-2);
|
|
296 }
|
|
297 g_free (args);
|
|
298 g_free (exepath);
|
|
299 g_free (tempstr);
|
|
300
|
|
301 request->sockfd = request->datafd = fdopen (fdm, "rb");
|
|
302 request->sockfd_write = fdopen (fdm, "wb");
|
|
303
|
|
304 params->channel = 0;
|
|
305 version = htonl (7 << 4);
|
|
306 if (ssh_send_command (request, SSH_VERSION, (char *) &version, 4) < 0)
|
|
307 return (-2);
|
|
308 if (ssh_read_response (request, &message, NULL) != SSH_VERSION)
|
|
309 return (-2);
|
|
310 g_free (message.data);
|
|
311
|
|
312 request->logging_function (gftp_logging_misc, request->user_data,
|
|
313 _("Successfully logged into SSH server %s\n"),
|
|
314 request->hostname);
|
|
315 }
|
|
316 else
|
|
317 {
|
|
318 request->logging_function (gftp_logging_error, request->user_data,
|
|
319 _("Cannot fork another process: %s\n"),
|
|
320 g_strerror (errno));
|
|
321 g_free (args);
|
|
322 return (-1);
|
|
323 }
|
|
324
|
|
325 ssh_chdir (request, request->directory);
|
|
326
|
|
327 if (ssh_send_command (request, GETDIR, NULL, 0) < 0)
|
|
328 return (-1);
|
|
329
|
|
330 if (ssh_read_response (request, &message, NULL) != TELLDIR)
|
|
331 {
|
|
332 request->logging_function (gftp_logging_error, request->user_data,
|
|
333 _("Could not get current working directory: %s\n"),
|
|
334 (char *) message.data);
|
|
335 g_free (message.data);
|
|
336 return (-1);
|
|
337 }
|
|
338
|
|
339 if (request->directory)
|
|
340 g_free (request->directory);
|
|
341 request->directory = message.data;
|
|
342
|
|
343 if (request->sockfd == NULL)
|
|
344 return (-2);
|
|
345
|
|
346 return (0);
|
|
347 }
|
|
348
|
|
349
|
|
350 static void
|
|
351 ssh_disconnect (gftp_request * request)
|
|
352 {
|
|
353 g_return_if_fail (request != NULL);
|
|
354 g_return_if_fail (request->protonum == GFTP_SSH_NUM);
|
|
355
|
|
356 if (request->sockfd != NULL)
|
|
357 {
|
|
358 request->logging_function (gftp_logging_misc, request->user_data,
|
|
359 _("Disconnecting from site %s\n"),
|
|
360 request->hostname);
|
|
361 fclose (request->sockfd);
|
|
362 request->sockfd = request->datafd = request->sockfd_write = NULL;
|
|
363 }
|
|
364 }
|
|
365
|
|
366
|
|
367 static long
|
|
368 ssh_get_file (gftp_request * request, const char *filename, FILE * fd,
|
|
369 off_t startsize)
|
|
370 {
|
|
371 ssh_message message;
|
|
372 ssh_parms *params;
|
|
373 off_t retsize;
|
|
374 int ret;
|
|
375
|
|
376 g_return_val_if_fail (request != NULL, -2);
|
|
377 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
|
|
378 g_return_val_if_fail (filename != NULL, -2);
|
|
379 /* fd ignored for this protocol */
|
|
380
|
|
381 params = request->protocol_data;
|
|
382 params->channel = 0;
|
|
383 if (ssh_send_command (request, REQUEST, filename, strlen (filename) + 1) < 0)
|
|
384 return (-1);
|
|
385
|
|
386 retsize = 0;
|
|
387 while (1)
|
|
388 {
|
|
389 ret = ssh_read_response (request, &message, NULL);
|
|
390 switch (ret)
|
|
391 {
|
|
392 case FILESIZE:
|
|
393 retsize = strtol ((char *) message.data, NULL, 10);
|
|
394 break;
|
|
395 case NOFILEMATCH:
|
|
396 request->logging_function (gftp_logging_misc, request->user_data,
|
|
397 _("Remote host could not find file %s\n"),
|
|
398 filename);
|
|
399 g_free (message.data);
|
|
400 return (-1);
|
|
401 case FILENAME:
|
|
402 params->channel = message.channel;
|
|
403 startsize = htonl (startsize);
|
|
404 if (ssh_send_command (request, SKIPBYTES, (char *) &startsize, 4) < 0)
|
|
405 {
|
|
406 g_free (message.data);
|
|
407 return (-1);
|
|
408 }
|
|
409 break;
|
|
410 case -1:
|
|
411 g_free (message.data);
|
|
412 return (-2);
|
|
413 }
|
|
414
|
|
415 g_free (message.data);
|
|
416 if (ret == FILETIME)
|
|
417 break;
|
|
418 }
|
|
419
|
|
420 return (retsize);
|
|
421 }
|
|
422
|
|
423
|
|
424 static int
|
|
425 ssh_put_file (gftp_request * request, const char *filename, FILE * fd,
|
|
426 off_t startsize, off_t totalsize)
|
|
427 {
|
|
428 ssh_message message;
|
|
429 ssh_parms *params;
|
|
430 char tempchar;
|
|
431
|
|
432 g_return_val_if_fail (request != NULL, -2);
|
|
433 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
|
|
434 g_return_val_if_fail (filename != NULL, -2);
|
|
435 /* fd ignored for this protocol */
|
|
436
|
|
437 params = request->protocol_data;
|
|
438 params->channel = 0;
|
|
439 tempchar = 1;
|
|
440 if (ssh_send_command (request, SENDFILE, &tempchar, 1) < 0)
|
|
441 return (-1);
|
|
442
|
|
443 params->channel = tempchar;
|
|
444 if (ssh_send_command (request, FILENAME, filename, strlen (filename) + 1) < 0)
|
|
445 return (-1);
|
|
446
|
|
447 if (ssh_read_response (request, &message, NULL) < 0)
|
|
448 {
|
|
449 g_free (message.data);
|
|
450 return (-1);
|
|
451 }
|
|
452
|
|
453 if (!(message.command == FILEOK && message.len == 1
|
|
454 && *(char *) message.data != 0))
|
|
455 {
|
|
456 g_free (message.data);
|
|
457 return (-1);
|
|
458 }
|
|
459 g_free (message.data);
|
|
460
|
|
461 if (ssh_send_command (request, FILESIZE, (void *) &totalsize, 4) < 0)
|
|
462 return (-1);
|
|
463
|
|
464 if (ssh_send_command (request, FILEMODE, "rw-r--r--", 9) < 0)
|
|
465 return (-1);
|
|
466
|
|
467 if (ssh_send_command (request, FILETIME, (char *) 0, 4) < 0)
|
|
468 return (-1);
|
|
469
|
|
470 if (startsize > 0)
|
|
471 {
|
|
472 startsize = htonl (startsize);
|
|
473 /* FIXME - warning on IRIX - pointer from integer of different size */
|
|
474 if (ssh_send_command (request, SKIPBYTES, GUINT_TO_POINTER (startsize), 4) < 0)
|
|
475 return (-1);
|
|
476 }
|
|
477
|
|
478 return (0);
|
|
479 }
|
|
480
|
|
481
|
|
482 static size_t
|
|
483 ssh_get_next_file_chunk (gftp_request * request, char *buf, size_t size)
|
|
484 {
|
|
485 ssh_message message;
|
|
486 size_t len;
|
|
487
|
|
488 switch (ssh_read_response (request, &message, NULL))
|
|
489 {
|
|
490 case DATA:
|
|
491 len = size > message.len ? message.len : size;
|
|
492 memcpy (buf, message.data, len);
|
|
493 g_free (message.data);
|
|
494 return (len);
|
|
495 case ENDDATA:
|
|
496 g_free (message.data);
|
|
497 if (ssh_read_response (request, &message, NULL) < 0)
|
|
498 {
|
|
499 g_free (message.data);
|
|
500 return (-1);
|
|
501 }
|
|
502 g_free (message.data);
|
|
503 return (0);
|
|
504 case -1:
|
|
505 g_free (message.data);
|
|
506 return (-1);
|
|
507 default:
|
|
508 g_free (message.data);
|
|
509 request->logging_function (gftp_logging_misc, request->user_data,
|
|
510 _("Received unexpected response from server\n"));
|
|
511 gftp_disconnect (request);
|
|
512 return (0);
|
|
513 }
|
|
514 }
|
|
515
|
|
516
|
|
517 static size_t
|
|
518 ssh_put_next_file_chunk (gftp_request * request, char *buf, size_t size)
|
|
519 {
|
|
520 if (size == 0)
|
|
521 {
|
|
522 if (ssh_send_command (request, ENDDATA, NULL, 0) < 0)
|
|
523 return (-2);
|
|
524 if (ssh_send_command (request, NOFILEMATCH, NULL, 0) < 0)
|
|
525 return (-2);
|
|
526 return (0);
|
|
527 }
|
|
528 return (ssh_send_command (request, DATA, buf, size) == 0 ? size : 0);
|
|
529 }
|
|
530
|
|
531
|
|
532 static int
|
|
533 ssh_end_transfer (gftp_request * request)
|
|
534 {
|
|
535 ssh_parms *params;
|
|
536
|
|
537 g_return_val_if_fail (request != NULL, -2);
|
|
538 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
|
|
539 g_return_val_if_fail (request->datafd != NULL, -2);
|
|
540
|
|
541 params = request->protocol_data;
|
|
542 if (params->buffer)
|
|
543 g_free (params->buffer);
|
|
544 params->buffer = params->pos = NULL;
|
|
545 params->enddata = 0;
|
|
546
|
|
547 return (0);
|
|
548 }
|
|
549
|
|
550
|
|
551 static int
|
|
552 ssh_list_files (gftp_request * request)
|
|
553 {
|
|
554 ssh_message message;
|
|
555 ssh_parms *params;
|
|
556 char *tempstr;
|
|
557 size_t len;
|
|
558
|
|
559 g_return_val_if_fail (request != NULL, -2);
|
|
560 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
|
|
561
|
|
562 params = request->protocol_data;
|
|
563 params->enddata = 0;
|
|
564 params->channel = 0;
|
|
565 request->logging_function (gftp_logging_misc, request->user_data,
|
|
566 _("Retrieving directory listing...\n"));
|
|
567
|
|
568 tempstr = g_strconcat ("/bin/ls -al", NULL);
|
|
569 len = ssh_remove_spaces (tempstr);
|
|
570
|
|
571 if (ssh_send_command (request, EXEC, tempstr, len) < 0)
|
|
572 {
|
|
573 g_free (tempstr);
|
|
574 return (-1);
|
|
575 }
|
|
576 g_free (tempstr);
|
|
577
|
|
578 if (ssh_read_response (request, &message, NULL) != STREAM)
|
|
579 {
|
|
580 g_free (message.data);
|
|
581 request->logging_function (gftp_logging_misc, request->user_data,
|
|
582 _("Received unexpected response from server\n"));
|
|
583 gftp_disconnect (request);
|
|
584 return (-2);
|
|
585 }
|
|
586 g_free (message.data);
|
|
587
|
|
588 return (0);
|
|
589 }
|
|
590
|
|
591
|
|
592 static int
|
|
593 ssh_get_next_file (gftp_request * request, gftp_file * fle, FILE * fd)
|
|
594 {
|
|
595 char *tempstr, *pos;
|
|
596 ssh_message message;
|
|
597 ssh_parms *params;
|
|
598 int ret, len;
|
|
599
|
|
600 g_return_val_if_fail (request != NULL, -2);
|
|
601 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
|
|
602 g_return_val_if_fail (fle != NULL, -2);
|
|
603
|
|
604 params = request->protocol_data;
|
|
605 if (request->last_dir_entry)
|
|
606 {
|
|
607 g_free (request->last_dir_entry);
|
|
608 request->last_dir_entry = NULL;
|
|
609 request->last_dir_entry_len = 0;
|
|
610 }
|
|
611
|
|
612 len = 0;
|
|
613 while (1)
|
|
614 {
|
|
615 if (params->enddata && params->buffer == NULL)
|
|
616 {
|
|
617 request->logging_function (gftp_logging_misc, request->user_data,
|
|
618 _("Finished retrieving directory listing\n"));
|
|
619 params->enddata = 0;
|
|
620 return (0);
|
|
621 }
|
|
622
|
|
623 if (!params->enddata &&
|
|
624 (!params->pos || strchr (params->pos, '\n') == NULL))
|
|
625 {
|
|
626 if ((ret = ssh_read_response (request, &message, fd)) < 0)
|
|
627 {
|
|
628 if (message.data)
|
|
629 g_free (message.data);
|
|
630 return (-2);
|
|
631 }
|
|
632
|
|
633 if (!request->cached)
|
|
634 {
|
|
635 request->last_dir_entry_len = message.len + 6;
|
|
636 request->last_dir_entry = g_malloc (request->last_dir_entry_len + 1);
|
|
637 request->last_dir_entry[0] = message.channel;
|
|
638 request->last_dir_entry[1] = message.command;
|
|
639 len = htonl (message.len);
|
|
640 memcpy (&request->last_dir_entry[2], &len, 4);
|
|
641 memcpy (&request->last_dir_entry[6], message.data, message.len);
|
|
642 }
|
|
643
|
|
644 if (ret == DATA)
|
|
645 {
|
|
646 if (params->pos == NULL || *params->pos == '\0')
|
|
647 {
|
|
648 if (params->buffer)
|
|
649 g_free (params->buffer);
|
|
650 params->buffer = params->pos = message.data;
|
|
651 }
|
|
652 else
|
|
653 {
|
|
654 tempstr = params->buffer;
|
|
655 params->buffer = g_malloc (strlen (params->pos) +
|
|
656 strlen ((char *) message.data) + 1);
|
|
657 strcpy (params->buffer, params->pos);
|
|
658 strcat (params->buffer, (char *) message.data);
|
|
659 g_free (tempstr);
|
|
660 g_free (message.data);
|
|
661 params->pos = params->buffer;
|
|
662 }
|
|
663 }
|
|
664 else
|
|
665 g_free (message.data);
|
|
666 }
|
|
667 else
|
|
668 ret = DATA;
|
|
669
|
|
670 switch (ret)
|
|
671 {
|
|
672 case DATA:
|
|
673 if ((tempstr = ssh_read_line (request)) == NULL)
|
|
674 continue;
|
|
675 pos = tempstr;
|
|
676 while (*pos == ' ' || *pos == '\t')
|
|
677 pos++;
|
|
678 if (*pos == '\0')
|
|
679 {
|
|
680 g_free (tempstr);
|
|
681 break;
|
|
682 }
|
|
683
|
|
684 if (gftp_parse_ls (tempstr, fle) != 0)
|
|
685 {
|
|
686 if (strncmp (tempstr, "total", strlen ("total")) &&
|
|
687 strncmp (tempstr, _("total"), strlen (_("total"))))
|
|
688 request->logging_function (gftp_logging_misc,
|
|
689 request->user_data,
|
|
690 _("Warning: Cannot parse listing %s\n"),
|
|
691 tempstr);
|
|
692 gftp_file_destroy (fle);
|
|
693 g_free (tempstr);
|
|
694 tempstr = NULL;
|
|
695 continue;
|
|
696 }
|
|
697 len = strlen (tempstr);
|
|
698 g_free (tempstr);
|
|
699 break;
|
|
700 case ENDDATA:
|
|
701 params->enddata = 1;
|
|
702 break;
|
|
703 default:
|
|
704 request->logging_function (gftp_logging_misc, request->user_data,
|
|
705 _("Received unexpected response from server\n"));
|
|
706 gftp_disconnect (request);
|
|
707 return (-2);
|
|
708 }
|
|
709
|
|
710 if (ret == DATA)
|
|
711 break;
|
|
712 }
|
|
713
|
|
714 return (len);
|
|
715 }
|
|
716
|
|
717
|
|
718 static int
|
|
719 ssh_chdir (gftp_request * request, const char *directory)
|
|
720 {
|
|
721 ssh_message message;
|
|
722 int ret;
|
|
723
|
|
724 g_return_val_if_fail (request != NULL, -2);
|
|
725 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
|
|
726
|
|
727 if (directory != NULL && *directory != '\0')
|
|
728 {
|
|
729 if (ssh_send_command (request, CHDIR, directory,
|
|
730 strlen (directory) + 1) < 0)
|
|
731 return (-1);
|
|
732
|
|
733 if ((ret = ssh_read_response (request, &message, NULL)) != SUCCESS)
|
|
734 {
|
|
735 request->logging_function (gftp_logging_error, request->user_data,
|
|
736 _("Could not change remote directory to %s: %s\n"),
|
|
737 directory, (char *) message.data);
|
|
738 g_free (message.data);
|
|
739 return (-1);
|
|
740 }
|
|
741 g_free (message.data);
|
|
742 }
|
|
743
|
|
744 if (directory != request->directory)
|
|
745 {
|
|
746 if (ssh_send_command (request, GETDIR, NULL, 0) < 0)
|
|
747 return (-1);
|
|
748
|
|
749 if (ssh_read_response (request, &message, NULL) != TELLDIR)
|
|
750 {
|
|
751 request->logging_function (gftp_logging_error, request->user_data,
|
|
752 _("Could not get current working directory: %s\n"),
|
|
753 (char *) message.data);
|
|
754 g_free (message.data);
|
|
755 return (-1);
|
|
756 }
|
|
757
|
|
758 if (request->directory)
|
|
759 g_free (request->directory);
|
|
760 request->directory = message.data;
|
|
761 }
|
|
762
|
|
763 return (0);
|
|
764 }
|
|
765
|
|
766
|
|
767 static char *
|
|
768 ssh_exec (gftp_request * request, const char *command, size_t len)
|
|
769 {
|
|
770 ssh_message message;
|
|
771 char *err, *pos;
|
|
772 int ret;
|
|
773
|
|
774 g_return_val_if_fail (request != NULL, NULL);
|
|
775 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, NULL);
|
|
776 g_return_val_if_fail (command != NULL, NULL);
|
|
777
|
|
778 err = NULL;
|
|
779 if (ssh_send_command (request, EXEC, command, len) < 0)
|
|
780 return (NULL);
|
|
781
|
|
782 while (1)
|
|
783 {
|
|
784 ret = ssh_read_response (request, &message, NULL);
|
|
785 switch (ret)
|
|
786 {
|
|
787 case -1:
|
|
788 g_free (message.data);
|
|
789 gftp_disconnect (request);
|
|
790 return (message.data);
|
|
791 case DATA:
|
|
792 case ERROR:
|
|
793 pos = (char *) message.data+message.len-1;
|
|
794 if (*pos == '\n')
|
|
795 *pos = '\0';
|
|
796
|
|
797 if (err != NULL)
|
|
798 {
|
|
799 err = g_realloc (err, strlen (message.data) + strlen (err) + 1);
|
|
800 strcat (err, message.data);
|
|
801 }
|
|
802 else
|
|
803 {
|
|
804 err = g_malloc (strlen (message.data) + 1);
|
|
805 strcpy (err, message.data);
|
|
806 }
|
|
807 if (ret == ERROR)
|
|
808 {
|
|
809 g_free (message.data);
|
|
810 return (err);
|
|
811 }
|
|
812 break;
|
|
813 case SUCCESS:
|
|
814 g_free (message.data);
|
|
815 return (err);
|
|
816 case STREAM:
|
|
817 break;
|
|
818 case ENDDATA:
|
|
819 g_free (message.data);
|
|
820 return (err);
|
|
821 }
|
|
822 g_free (message.data);
|
|
823 }
|
|
824 }
|
|
825
|
|
826
|
|
827 static int
|
|
828 ssh_rmdir (gftp_request * request, const char *directory)
|
|
829 {
|
|
830 char *tempstr, *pos, *ret;
|
|
831 size_t len;
|
|
832
|
|
833 g_return_val_if_fail (request != NULL, -2);
|
|
834 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
|
|
835 g_return_val_if_fail (directory != NULL, -2);
|
|
836
|
|
837 tempstr = g_strconcat ("/bin/rmdir ", directory, NULL);
|
|
838 len = strlen (tempstr);
|
|
839 pos = tempstr;
|
|
840 while ((pos = strchr (pos, ' ')) != NULL)
|
|
841 *pos++ = '\0';
|
|
842 if ((ret = ssh_exec (request, tempstr, len)) != NULL)
|
|
843 {
|
|
844 request->logging_function (gftp_logging_error, request->user_data,
|
|
845 _("Error: Could not remove directory %s: %s\n"),
|
|
846 directory, ret);
|
|
847 g_free (tempstr);
|
|
848 g_free (ret);
|
|
849 return (-2);
|
|
850 }
|
|
851 else
|
|
852 request->logging_function (gftp_logging_misc, request->user_data,
|
|
853 _("Successfully removed %s\n"), directory);
|
|
854 g_free (tempstr);
|
|
855 return (0);
|
|
856 }
|
|
857
|
|
858
|
|
859 static int
|
|
860 ssh_rmfile (gftp_request * request, const char *file)
|
|
861 {
|
|
862 char *tempstr, *pos, *ret;
|
|
863 size_t len;
|
|
864
|
|
865 g_return_val_if_fail (request != NULL, -2);
|
|
866 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
|
|
867 g_return_val_if_fail (file != NULL, -2);
|
|
868
|
|
869 tempstr = g_strconcat ("/bin/rm -f ", file, NULL);
|
|
870 len = strlen (tempstr);
|
|
871 pos = tempstr;
|
|
872 while ((pos = strchr (pos, ' ')) != NULL)
|
|
873 *pos++ = '\0';
|
|
874 if ((ret = ssh_exec (request, tempstr, len)) != NULL)
|
|
875 {
|
|
876 request->logging_function (gftp_logging_error, request->user_data,
|
|
877 _("Error: Could not remove file %s: %s\n"),
|
|
878 file, ret);
|
|
879 g_free (tempstr);
|
|
880 g_free (ret);
|
|
881 return (-2);
|
|
882 }
|
|
883 else
|
|
884 request->logging_function (gftp_logging_misc, request->user_data,
|
|
885 _("Successfully removed %s\n"), file);
|
|
886 g_free (tempstr);
|
|
887 return (0);
|
|
888 }
|
|
889
|
|
890
|
|
891 static int
|
|
892 ssh_mkdir (gftp_request * request, const char *newdir)
|
|
893 {
|
|
894 char *tempstr, *pos, *ret;
|
|
895 size_t len;
|
|
896
|
|
897 g_return_val_if_fail (request != NULL, -2);
|
|
898 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
|
|
899 g_return_val_if_fail (newdir != NULL, -2);
|
|
900
|
|
901 tempstr = g_strconcat ("/bin/mkdir ", newdir, NULL);
|
|
902 len = strlen (tempstr);
|
|
903 pos = tempstr;
|
|
904 while ((pos = strchr (pos, ' ')) != NULL)
|
|
905 *pos++ = '\0';
|
|
906 if ((ret = ssh_exec (request, tempstr, len)) != NULL)
|
|
907 {
|
|
908 request->logging_function (gftp_logging_error, request->user_data,
|
|
909 _("Error: Could not make directory %s: %s\n"),
|
|
910 newdir, ret);
|
|
911 g_free (tempstr);
|
|
912 g_free (ret);
|
|
913 return (-2);
|
|
914 }
|
|
915 else
|
|
916 request->logging_function (gftp_logging_misc, request->user_data,
|
|
917 _("Successfully made directory %s\n"),
|
|
918 newdir);
|
|
919 g_free (tempstr);
|
|
920 return (0);
|
|
921 }
|
|
922
|
|
923
|
|
924 static int
|
|
925 ssh_rename (gftp_request * request, const char *oldname, const char *newname )
|
|
926 {
|
|
927 char *tempstr, *pos, *ret;
|
|
928 size_t len;
|
|
929
|
|
930 g_return_val_if_fail (request != NULL, -2);
|
|
931 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
|
|
932 g_return_val_if_fail (oldname != NULL, -2);
|
|
933 g_return_val_if_fail (newname != NULL, -2);
|
|
934
|
|
935 tempstr = g_strconcat ("/bin/mv ", oldname, " ", newname, NULL);
|
|
936 len = strlen (tempstr);
|
|
937 pos = tempstr;
|
|
938 while ((pos = strchr (pos, ' ')) != NULL)
|
|
939 *pos++ = '\0';
|
|
940 if ((ret = ssh_exec (request, tempstr, len)) != NULL)
|
|
941 {
|
|
942 request->logging_function (gftp_logging_misc, request->user_data,
|
|
943 _("Error: Could not rename %s to %s: %s\n"),
|
|
944 oldname, newname, ret);
|
|
945 g_free (tempstr);
|
|
946 g_free (ret);
|
|
947 return (-2);
|
|
948 }
|
|
949 else
|
|
950 request->logging_function (gftp_logging_misc, request->user_data,
|
|
951 _("Successfully renamed %s to %s\n"),
|
|
952 oldname, newname);
|
|
953 g_free (tempstr);
|
|
954 return (0);
|
|
955 }
|
|
956
|
|
957
|
|
958 static int
|
|
959 ssh_chmod (gftp_request * request, const char *file, int mode)
|
|
960 {
|
|
961 char *tempstr, *pos, *ret;
|
|
962 size_t len;
|
|
963
|
|
964 g_return_val_if_fail (request != NULL, -2);
|
|
965 g_return_val_if_fail (request->protonum == GFTP_SSH_NUM, -2);
|
|
966 g_return_val_if_fail (file != NULL, -2);
|
|
967
|
|
968 tempstr = g_malloc (strlen (file) + (mode / 10) + 14);
|
|
969 sprintf (tempstr, "/bin/chmod %d %s", mode, file);
|
|
970 len = strlen (tempstr);
|
|
971 pos = tempstr;
|
|
972 while ((pos = strchr (pos, ' ')) != NULL)
|
|
973 *pos++ = '\0';
|
|
974 if ((ret = ssh_exec (request, tempstr, len)) != NULL)
|
|
975 {
|
|
976 request->logging_function (gftp_logging_misc, request->user_data,
|
|
977 _("Error: Could not change mode of %s to %d: %s\n"),
|
|
978 file, mode, ret);
|
|
979 g_free (tempstr);
|
|
980 g_free (ret);
|
|
981 return (-2);
|
|
982 }
|
|
983 else
|
|
984 request->logging_function (gftp_logging_misc, request->user_data,
|
|
985 _("Successfully changed mode of %s to %d\n"),
|
|
986 file, mode);
|
|
987 g_free (tempstr);
|
|
988 return (0);
|
|
989 }
|
|
990
|
|
991
|
|
992 static int
|
|
993 ssh_send_command (gftp_request * request, int cmdnum, const char *command,
|
|
994 size_t len)
|
|
995 {
|
|
996 ssize_t wrote;
|
|
997 ssh_parms * params;
|
|
998 char *buf;
|
|
999 int clen;
|
|
1000
|
|
1001 params = request->protocol_data;
|
|
1002 clen = htonl (len);
|
|
1003 buf = g_malloc (len + 6);
|
|
1004 buf[0] = params->channel;
|
|
1005 buf[1] = cmdnum;
|
|
1006 memcpy (&buf[2], &clen, 4);
|
|
1007 if (command)
|
|
1008 memcpy (&buf[6], command, len);
|
|
1009 ssh_log_command (request, params->channel, cmdnum, command, len, 1);
|
|
1010
|
|
1011 wrote = fwrite (buf, 1, len + 6, request->sockfd_write);
|
|
1012 if (ferror (request->sockfd_write))
|
|
1013 {
|
|
1014 request->logging_function (gftp_logging_error, request->user_data,
|
|
1015 _("Error: Could not write to socket: %s\n"),
|
|
1016 g_strerror (errno));
|
|
1017 gftp_disconnect (request);
|
|
1018 g_free (buf);
|
|
1019 return (-1);
|
|
1020 }
|
|
1021
|
|
1022 g_free (buf);
|
|
1023
|
|
1024 fflush (request->sockfd_write);
|
|
1025 if (ferror (request->sockfd_write))
|
|
1026 {
|
|
1027 request->logging_function (gftp_logging_error, request->user_data,
|
|
1028 _("Error: Could not write to socket: %s\n"),
|
|
1029 g_strerror (errno));
|
|
1030 gftp_disconnect (request);
|
|
1031 return (-1);
|
|
1032 }
|
|
1033 return 0;
|
|
1034
|
|
1035 }
|
|
1036
|
|
1037 static int
|
|
1038 ssh_read_response (gftp_request * request, ssh_message *message, FILE * fd)
|
|
1039 {
|
|
1040 char buf[6];
|
|
1041
|
|
1042 if (ssh_read_message (request, buf, 6, fd) == NULL)
|
|
1043 return (-1);
|
|
1044
|
|
1045 message->channel = buf[0];
|
|
1046 message->command = buf[1];
|
|
1047 memcpy (&message->len, buf + 2, 4);
|
|
1048 message->len = ntohl (message->len);
|
|
1049 if (message->len > 8192)
|
|
1050 {
|
|
1051 request->logging_function (gftp_logging_error, request->user_data,
|
|
1052 _("Error: Message size %d too big from server\n"),
|
|
1053 message->len);
|
|
1054 memset (message, 0, sizeof (*message));
|
|
1055 gftp_disconnect (request);
|
|
1056 return (-1);
|
|
1057 }
|
|
1058
|
|
1059 message->data = g_malloc (message->len + 1);
|
|
1060
|
|
1061 if (message->len > 0 && ssh_read_message (request,
|
|
1062 (char *) message->data, message->len, fd) == NULL)
|
|
1063 return (-1);
|
|
1064
|
|
1065 ((char *) message->data)[message->len] = '\0';
|
|
1066 ssh_log_command (request, message->channel, message->command, message->data,
|
|
1067 message->len, 0);
|
|
1068 return (message->command);
|
|
1069 }
|
|
1070
|
|
1071
|
|
1072 static char *
|
|
1073 ssh_read_message (gftp_request * request, char *buf, size_t len, FILE * fd)
|
|
1074 {
|
|
1075 if (fd == NULL)
|
|
1076 fd = request->sockfd;
|
|
1077
|
|
1078 fread (buf, len, 1, fd);
|
|
1079 if (ferror (fd))
|
|
1080 {
|
|
1081 request->logging_function (gftp_logging_error, request->user_data,
|
|
1082 _("Error: Could not read from socket: %s\n"),
|
|
1083 g_strerror (errno));
|
|
1084 gftp_disconnect (request);
|
|
1085 return (NULL);
|
|
1086 }
|
|
1087
|
|
1088 return (buf);
|
|
1089 }
|
|
1090
|
|
1091
|
|
1092 static char *
|
|
1093 ssh_read_line (gftp_request * request)
|
|
1094 {
|
|
1095 char *retstr, *pos, tempchar;
|
|
1096 ssh_parms *buffer;
|
|
1097
|
|
1098 pos = NULL;
|
|
1099 buffer = request->protocol_data;
|
|
1100 if (!buffer->enddata && (pos = strchr (buffer->pos, '\n')) == NULL)
|
|
1101 return (NULL);
|
|
1102
|
|
1103 if (pos == NULL)
|
|
1104 {
|
|
1105 pos = buffer->pos + strlen (buffer->pos) - 1;
|
|
1106 tempchar = '\0';
|
|
1107 }
|
|
1108 else
|
|
1109 tempchar = pos + 1 == '\0' ? '\0' : '1';
|
|
1110
|
|
1111 if (*(pos-1) == '\r')
|
|
1112 *(pos-1) = '\0';
|
|
1113 else
|
|
1114 *pos = '\0';
|
|
1115
|
|
1116 retstr = g_malloc (strlen (buffer->pos) + 1);
|
|
1117 strcpy (retstr, buffer->pos);
|
|
1118
|
|
1119 if (tempchar != '\0' && *buffer->pos != '\0')
|
|
1120 {
|
|
1121 buffer->pos = pos + 1;
|
|
1122 while (*buffer->pos == '\r' || *buffer->pos == '\n')
|
|
1123 buffer->pos++;
|
|
1124 }
|
|
1125 else
|
|
1126 {
|
|
1127 g_free (buffer->buffer);
|
|
1128 buffer->buffer = buffer->pos = NULL;
|
|
1129 }
|
|
1130 return (retstr);
|
|
1131 }
|
|
1132
|
|
1133
|
|
1134 static void
|
|
1135 ssh_log_command (gftp_request * request, int channel, int cmdnum,
|
|
1136 const char *command, size_t len, int direction)
|
|
1137 {
|
|
1138 const char *pos;
|
|
1139 char *tempstr;
|
|
1140 int ok;
|
|
1141
|
|
1142 switch (cmdnum)
|
|
1143 {
|
|
1144 case CHDIR:
|
|
1145 tempstr = "CHDIR ";
|
|
1146 break;
|
|
1147 case GETDIR:
|
|
1148 tempstr = "GETDIR ";
|
|
1149 break;
|
|
1150 case TELLDIR:
|
|
1151 tempstr = "TELLDIR ";
|
|
1152 break;
|
|
1153 case SENDFILE:
|
|
1154 tempstr = "SENDFILE ";
|
|
1155 break;
|
|
1156 case FILESIZE:
|
|
1157 tempstr = "FILESIZE ";
|
|
1158 break;
|
|
1159 case FILEMODE:
|
|
1160 tempstr = "FILEMODE ";
|
|
1161 break;
|
|
1162 case ENDDATA:
|
|
1163 tempstr = "ENDDATA ";
|
|
1164 break;
|
|
1165 case FILEOK:
|
|
1166 tempstr = "FILEOK ";
|
|
1167 break;
|
|
1168 case STREAM:
|
|
1169 tempstr = "STREAM ";
|
|
1170 break;
|
|
1171 case REQUEST:
|
|
1172 tempstr = "REQUEST ";
|
|
1173 break;
|
|
1174 case FILENAME:
|
|
1175 tempstr = "FILENAME ";
|
|
1176 break;
|
|
1177 case EXEC:
|
|
1178 tempstr = "EXEC ";
|
|
1179 break;
|
|
1180 case SKIPBYTES:
|
|
1181 tempstr = "SKIPBYTES ";
|
|
1182 break;
|
|
1183 case ERROR:
|
|
1184 tempstr = "ERROR: ";
|
|
1185 break;
|
|
1186 case SUCCESS:
|
|
1187 tempstr = "SUCCESS ";
|
|
1188 break;
|
|
1189 case CLOSE:
|
|
1190 tempstr = "CLOSE ";
|
|
1191 break;
|
|
1192 case SSH_VERSION:
|
|
1193 tempstr = "VERSION ";
|
|
1194 break;
|
|
1195 case CANCEL:
|
|
1196 tempstr = "CANCEL ";
|
|
1197 break;
|
|
1198 case FILETIME:
|
|
1199 tempstr = "FILETIME ";
|
|
1200 break;
|
|
1201 default:
|
|
1202 return;
|
|
1203 }
|
|
1204
|
|
1205 ok = 0;
|
|
1206 if (command)
|
|
1207 {
|
|
1208 for (pos = command; pos < command + len; pos++)
|
|
1209 {
|
|
1210 if (*pos == '\0')
|
|
1211 {
|
|
1212 ok = 1;
|
|
1213 break;
|
|
1214 }
|
|
1215 }
|
|
1216 }
|
|
1217
|
|
1218 request->logging_function (direction == GFTP_DIRECTION_DOWNLOAD ?
|
|
1219 gftp_logging_send : gftp_logging_recv,
|
|
1220 request->user_data, "%d: %s %s\n", channel,
|
|
1221 tempstr, ok ? command : "");
|
|
1222 }
|
|
1223
|
|
1224
|
|
1225 static size_t
|
|
1226 ssh_remove_spaces ( char *string )
|
|
1227 {
|
|
1228 size_t len;
|
|
1229 char *pos;
|
|
1230
|
|
1231 for (pos = string, len = 0; *pos != '\0'; len++, pos++)
|
|
1232 {
|
|
1233 if (*pos == ' ')
|
|
1234 *pos = '\0';
|
|
1235 }
|
|
1236 return (len);
|
|
1237 }
|
|
1238
|