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