comparison lib/sshv2.c @ 1:8b1883341c6f

Initial revision
author masneyb
date Mon, 05 Aug 2002 19:46:57 +0000
parents
children 83090328581e
comparison
equal deleted inserted replaced
0:674ed97069fd 1:8b1883341c6f
1 /*****************************************************************************/
2 /* sshv2.c - functions that will use the sshv2 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 #include "gftp.h"
21
22 #define SSH_MAX_HANDLE_SIZE 256
23 #define SSH_MAX_STRING_SIZE 34000
24
25 typedef struct sshv2_attribs_tag
26 {
27 gint32 flags;
28 gint64 size;
29 gint32 uid;
30 gint32 gid;
31 gint32 perm;
32 gint32 atime;
33 gint32 mtime;
34 } sshv2_attribs;
35
36 typedef struct sshv2_message_tag
37 {
38 gint32 length;
39 char command;
40 char *buffer,
41 *pos,
42 *end;
43 } sshv2_message;
44
45 typedef struct sshv2_params_tag
46 {
47 char handle[SSH_MAX_HANDLE_SIZE + 4]; /* We'll encode the ID in here too */
48 int handle_len,
49 dont_log_status : 1; /* For uploading files */
50 sshv2_message message;
51
52 gint32 id,
53 count;
54 #ifdef G_HAVE_GINT64
55 gint64 offset;
56 #else
57 gint32 offset;
58 #endif
59 char *read_buffer;
60 } sshv2_params;
61
62
63 static void sshv2_destroy ( gftp_request * request );
64 static int sshv2_connect ( gftp_request * request );
65 static void sshv2_disconnect ( gftp_request * request );
66 static gint32 sshv2_buffer_get_int32 ( gftp_request * request,
67 sshv2_message * buffer,
68 int expected_response );
69 static char * sshv2_buffer_get_string ( gftp_request * request,
70 sshv2_message * buffer );
71 static int sshv2_send_command ( gftp_request * request,
72 char type,
73 char *command,
74 gint32 len );
75 static int sshv2_read_response ( gftp_request * request,
76 sshv2_message * message,
77 FILE * fd );
78 static void sshv2_message_free ( sshv2_message * message );
79 static void sshv2_log_command ( gftp_request * request,
80 gftp_logging_level level,
81 char type,
82 char *message,
83 size_t length );
84 static int sshv2_end_transfer ( gftp_request * request );
85 static int sshv2_list_files ( gftp_request * request );
86 static int sshv2_get_next_file ( gftp_request * request,
87 gftp_file * fle,
88 FILE * fd );
89 static int sshv2_chdir ( gftp_request * request,
90 const char *directory );
91 static int sshv2_getcwd ( gftp_request * request );
92 static int sshv2_rmdir ( gftp_request * request,
93 const char *directory );
94 static int sshv2_rmfile ( gftp_request * request,
95 const char *file);
96 static int sshv2_chmod ( gftp_request * request,
97 const char *file,
98 int mode );
99 static int sshv2_mkdir ( gftp_request * request,
100 const char *newdir );
101 static int sshv2_rename ( gftp_request * request,
102 const char *oldname,
103 const char *newname );
104 static int sshv2_set_file_time ( gftp_request * request,
105 const char *file,
106 time_t datetime );
107 static off_t sshv2_get_file_size ( gftp_request * request,
108 const char *file );
109 static long sshv2_get_file ( gftp_request * request,
110 const char *filename,
111 FILE * fd,
112 off_t startsize );
113 static int sshv2_put_file ( gftp_request * request,
114 const char *filename,
115 FILE * fd,
116 off_t startsize,
117 off_t totalsize );
118 static size_t sshv2_get_next_file_chunk ( gftp_request * request,
119 char *buf,
120 size_t size );
121 static size_t sshv2_put_next_file_chunk ( gftp_request * request,
122 char *buf,
123 size_t size );
124
125 #define SSH_MY_VERSION 3
126
127 #define SSH_FXP_INIT 1
128 #define SSH_FXP_VERSION 2
129 #define SSH_FXP_OPEN 3
130 #define SSH_FXP_CLOSE 4
131 #define SSH_FXP_READ 5
132 #define SSH_FXP_WRITE 6
133 #define SSH_FXP_LSTAT 7
134 #define SSH_FXP_FSTAT 8
135 #define SSH_FXP_SETSTAT 9
136 #define SSH_FXP_FSETSTAT 10
137 #define SSH_FXP_OPENDIR 11
138 #define SSH_FXP_READDIR 12
139 #define SSH_FXP_REMOVE 13
140 #define SSH_FXP_MKDIR 14
141 #define SSH_FXP_RMDIR 15
142 #define SSH_FXP_REALPATH 16
143 #define SSH_FXP_STAT 17
144 #define SSH_FXP_RENAME 18
145 #define SSH_FXP_STATUS 101
146 #define SSH_FXP_HANDLE 102
147 #define SSH_FXP_DATA 103
148 #define SSH_FXP_NAME 104
149 #define SSH_FXP_ATTRS 105
150 #define SSH_FXP_EXTENDED 200
151 #define SSH_FXP_EXTENDED_REPLY 201
152
153 #define SSH_FILEXFER_ATTR_SIZE 0x00000001
154 #define SSH_FILEXFER_ATTR_UIDGID 0x00000002
155 #define SSH_FILEXFER_ATTR_PERMISSIONS 0x00000004
156 #define SSH_FILEXFER_ATTR_ACMODTIME 0x00000008
157 #define SSH_FILEXFER_ATTR_EXTENDED 0x80000000
158
159 #define SSH_FXF_READ 0x00000001
160 #define SSH_FXF_WRITE 0x00000002
161 #define SSH_FXF_APPEND 0x00000004
162 #define SSH_FXF_CREAT 0x00000008
163 #define SSH_FXF_TRUNC 0x00000010
164 #define SSH_FXF_EXCL 0x00000020
165
166 #define SSH_FX_OK 0
167 #define SSH_FX_EOF 1
168 #define SSH_FX_NO_SUCH_FILE 2
169 #define SSH_FX_PERMISSION_DENIED 3
170 #define SSH_FX_FAILURE 4
171 #define SSH_FX_BAD_MESSAGE 5
172 #define SSH_FX_NO_CONNECTION 6
173 #define SSH_FX_CONNECTION_LOST 7
174 #define SSH_FX_OP_UNSUPPORTED 8
175
176
177 void
178 sshv2_init (gftp_request * request)
179 {
180 sshv2_params * params;
181
182 g_return_if_fail (request != NULL);
183
184 request->protonum = GFTP_SSHV2_NUM;
185 request->init = sshv2_init;
186 request->destroy = sshv2_destroy;
187 request->connect = sshv2_connect;
188 request->disconnect = sshv2_disconnect;
189 request->get_file = sshv2_get_file;
190 request->put_file = sshv2_put_file;
191 request->transfer_file = NULL;
192 request->get_next_file_chunk = sshv2_get_next_file_chunk;
193 request->put_next_file_chunk = sshv2_put_next_file_chunk;
194 request->end_transfer = sshv2_end_transfer;
195 request->list_files = sshv2_list_files;
196 request->get_next_file = sshv2_get_next_file;
197 request->set_data_type = NULL;
198 request->get_file_size = sshv2_get_file_size;
199 request->chdir = sshv2_chdir;
200 request->rmdir = sshv2_rmdir;
201 request->rmfile = sshv2_rmfile;
202 request->mkdir = sshv2_mkdir;
203 request->rename = sshv2_rename;
204 request->chmod = sshv2_chmod;
205 request->set_file_time = sshv2_set_file_time;
206 request->site = NULL;
207 request->parse_url = NULL;
208 request->url_prefix = "ssh2";
209 request->protocol_name = "SSH2";
210 request->need_hostport = 1;
211 request->need_userpass = ssh_need_userpass;
212 request->use_cache = 1;
213 request->use_threads = 1;
214 request->always_connected = 0;
215 request->protocol_data = g_malloc0 (sizeof (sshv2_params));
216 gftp_set_config_options (request);
217
218 params = request->protocol_data;
219 params->id = 1;
220 }
221
222
223 static void
224 sshv2_destroy (gftp_request * request)
225 {
226 g_return_if_fail (request != NULL);
227 g_return_if_fail (request->protonum == GFTP_SSHV2_NUM);
228
229 g_free (request->protocol_data);
230 request->protocol_data = NULL;
231 }
232
233
234 static int
235 sshv2_connect (gftp_request * request)
236 {
237 char **args, *tempstr, pts_name[20], *p1, p2, *exepath, port[6];
238 int version, fdm, fds, s[2];
239 sshv2_message message;
240 const gchar *errstr;
241 pid_t child;
242
243 g_return_val_if_fail (request != NULL, -2);
244 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
245 g_return_val_if_fail (request->hostname != NULL, -2);
246
247 if (request->sockfd != NULL)
248 return (0);
249
250 request->logging_function (gftp_logging_misc, request->user_data,
251 _("Opening SSH connection to %s\n"),
252 request->hostname);
253
254 /* Ugh!! We don't get a login banner from sftp-server, and if we are
255 using ssh-agent to cache a users password, then we won't receive
256 any initial text from the server, and we'll block. So I just send a
257 xsftp server banner over. I hope this works on most Unices */
258
259 if (request->sftpserv_path == NULL ||
260 *request->sftpserv_path == '\0')
261 {
262 p1 = "";
263 p2 = ' ';
264 }
265 else
266 {
267 p1 = request->sftpserv_path;
268 p2 = '/';
269 }
270
271 *port = '\0';
272 exepath = g_strdup_printf ("echo -n xsftp ; %s%csftp-server", p1, p2);
273 args = make_ssh_exec_args (request, exepath, sshv2_use_sftp_subsys, port);
274
275 if (ssh_use_askpass || sshv2_use_sftp_subsys)
276 {
277 fdm = fds = 0;
278 if (socketpair (AF_LOCAL, SOCK_STREAM, 0, s) < 0)
279 {
280 request->logging_function (gftp_logging_error, request->user_data,
281 _("Cannot create a socket pair: %s\n"),
282 g_strerror (errno));
283 return (-2);
284 }
285 }
286 else
287 {
288 s[0] = s[1] = 0;
289 if ((fdm = ptym_open (pts_name)) < 0)
290 {
291 request->logging_function (gftp_logging_error, request->user_data,
292 _("Cannot open master pty %s: %s\n"), pts_name,
293 g_strerror (errno));
294 return (-2);
295 }
296 }
297
298 if ((child = fork ()) == 0)
299 {
300 setsid ();
301 if (ssh_use_askpass || sshv2_use_sftp_subsys)
302 {
303 close (s[0]);
304 fds = s[1];
305 }
306 else
307 {
308 if ((fds = ptys_open (fdm, pts_name)) < 0)
309 {
310 printf ("Cannot open slave pts %s: %s\n", pts_name,
311 g_strerror (errno));
312 return (-1);
313 }
314 close (fdm);
315 }
316
317 tty_raw (fds);
318 dup2 (fds, 0);
319 dup2 (fds, 1);
320 dup2 (fds, 2);
321 if (!ssh_use_askpass && fds > 2)
322 close (fds);
323 execvp (ssh_prog_name != NULL && *ssh_prog_name != '\0' ?
324 ssh_prog_name : "ssh", args);
325
326 tempstr = _("Error: Cannot execute ssh: ");
327 write (1, tempstr, strlen (tempstr));
328 errstr = g_strerror (errno);
329 write (1, errstr, strlen (errstr));
330 write (1, "\n", 1);
331 return (-1);
332 }
333 else if (child > 0)
334 {
335 if (ssh_use_askpass || sshv2_use_sftp_subsys)
336 {
337 close (s[1]);
338 fdm = s[0];
339 }
340 tty_raw (fdm);
341 if (!sshv2_use_sftp_subsys)
342 {
343 tempstr = ssh_start_login_sequence (request, fdm);
344 if (!tempstr ||
345 !(strlen (tempstr) > 4 && strcmp (tempstr + strlen (tempstr) - 5,
346 "xsftp") == 0))
347 {
348 request->logging_function (gftp_logging_error, request->user_data,
349 _("Error: Received wrong init string from server\n"));
350 g_free (args);
351 g_free (exepath);
352 return (-2);
353 }
354 g_free (tempstr);
355 }
356 g_free (args);
357 g_free (exepath);
358
359 request->sockfd = request->datafd = fdopen (fdm, "rb");
360 request->sockfd_write = fdopen (fdm, "wb");
361
362 version = htonl (SSH_MY_VERSION);
363 if (sshv2_send_command (request, SSH_FXP_INIT, (char *) &version, 4) < 0)
364 return (-2);
365
366 memset (&message, 0, sizeof (message));
367 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_VERSION)
368 {
369 request->logging_function (gftp_logging_error, request->user_data,
370 _("Received wrong response from server, disconnecting\n"));
371 sshv2_message_free (&message);
372 gftp_disconnect (request);
373 return (-2);
374 }
375 sshv2_message_free (&message);
376
377 request->logging_function (gftp_logging_misc, request->user_data,
378 _("Successfully logged into SSH server %s\n"),
379 request->hostname);
380 }
381 else
382 {
383 request->logging_function (gftp_logging_error, request->user_data,
384 _("Cannot fork another process: %s\n"),
385 g_strerror (errno));
386 g_free (args);
387 return (-1);
388 }
389
390 sshv2_getcwd (request);
391 if (request->sockfd == NULL)
392 return (-2);
393
394 return (0);
395 }
396
397
398 static void
399 sshv2_disconnect (gftp_request * request)
400 {
401 sshv2_params * params;
402
403 g_return_if_fail (request != NULL);
404 g_return_if_fail (request->protonum == GFTP_SSHV2_NUM);
405
406 params = request->protocol_data;
407
408 if (request->sockfd != NULL)
409 {
410 request->logging_function (gftp_logging_misc, request->user_data,
411 _("Disconnecting from site %s\n"),
412 request->hostname);
413 fclose (request->sockfd);
414 request->sockfd = request->datafd = request->sockfd_write = NULL;
415 }
416
417 if (params->message.buffer != NULL)
418 sshv2_message_free (&params->message);
419 }
420
421
422 static gint32
423 sshv2_buffer_get_int32 (gftp_request * request, sshv2_message * message,
424 int expected_response)
425 {
426 gint32 ret;
427
428 if (message->end - message->pos < 4)
429 {
430 request->logging_function (gftp_logging_error, request->user_data,
431 _("Received wrong response from server, disconnecting\n"));
432 sshv2_message_free (message);
433 gftp_disconnect (request);
434 return (-2);
435 }
436
437 memcpy (&ret, message->pos, 4);
438 ret = ntohl (ret);
439 message->pos += 4;
440
441 if (expected_response > 0 && ret != expected_response)
442 {
443 request->logging_function (gftp_logging_error, request->user_data,
444 _("Received wrong response from server, disconnecting\n"));
445 sshv2_message_free (message);
446 gftp_disconnect (request);
447 return (-2);
448 }
449
450 return (ret);
451 }
452
453
454 static char *
455 sshv2_buffer_get_string (gftp_request * request, sshv2_message * message)
456 {
457 char *string;
458 gint32 len;
459
460 if ((len = sshv2_buffer_get_int32 (request, message, -1)) < 0)
461 return (NULL);
462
463 if (len > SSH_MAX_STRING_SIZE || (message->end - message->pos < len))
464 {
465 request->logging_function (gftp_logging_error, request->user_data,
466 _("Received wrong response from server, disconnecting\n"));
467 sshv2_message_free (message);
468 gftp_disconnect (request);
469 return (NULL);
470 }
471
472 string = g_malloc (len + 1);
473 memcpy (string, message->pos, len);
474 string[len] = '\0';
475 message->pos += len;
476 return (string);
477 }
478
479
480 static int
481 sshv2_send_command (gftp_request * request, char type, char *command,
482 gint32 len)
483 {
484 char buf[34000];
485 ssize_t wrote;
486 gint32 clen;
487
488 if (len > 33995)
489 {
490 request->logging_function (gftp_logging_error, request->user_data,
491 _("Error: Message size %d too big\n"), len);
492 gftp_disconnect (request);
493 return (-1);
494 }
495
496 clen = htonl (len + 1);
497 memcpy (buf, &clen, 4);
498 buf[4] = type;
499 memcpy (&buf[5], command, len);
500 buf[len + 5] = '\0';
501
502 #ifdef DEBUG
503 printf ("\rSending: ");
504 for (wrote=0; wrote<len + 5; wrote++)
505 printf ("%x ", buf[wrote]);
506 printf ("\n");
507 #endif
508
509 sshv2_log_command (request, gftp_logging_send, type, buf + 5, len);
510
511 wrote = fwrite (buf, len + 5, 1, request->sockfd_write);
512 if (ferror (request->sockfd_write))
513 {
514 request->logging_function (gftp_logging_error, request->user_data,
515 _("Error: Could not write to socket: %s\n"),
516 g_strerror (errno));
517 gftp_disconnect (request);
518 return (-1);
519 }
520
521 fflush (request->sockfd_write);
522 if (ferror (request->sockfd_write))
523 {
524 request->logging_function (gftp_logging_error, request->user_data,
525 _("Error: Could not write to socket: %s\n"),
526 g_strerror (errno));
527 gftp_disconnect (request);
528 return (-1);
529 }
530 return 0;
531 }
532
533
534 static int
535 sshv2_read_response (gftp_request * request, sshv2_message * message,
536 FILE * fd)
537 {
538 ssize_t numread;
539 char buf[5];
540
541 if (fd == NULL)
542 fd = request->sockfd;
543
544 numread = fread (buf, 5, 1, fd);
545 if (ferror (fd))
546 {
547 request->logging_function (gftp_logging_error, request->user_data,
548 _("Error: Could not read from socket: %s\n"),
549 g_strerror (errno));
550 gftp_disconnect (request);
551 return (-1);
552 }
553
554 #ifdef DEBUG
555 printf ("\rReceived: ");
556 for (numread=0; numread<5; numread++)
557 printf ("%x ", buf[numread]);
558 fflush (stdout);
559 #endif
560
561 memcpy (&message->length, buf, 4);
562 message->length = ntohl (message->length);
563 if (message->length > 34000)
564 {
565 request->logging_function (gftp_logging_error, request->user_data,
566 _("Error: Message size %d too big from server\n"),
567 message->length);
568 memset (message, 0, sizeof (*message));
569 gftp_disconnect (request);
570 return (-1);
571 }
572 message->command = buf[4];
573 message->buffer = g_malloc (message->length);
574
575 message->pos = message->buffer;
576 message->end = message->buffer + message->length - 1;
577
578 numread = fread (message->buffer, message->length - 1, 1, fd);
579 if (ferror (fd))
580 {
581 request->logging_function (gftp_logging_error, request->user_data,
582 _("Error: Could not read from socket: %s\n"),
583 g_strerror (errno));
584 gftp_disconnect (request);
585 return (-1);
586 }
587 message->buffer[message->length - 1] = '\0';
588
589 #ifdef DEBUG
590 printf ("\rReceived: ");
591 for (numread=0; numread<message->length - 1; numread++)
592 printf ("%x ", message->buffer[numread]);
593 printf ("\n");
594 #endif
595
596 sshv2_log_command (request, gftp_logging_recv, message->command,
597 message->buffer, message->length);
598
599 return (message->command);
600 }
601
602
603 static void
604 sshv2_message_free (sshv2_message * message)
605 {
606 if (message->buffer)
607 g_free (message->buffer);
608 memset (message, 0, sizeof (*message));
609 }
610
611
612 static void
613 sshv2_log_command (gftp_request * request, gftp_logging_level level,
614 char type, char *message, size_t length)
615 {
616 gint32 id, num, attr, stattype;
617 char *descr, *pos, oldchar;
618 sshv2_params * params;
619
620 params = request->protocol_data;
621 memcpy (&id, message, 4);
622 id = ntohl (id);
623 switch (type)
624 {
625 case SSH_FXP_INIT:
626 request->logging_function (level, request->user_data,
627 _("%d: Protocol Initialization\n"), id);
628 break;
629 case SSH_FXP_VERSION:
630 memcpy (&num, message, 4);
631 num = ntohl (num);
632 request->logging_function (level, request->user_data,
633 _("%d: Protocol version %d\n"), id, num);
634 break;
635 case SSH_FXP_OPEN:
636 memcpy (&num, message + 4, 4);
637 num = ntohl (num);
638 pos = message + 12 + num - 1;
639 oldchar = *pos;
640 *pos = '\0';
641 request->logging_function (level, request->user_data,
642 _("%d: Open %s\n"), id, message + 8);
643 *pos = oldchar;
644 break;
645 case SSH_FXP_CLOSE:
646 request->logging_function (level, request->user_data,
647 _("%d: Close\n"), id);
648 case SSH_FXP_READ:
649 case SSH_FXP_WRITE:
650 break;
651 case SSH_FXP_OPENDIR:
652 request->logging_function (level, request->user_data,
653 _("%d: Open Directory %s\n"), id,
654 message + 8);
655 break;
656 case SSH_FXP_READDIR:
657 request->logging_function (level, request->user_data,
658 _("%d: Read Directory\n"), id);
659 break;
660 case SSH_FXP_REMOVE:
661 request->logging_function (level, request->user_data,
662 _("%d: Remove file %s\n"), id,
663 message + 8);
664 break;
665 case SSH_FXP_MKDIR:
666 request->logging_function (level, request->user_data,
667 _("%d: Make directory %s\n"), id,
668 message + 8);
669 break;
670 case SSH_FXP_RMDIR:
671 request->logging_function (level, request->user_data,
672 _("%d: Remove directory %s\n"), id,
673 message + 8);
674 break;
675 case SSH_FXP_REALPATH:
676 request->logging_function (level, request->user_data,
677 _("%d: Realpath %s\n"), id,
678 message + 8);
679 break;
680 case SSH_FXP_ATTRS:
681 request->logging_function (level, request->user_data,
682 _("%d: File attributes\n"), id);
683 break;
684 case SSH_FXP_STAT:
685 request->logging_function (level, request->user_data,
686 _("%d: Stat %s\n"), id,
687 message + 8);
688 break;
689 case SSH_FXP_SETSTAT:
690 memcpy (&num, message + 4, 4);
691 num = ntohl (num);
692 pos = message + 12 + num - 1;
693 oldchar = *pos;
694 *pos = '\0';
695 memcpy (&stattype, message + 8 + num, 4);
696 stattype = ntohl (stattype);
697 memcpy (&attr, message + 12 + num, 4);
698 attr = ntohl (attr);
699 switch (stattype)
700 {
701 case SSH_FILEXFER_ATTR_PERMISSIONS:
702 request->logging_function (level, request->user_data,
703 _("%d: Chmod %s %o\n"), id,
704 message + 8, attr);
705 break;
706 case SSH_FILEXFER_ATTR_ACMODTIME:
707 request->logging_function (level, request->user_data,
708 _("%d: Utime %s %d\n"), id,
709 message + 8, attr);
710 }
711 *pos = oldchar;
712 break;
713 case SSH_FXP_STATUS:
714 if (params->dont_log_status)
715 break;
716 memcpy (&num, message + 4, 4);
717 num = ntohl (num);
718 switch (num)
719 {
720 case SSH_FX_OK:
721 descr = _("OK");
722 break;
723 case SSH_FX_EOF:
724 descr = _("EOF");
725 break;
726 case SSH_FX_NO_SUCH_FILE:
727 descr = _("No such file or directory");
728 break;
729 case SSH_FX_PERMISSION_DENIED:
730 descr = _("Permission denied");
731 break;
732 case SSH_FX_FAILURE:
733 descr = _("Failure");
734 break;
735 case SSH_FX_BAD_MESSAGE:
736 descr = _("Bad message");
737 break;
738 case SSH_FX_NO_CONNECTION:
739 descr = _("No connection");
740 break;
741 case SSH_FX_CONNECTION_LOST:
742 descr = _("Connection lost");
743 break;
744 case SSH_FX_OP_UNSUPPORTED:
745 descr = _("Operation unsupported");
746 break;
747 default:
748 descr = _("Unknown message returned from server");
749 break;
750 }
751 request->logging_function (level, request->user_data,
752 "%d: %s\n", id, descr);
753 break;
754 case SSH_FXP_HANDLE:
755 request->logging_function (level, request->user_data,
756 "%d: File handle\n", id);
757 break;
758 case SSH_FXP_DATA:
759 break;
760 case SSH_FXP_NAME:
761 memcpy (&num, message + 4, 4);
762 num = ntohl (num);
763 request->logging_function (level, request->user_data,
764 "%d: Filenames (%d entries)\n", id,
765 num);
766 break;
767 default:
768 request->logging_function (level, request->user_data,
769 "Command: %x\n", type);
770 }
771 }
772
773
774 static int
775 sshv2_end_transfer (gftp_request * request)
776 {
777 sshv2_params * params;
778 sshv2_message message;
779 gint32 len;
780
781 g_return_val_if_fail (request != NULL, -2);
782 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
783 g_return_val_if_fail (request->datafd != NULL, -2);
784
785 params = request->protocol_data;
786 if (params->message.buffer != NULL)
787 {
788 sshv2_message_free (&params->message);
789 params->count = 0;
790 }
791
792 if (params->handle_len > 0)
793 {
794 len = htonl (params->id++);
795 memcpy (params->handle, &len, 4);
796
797 if (sshv2_send_command (request, SSH_FXP_CLOSE, params->handle,
798 params->handle_len) < 0)
799 return (-2);
800
801 memset (&message, 0, sizeof (message));
802 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_STATUS)
803 {
804 request->logging_function (gftp_logging_error, request->user_data,
805 _("Received wrong response from server, disconnecting\n"));
806 sshv2_message_free (&message);
807 gftp_disconnect (request);
808 return (-2);
809 }
810 sshv2_message_free (&message);
811 params->handle_len = 0;
812 }
813
814 if (params->read_buffer != NULL)
815 {
816 g_free (params->read_buffer);
817 params->read_buffer = NULL;
818 }
819
820 return (0);
821 }
822
823
824 static int
825 sshv2_list_files (gftp_request * request)
826 {
827 sshv2_params * params;
828 sshv2_message message;
829 char *tempstr;
830 gint32 len;
831
832 g_return_val_if_fail (request != NULL, -2);
833 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
834 g_return_val_if_fail (request->sockfd != NULL, -2);
835
836 params = request->protocol_data;
837
838 request->logging_function (gftp_logging_misc, request->user_data,
839 _("Retrieving directory listing...\n"));
840
841 tempstr = g_malloc (strlen (request->directory) + 9);
842
843 len = htonl (params->id++);
844 memcpy (tempstr, &len, 4);
845
846 len = htonl (strlen (request->directory));
847 memcpy (tempstr + 4, &len, 4);
848 strcpy (tempstr + 8, request->directory);
849 if (sshv2_send_command (request, SSH_FXP_OPENDIR, tempstr,
850 strlen (request->directory) + 8) < 0)
851 {
852 g_free (tempstr);
853 return (-2);
854 }
855 g_free (tempstr);
856
857 memset (&message, 0, sizeof (message));
858 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_HANDLE)
859 {
860 request->logging_function (gftp_logging_error, request->user_data,
861 _("Received wrong response from server, disconnecting\n"));
862 sshv2_message_free (&message);
863 gftp_disconnect (request);
864 return (-2);
865 }
866
867 if (message.length - 4 > SSH_MAX_HANDLE_SIZE)
868 {
869 request->logging_function (gftp_logging_error, request->user_data,
870 _("Error: Message size %d too big from server\n"),
871 message.length - 4);
872 sshv2_message_free (&message);
873 gftp_disconnect (request);
874 return (-1);
875
876 }
877
878 memset (params->handle, 0, 4);
879 memcpy (params->handle + 4, message.buffer + 4, message.length - 5);
880 params->handle_len = message.length - 1;
881 sshv2_message_free (&message);
882 params->count = 0;
883 return (0);
884 }
885
886
887 static int
888 sshv2_get_next_file (gftp_request * request, gftp_file * fle, FILE * fd)
889 {
890 gint32 len, attrs, longnamelen;
891 int ret, i, count, retsize;
892 sshv2_params *params;
893 char *longname;
894
895 g_return_val_if_fail (request != NULL, -2);
896 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
897 g_return_val_if_fail (fle != NULL, -2);
898
899 params = request->protocol_data;
900
901 if (request->last_dir_entry)
902 {
903 g_free (request->last_dir_entry);
904 request->last_dir_entry = NULL;
905 request->last_dir_entry_len = 0;
906 }
907 retsize = 0;
908
909 if (params->count > 0)
910 ret = SSH_FXP_NAME;
911 else
912 {
913 if (!request->cached)
914 {
915 if (params->message.buffer != NULL)
916 sshv2_message_free (&params->message);
917
918 len = htonl (params->id++);
919 memcpy (params->handle, &len, 4);
920
921 if (sshv2_send_command (request, SSH_FXP_READDIR, params->handle,
922 params->handle_len) < 0)
923 return (-2);
924 }
925
926 if ((ret = sshv2_read_response (request, &params->message, fd)) < 0)
927 return (-2);
928
929 if (!request->cached)
930 {
931 request->last_dir_entry = g_malloc (params->message.length + 4);
932 len = htonl (params->message.length);
933 memcpy (request->last_dir_entry, &len, 4);
934 request->last_dir_entry[4] = params->message.command;
935 memcpy (request->last_dir_entry + 5, params->message.buffer,
936 params->message.length - 1);
937 request->last_dir_entry_len = params->message.length + 4;
938 }
939
940 if (ret == SSH_FXP_NAME)
941 {
942 params->message.pos = params->message.buffer + 4;
943 if ((params->count = sshv2_buffer_get_int32 (request,
944 &params->message, -1)) < 0)
945 return (-2);
946 }
947 }
948
949 if (ret == SSH_FXP_NAME)
950 {
951 if ((len = sshv2_buffer_get_int32 (request, &params->message, -1)) < 0 ||
952 params->message.pos + len > params->message.end)
953 return (-2);
954
955 params->message.pos += len;
956
957 if ((longnamelen = sshv2_buffer_get_int32 (request,
958 &params->message, -1)) < 0 ||
959 params->message.pos + longnamelen > params->message.end)
960 return (-2);
961
962 longname = params->message.pos;
963 params->message.pos += longnamelen;
964
965 if ((attrs = sshv2_buffer_get_int32 (request, &params->message, -1)) < 0)
966 return (-2);
967
968 if (attrs & SSH_FILEXFER_ATTR_SIZE)
969 {
970 params->message.pos += 8;
971 if (params->message.pos > params->message.end)
972 {
973 request->logging_function (gftp_logging_error, request->user_data,
974 _("Received wrong response from server, disconnecting\n"));
975 sshv2_message_free (&params->message);
976 gftp_disconnect (request);
977 return (-2);
978 }
979 }
980
981 if (attrs & SSH_FILEXFER_ATTR_UIDGID)
982 {
983 params->message.pos += 8;
984 if (params->message.pos > params->message.end)
985 {
986 request->logging_function (gftp_logging_error, request->user_data,
987 _("Received wrong response from server, disconnecting\n"));
988 sshv2_message_free (&params->message);
989 gftp_disconnect (request);
990 return (-2);
991 }
992 }
993
994 if (attrs & SSH_FILEXFER_ATTR_PERMISSIONS)
995 {
996 params->message.pos += 4;
997 if (params->message.pos > params->message.end)
998 {
999 request->logging_function (gftp_logging_error, request->user_data,
1000 _("Received wrong response from server, disconnecting\n"));
1001 sshv2_message_free (&params->message);
1002 gftp_disconnect (request);
1003 return (-2);
1004 }
1005 }
1006
1007 if (attrs & SSH_FILEXFER_ATTR_ACMODTIME)
1008 {
1009 params->message.pos += 8;
1010 if (params->message.pos > params->message.end)
1011 {
1012 request->logging_function (gftp_logging_error, request->user_data,
1013 _("Received wrong response from server, disconnecting\n"));
1014 sshv2_message_free (&params->message);
1015 gftp_disconnect (request);
1016 return (-2);
1017 }
1018 }
1019
1020 if (attrs & SSH_FILEXFER_ATTR_EXTENDED)
1021 {
1022 if ((count = sshv2_buffer_get_int32 (request,
1023 &params->message, -1)) < 0)
1024 return (-2);
1025
1026 for (i=0; i<count; i++)
1027 {
1028 if ((len = sshv2_buffer_get_int32 (request,
1029 &params->message, -1)) < 0 ||
1030 params->message.pos + len + 4 > params->message.end)
1031 return (-2);
1032
1033 params->message.pos += len + 4;
1034
1035 if ((len = sshv2_buffer_get_int32 (request,
1036 &params->message, -1)) < 0 ||
1037 params->message.pos + len + 4 > params->message.end)
1038 return (-2);
1039
1040 params->message.pos += len + 4;
1041 }
1042 }
1043
1044 longname[longnamelen] = '\0';
1045
1046 /* The commercial SSH2 puts a / and * after some entries */
1047 if (longname[longnamelen - 1] == '*')
1048 longname[--longnamelen] = '\0';
1049 if (longname[longnamelen - 1] == '/')
1050 longname[--longnamelen] = '\0';
1051
1052 if (gftp_parse_ls (longname, fle) != 0)
1053 {
1054 gftp_file_destroy (fle);
1055 return (-2);
1056 }
1057 retsize = strlen (longname);
1058
1059 params->count--;
1060 }
1061 else if (ret == SSH_FXP_STATUS)
1062 {
1063 sshv2_message_free (&params->message);
1064 return (0);
1065 }
1066 else
1067 {
1068 request->logging_function (gftp_logging_error, request->user_data,
1069 _("Received wrong response from server, disconnecting\n"));
1070 sshv2_message_free (&params->message);
1071 gftp_disconnect (request);
1072 return (-2);
1073 }
1074
1075 return (retsize);
1076 }
1077
1078
1079 static int
1080 sshv2_chdir (gftp_request * request, const char *directory)
1081 {
1082 sshv2_message message;
1083 sshv2_params * params;
1084 char *tempstr, *dir;
1085 gint32 num;
1086 size_t len;
1087
1088 g_return_val_if_fail (request != NULL, -2);
1089 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1090 g_return_val_if_fail (request->datafd != NULL, -2);
1091
1092 params = request->protocol_data;
1093 if (request->directory != directory)
1094 {
1095 if (*directory == '/')
1096 {
1097 len = strlen (directory) + 8;
1098 tempstr = g_malloc (len + 1);
1099 strcpy (tempstr + 8, directory);
1100 }
1101 else
1102 {
1103 len = strlen (directory) + strlen (request->directory) + 9;
1104 tempstr = g_malloc (len + 1);
1105 strcpy (tempstr + 8, request->directory);
1106 strcat (tempstr + 8, "/");
1107 strcat (tempstr + 8, directory);
1108 }
1109
1110 num = htonl (params->id++);
1111 memcpy (tempstr, &num, 4);
1112
1113 num = htonl (len - 8);
1114 memcpy (tempstr + 4, &num, 4);
1115 if (sshv2_send_command (request, SSH_FXP_REALPATH, tempstr, len) < 0)
1116 {
1117 g_free (tempstr);
1118 return (-2);
1119 }
1120 g_free (tempstr);
1121
1122 memset (&message, 0, sizeof (message));
1123 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_NAME)
1124 {
1125 request->logging_function (gftp_logging_error, request->user_data,
1126 _("Received wrong response from server, disconnecting\n"));
1127 sshv2_message_free (&message);
1128 gftp_disconnect (request);
1129 return (-2);
1130 }
1131
1132 message.pos += 4;
1133 if (sshv2_buffer_get_int32 (request, &message, 1) != 1)
1134 return (-2);
1135
1136 if ((dir = sshv2_buffer_get_string (request, &message)) == NULL)
1137 return (-2);
1138
1139 if (request->directory)
1140 g_free (request->directory);
1141 request->directory = dir;
1142 sshv2_message_free (&message);
1143 }
1144
1145 return (0);
1146 }
1147
1148
1149 static int
1150 sshv2_getcwd (gftp_request * request)
1151 {
1152 sshv2_message message;
1153 sshv2_params * params;
1154 char *tempstr, *dir;
1155 gint32 num;
1156 size_t len;
1157
1158 g_return_val_if_fail (request != NULL, -2);
1159 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1160 g_return_val_if_fail (request->datafd != NULL, -2);
1161
1162 if (request->directory == NULL || *request->directory == '\0')
1163 dir = ".";
1164 else
1165 dir = request->directory;
1166
1167 params = request->protocol_data;
1168 len = strlen (dir);
1169 tempstr = g_malloc (len + 9);
1170 strcpy (tempstr + 8, dir);
1171
1172 num = htonl (params->id++);
1173 memcpy (tempstr, &num, 4);
1174
1175 num = htonl (len);
1176 memcpy (tempstr + 4, &num, 4);
1177 if (sshv2_send_command (request, SSH_FXP_REALPATH, tempstr, len + 8) < 0)
1178 {
1179 g_free (tempstr);
1180 return (-2);
1181 }
1182
1183 g_free (tempstr);
1184 if (request->directory)
1185 {
1186 g_free (request->directory);
1187 request->directory = NULL;
1188 }
1189
1190 memset (&message, 0, sizeof (message));
1191 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_NAME)
1192 {
1193 request->logging_function (gftp_logging_error, request->user_data,
1194 _("Received wrong response from server, disconnecting\n"));
1195 sshv2_message_free (&message);
1196 gftp_disconnect (request);
1197 return (-2);
1198 }
1199
1200 message.pos += 4;
1201 if (sshv2_buffer_get_int32 (request, &message, 1) < 0)
1202 return (-2);
1203
1204 if ((request->directory = sshv2_buffer_get_string (request, &message)) == NULL)
1205 return (-2);
1206 sshv2_message_free (&message);
1207 return (0);
1208 }
1209
1210
1211 static int
1212 sshv2_rmdir (gftp_request * request, const char *directory)
1213 {
1214 sshv2_params * params;
1215 sshv2_message message;
1216 char *tempstr;
1217 gint32 num;
1218 size_t len;
1219
1220 g_return_val_if_fail (request != NULL, -2);
1221 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1222 g_return_val_if_fail (request->datafd != NULL, -2);
1223 g_return_val_if_fail (directory != NULL, -2);
1224
1225 params = request->protocol_data;
1226
1227 if (*directory == '/')
1228 {
1229 len = strlen (directory) + 8;
1230 tempstr = g_malloc (len + 1);
1231 strcpy (tempstr + 8, directory);
1232 }
1233 else
1234 {
1235 len = strlen (directory) + strlen (request->directory) + 9;
1236 tempstr = g_malloc (len + 1);
1237 strcpy (tempstr + 8, request->directory);
1238 strcat (tempstr + 8, "/");
1239 strcat (tempstr + 8, directory);
1240 }
1241
1242 num = htonl (params->id++);
1243 memcpy (tempstr, &num, 4);
1244
1245 num = htonl (len - 8);
1246 memcpy (tempstr + 4, &num, 4);
1247
1248 if (sshv2_send_command (request, SSH_FXP_RMDIR, tempstr, len) < 0)
1249 {
1250 g_free (tempstr);
1251 return (-2);
1252 }
1253 g_free (tempstr);
1254
1255 memset (&message, 0, sizeof (message));
1256 if (sshv2_read_response (request, &message, NULL) < 0)
1257 return (-2);
1258
1259 message.pos += 4;
1260 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0)
1261 return (-2);
1262
1263 sshv2_message_free (&message);
1264
1265 return (0);
1266 }
1267
1268
1269 static int
1270 sshv2_rmfile (gftp_request * request, const char *file)
1271 {
1272 sshv2_params * params;
1273 sshv2_message message;
1274 char *tempstr;
1275 gint32 num;
1276 size_t len;
1277
1278 g_return_val_if_fail (request != NULL, -2);
1279 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1280 g_return_val_if_fail (request->datafd != NULL, -2);
1281 g_return_val_if_fail (file != NULL, -2);
1282
1283 params = request->protocol_data;
1284
1285 if (*file == '/')
1286 {
1287 len = strlen (file) + 8;
1288 tempstr = g_malloc (len + 1);
1289 strcpy (tempstr + 8, file);
1290 }
1291 else
1292 {
1293 len = strlen (file) + strlen (request->directory) + 9;
1294 tempstr = g_malloc (len + 1);
1295 strcpy (tempstr + 8, request->directory);
1296 strcat (tempstr + 8, "/");
1297 strcat (tempstr + 8, file);
1298 }
1299
1300 num = htonl (params->id++);
1301 memcpy (tempstr, &num, 4);
1302
1303 num = htonl (len - 8);
1304 memcpy (tempstr + 4, &num, 4);
1305
1306 if (sshv2_send_command (request, SSH_FXP_REMOVE, tempstr, len) < 0)
1307 {
1308 g_free (tempstr);
1309 return (-2);
1310 }
1311 g_free (tempstr);
1312
1313 memset (&message, 0, sizeof (message));
1314 if (sshv2_read_response (request, &message, NULL) < 0)
1315 return (-2);
1316
1317 message.pos += 4;
1318 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0)
1319 return (-2);
1320
1321 sshv2_message_free (&message);
1322
1323 return (0);
1324 }
1325
1326
1327 static int
1328 sshv2_chmod (gftp_request * request, const char *file, int mode)
1329 {
1330 char *tempstr, buf[10];
1331 sshv2_params * params;
1332 sshv2_message message;
1333 gint32 num;
1334 size_t len;
1335
1336 g_return_val_if_fail (request != NULL, -2);
1337 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1338 g_return_val_if_fail (request->datafd != NULL, -2);
1339 g_return_val_if_fail (file != NULL, -2);
1340
1341 params = request->protocol_data;
1342
1343 if (*file == '/')
1344 {
1345 len = strlen (file) + 16;
1346 tempstr = g_malloc (len + 1);
1347 strcpy (tempstr + 8, file);
1348 }
1349 else
1350 {
1351 len = strlen (file) + strlen (request->directory) + 17;
1352 tempstr = g_malloc (len + 1);
1353 strcpy (tempstr + 8, request->directory);
1354 strcat (tempstr + 8, "/");
1355 strcat (tempstr + 8, file);
1356 }
1357
1358 num = htonl (params->id++);
1359 memcpy (tempstr, &num, 4);
1360
1361 num = htonl (len - 16);
1362 memcpy (tempstr + 4, &num, 4);
1363
1364 num = htonl (SSH_FILEXFER_ATTR_PERMISSIONS);
1365 memcpy (tempstr + len - 8, &num, 4);
1366
1367 g_snprintf (buf, sizeof (buf), "%d", mode);
1368 num = htonl (strtol (buf, NULL, 8));
1369 memcpy (tempstr + len - 4, &num, 4);
1370
1371 if (sshv2_send_command (request, SSH_FXP_SETSTAT, tempstr, len) < 0)
1372 {
1373 g_free (tempstr);
1374 return (-2);
1375 }
1376 g_free (tempstr);
1377
1378 memset (&message, 0, sizeof (message));
1379 if (sshv2_read_response (request, &message, NULL) < 0)
1380 return (-2);
1381
1382 message.pos += 4;
1383 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0)
1384 return (-2);
1385
1386 sshv2_message_free (&message);
1387
1388 return (0);
1389 }
1390
1391
1392 static int
1393 sshv2_mkdir (gftp_request * request, const char *newdir)
1394 {
1395 sshv2_params * params;
1396 sshv2_message message;
1397 char *tempstr;
1398 gint32 num;
1399 size_t len;
1400
1401 g_return_val_if_fail (request != NULL, -2);
1402 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1403 g_return_val_if_fail (request->datafd != NULL, -2);
1404 g_return_val_if_fail (newdir != NULL, -2);
1405
1406 params = request->protocol_data;
1407
1408 if (*newdir == '/')
1409 {
1410 len = strlen (newdir) + 12;
1411 tempstr = g_malloc (len + 1);
1412 strcpy (tempstr + 8, newdir);
1413 }
1414 else
1415 {
1416 len = strlen (newdir) + strlen (request->directory) + 13;
1417 tempstr = g_malloc (len + 1);
1418 strcpy (tempstr + 8, request->directory);
1419 strcat (tempstr + 8, "/");
1420 strcat (tempstr + 8, newdir);
1421 }
1422
1423 num = htonl (params->id++);
1424 memcpy (tempstr, &num, 4);
1425
1426 num = htonl (len - 12);
1427 memcpy (tempstr + 4, &num, 4);
1428 memset (tempstr + len - 4, 0, 4); /* attributes */
1429
1430 if (sshv2_send_command (request, SSH_FXP_MKDIR, tempstr, len) < 0)
1431 {
1432 g_free (tempstr);
1433 return (-2);
1434 }
1435 g_free (tempstr);
1436
1437 memset (&message, 0, sizeof (message));
1438 if (sshv2_read_response (request, &message, NULL) < 0)
1439 return (-2);
1440
1441 message.pos += 4;
1442 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0)
1443 return (-2);
1444
1445 sshv2_message_free (&message);
1446
1447 return (0);
1448 }
1449
1450
1451 static int
1452 sshv2_rename (gftp_request * request, const char *oldname, const char *newname)
1453 {
1454 char *tempstr, *oldstr, *newstr;
1455 sshv2_params * params;
1456 sshv2_message message;
1457 gint32 num;
1458 size_t oldlen, newlen;
1459
1460 g_return_val_if_fail (request != NULL, -2);
1461 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1462 g_return_val_if_fail (request->datafd != NULL, -2);
1463 g_return_val_if_fail (oldname != NULL, -2);
1464 g_return_val_if_fail (newname != NULL, -2);
1465
1466 params = request->protocol_data;
1467
1468 if (*oldname == '/')
1469 {
1470 oldlen = strlen (oldname);
1471 oldstr = g_strconcat (oldname, NULL);
1472 }
1473 else
1474 {
1475 oldlen = strlen (request->directory) + strlen (oldname) + 1;
1476 oldstr = g_strconcat (request->directory, "/", oldname, NULL);
1477 }
1478
1479 if (*newname == '/')
1480 {
1481 newlen = strlen (newname);
1482 newstr = g_strconcat (newname, NULL);
1483 }
1484 else
1485 {
1486 newlen = strlen (request->directory) + strlen (newname) + 1;
1487 newstr = g_strconcat (request->directory, "/", newname, NULL);
1488 }
1489
1490 tempstr = g_malloc (oldlen + newlen + 13);
1491 num = htonl (params->id++);
1492 memcpy (tempstr, &num, 4);
1493
1494 num = htonl (oldlen);
1495 memcpy (tempstr + 4, &num, 4);
1496 strcpy (tempstr + 8, oldstr);
1497
1498 num = htonl (newlen);
1499 memcpy (tempstr + 8 + oldlen, &num, 4);
1500 strcpy (tempstr + 12 + oldlen, newstr);
1501
1502 if (sshv2_send_command (request, SSH_FXP_RENAME, tempstr, oldlen + newlen + 12) < 0)
1503 {
1504 g_free (tempstr);
1505 return (-2);
1506 }
1507 g_free (tempstr);
1508
1509 memset (&message, 0, sizeof (message));
1510 if (sshv2_read_response (request, &message, NULL) < 0)
1511 return (-2);
1512
1513 message.pos += 4;
1514 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0)
1515 return (-2);
1516
1517 sshv2_message_free (&message);
1518
1519 return (0);
1520 }
1521
1522
1523 static int
1524 sshv2_set_file_time (gftp_request * request, const char *file, time_t datetime)
1525 {
1526 sshv2_params * params;
1527 sshv2_message message;
1528 char *tempstr;
1529 gint32 num;
1530 size_t len;
1531
1532 g_return_val_if_fail (request != NULL, -2);
1533 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1534 g_return_val_if_fail (request->datafd != NULL, -2);
1535 g_return_val_if_fail (file != NULL, -2);
1536
1537 params = request->protocol_data;
1538
1539 if (*file == '/')
1540 {
1541 len = strlen (file) + 20;
1542 tempstr = g_malloc (len + 1);
1543 strcpy (tempstr + 8, file);
1544 }
1545 else
1546 {
1547 len = strlen (file) + strlen (request->directory) + 21;
1548 tempstr = g_malloc (len + 1);
1549 strcpy (tempstr + 8, request->directory);
1550 strcat (tempstr + 8, "/");
1551 strcat (tempstr + 8, file);
1552 }
1553
1554 num = htonl (params->id++);
1555 memcpy (tempstr, &num, 4);
1556
1557 num = htonl (len - 20);
1558 memcpy (tempstr + 4, &num, 4);
1559
1560 num = htonl (SSH_FILEXFER_ATTR_ACMODTIME);
1561 memcpy (tempstr + len - 12, &num, 4);
1562
1563 num = htonl (datetime);
1564 memcpy (tempstr + len - 8, &num, 4);
1565
1566 num = htonl (datetime);
1567 memcpy (tempstr + len - 4, &num, 4);
1568
1569 if (sshv2_send_command (request, SSH_FXP_SETSTAT, tempstr, len) < 0)
1570 {
1571 g_free (tempstr);
1572 return (-2);
1573 }
1574 g_free (tempstr);
1575
1576 memset (&message, 0, sizeof (message));
1577 if (sshv2_read_response (request, &message, NULL) < 0)
1578 return (-2);
1579
1580 message.pos += 4;
1581 if (sshv2_buffer_get_int32 (request, &message, SSH_FX_OK) < 0)
1582 return (-2);
1583
1584 sshv2_message_free (&message);
1585
1586 return (0);
1587 }
1588
1589
1590 static off_t
1591 sshv2_get_file_size (gftp_request * request, const char *file)
1592 {
1593 gint32 len, highnum, lownum, attrs, num;
1594 sshv2_params * params;
1595 char *tempstr;
1596 #ifdef G_HAVE_GINT64
1597 gint64 ret;
1598 #endif
1599
1600 g_return_val_if_fail (request != NULL, -2);
1601 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1602 g_return_val_if_fail (request->datafd != NULL, -2);
1603 g_return_val_if_fail (file != NULL, -2);
1604
1605 params = request->protocol_data;
1606
1607 if (*file == '/')
1608 {
1609 len = strlen (file);
1610 tempstr = g_malloc (len + 9);
1611 strcpy (tempstr + 8, file);
1612 }
1613 else
1614 {
1615 len = strlen (file) + strlen (request->directory) + 1;
1616 tempstr = g_malloc (len + 9);
1617 strcpy (tempstr + 8, request->directory);
1618 strcat (tempstr + 8, "/");
1619 strcat (tempstr + 8, file);
1620 }
1621
1622 num = htonl (params->id++);
1623 memcpy (tempstr, &num, 4);
1624
1625 num = htonl (len);
1626 memcpy (tempstr + 4, &num, 4);
1627
1628 if (sshv2_send_command (request, SSH_FXP_STAT, tempstr, len + 8) < 0)
1629 {
1630 g_free (tempstr);
1631 return (-2);
1632 }
1633 g_free (tempstr);
1634
1635 memset (&params->message, 0, sizeof (params->message));
1636 if (sshv2_read_response (request, &params->message, NULL) != SSH_FXP_ATTRS)
1637 {
1638 request->logging_function (gftp_logging_error, request->user_data,
1639 _("Received wrong response from server, disconnecting\n"));
1640 sshv2_message_free (&params->message);
1641 gftp_disconnect (request);
1642 return (-2);
1643 }
1644
1645 if (params->message.length < 5)
1646 return (-2);
1647 params->message.pos += 4;
1648
1649 if ((attrs = sshv2_buffer_get_int32 (request, &params->message, -1)) < 0)
1650 return (-2);
1651
1652 if (attrs & SSH_FILEXFER_ATTR_SIZE)
1653 {
1654 if ((highnum = sshv2_buffer_get_int32 (request, &params->message, -1)) < 0)
1655 return (-2);
1656
1657 if ((lownum = sshv2_buffer_get_int32 (request, &params->message, -1)) < 0)
1658 return (-2);
1659
1660 sshv2_message_free (&params->message);
1661
1662 #if G_HAVE_GINT64
1663 ret = (gint64) lownum | ((gint64) highnum >> 32);
1664 return (ret);
1665 #else
1666 return (lownum);
1667 #endif
1668 }
1669
1670 sshv2_message_free (&params->message);
1671
1672 return (0);
1673
1674 }
1675
1676
1677 static long
1678 sshv2_get_file (gftp_request * request, const char *file, FILE * fd,
1679 off_t startsize)
1680 {
1681 sshv2_params * params;
1682 sshv2_message message;
1683 char *tempstr;
1684 size_t stlen;
1685 gint32 num;
1686
1687 g_return_val_if_fail (request != NULL, -2);
1688 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1689 g_return_val_if_fail (request->sockfd != NULL, -2);
1690 /* fd ignored for this protocol */
1691
1692 params = request->protocol_data;
1693 params->offset = startsize;
1694
1695 if (*file == '/')
1696 {
1697 stlen = strlen (file);
1698 tempstr = g_malloc (stlen + 16);
1699 strcpy (tempstr + 8, file);
1700 }
1701 else
1702 {
1703 stlen = strlen (file) + strlen (request->directory) + 1;
1704 tempstr = g_malloc (stlen + 16);
1705 strcpy (tempstr + 8, request->directory);
1706 strcat (tempstr + 8, "/");
1707 strcat (tempstr + 8, file);
1708 }
1709
1710 num = htonl (params->id++);
1711 memcpy (tempstr, &num, 4);
1712
1713 num = htonl (stlen);
1714 memcpy (tempstr + 4, &num, 4);
1715
1716 num = htonl (SSH_FXF_READ);
1717 memcpy (tempstr + 8 + stlen, &num, 4);
1718
1719 memset (tempstr + 12 + stlen, 0, 4);
1720
1721 if (sshv2_send_command (request, SSH_FXP_OPEN, tempstr, stlen + 16) < 0)
1722 {
1723 g_free (tempstr);
1724 return (-2);
1725 }
1726
1727 g_free (tempstr);
1728 memset (&message, 0, sizeof (message));
1729 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_HANDLE)
1730 {
1731 request->logging_function (gftp_logging_error, request->user_data,
1732 _("Received wrong response from server, disconnecting\n"));
1733 sshv2_message_free (&message);
1734 gftp_disconnect (request);
1735 return (-2);
1736 }
1737
1738 if (message.length - 4 > SSH_MAX_HANDLE_SIZE)
1739 {
1740 request->logging_function (gftp_logging_error, request->user_data,
1741 _("Error: Message size %d too big from server\n"),
1742 message.length - 4);
1743 sshv2_message_free (&message);
1744 gftp_disconnect (request);
1745 return (-1);
1746
1747 }
1748
1749 memset (params->handle, 0, 4);
1750 memcpy (params->handle + 4, message.buffer+ 4, message.length - 5);
1751 params->handle_len = message.length - 1;
1752 sshv2_message_free (&message);
1753
1754 return (sshv2_get_file_size (request, file));
1755 }
1756
1757
1758 static int
1759 sshv2_put_file (gftp_request * request, const char *file, FILE * fd,
1760 off_t startsize, off_t totalsize)
1761 {
1762 sshv2_params * params;
1763 sshv2_message message;
1764 char *tempstr;
1765 size_t stlen;
1766 gint32 num;
1767
1768 g_return_val_if_fail (request != NULL, -2);
1769 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1770 g_return_val_if_fail (request->sockfd != NULL, -2);
1771 /* fd ignored for this protocol */
1772
1773 params = request->protocol_data;
1774 params->offset = 0;
1775
1776 if (*file == '/')
1777 {
1778 stlen = strlen (file);
1779 tempstr = g_malloc (stlen + 16);
1780 strcpy (tempstr + 8, file);
1781 }
1782 else
1783 {
1784 stlen = strlen (file) + strlen (request->directory) + 1;
1785 tempstr = g_malloc (stlen + 16);
1786 strcpy (tempstr + 8, request->directory);
1787 strcat (tempstr + 8, "/");
1788 strcat (tempstr + 8, file);
1789 }
1790
1791 num = htonl (params->id++);
1792 memcpy (tempstr, &num, 4);
1793
1794 num = htonl (stlen);
1795 memcpy (tempstr + 4, &num, 4);
1796
1797 if (startsize > 0)
1798 num = htonl (SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_APPEND);
1799 else
1800 num = htonl (SSH_FXF_WRITE | SSH_FXF_CREAT | SSH_FXF_TRUNC);
1801 memcpy (tempstr + 8 + stlen, &num, 4);
1802
1803 memset (tempstr + 12 + stlen, 0, 4);
1804
1805 if (sshv2_send_command (request, SSH_FXP_OPEN, tempstr, stlen + 16) < 0)
1806 {
1807 g_free (tempstr);
1808 return (-2);
1809 }
1810
1811 g_free (tempstr);
1812 memset (&message, 0, sizeof (message));
1813 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_HANDLE)
1814 {
1815 request->logging_function (gftp_logging_error, request->user_data,
1816 _("Received wrong response from server, disconnecting\n"));
1817 sshv2_message_free (&message);
1818 gftp_disconnect (request);
1819 return (-2);
1820 }
1821
1822 if (message.length - 4 > SSH_MAX_HANDLE_SIZE)
1823 {
1824 request->logging_function (gftp_logging_error, request->user_data,
1825 _("Error: Message size %d too big from server\n"),
1826 message.length - 4);
1827 sshv2_message_free (&message);
1828 gftp_disconnect (request);
1829 return (-1);
1830
1831 }
1832
1833 memset (params->handle, 0, 4);
1834 memcpy (params->handle + 4, message.buffer+ 4, message.length - 5);
1835 params->handle_len = message.length - 1;
1836 sshv2_message_free (&message);
1837
1838 return (0);
1839 }
1840
1841
1842 static size_t
1843 sshv2_get_next_file_chunk (gftp_request * request, char *buf, size_t size)
1844 {
1845 sshv2_params * params;
1846 sshv2_message message;
1847 gint32 num;
1848
1849 #ifdef G_HAVE_GINT64
1850 gint64 offset;
1851 #else
1852 gint32 offset;
1853 #endif
1854
1855 g_return_val_if_fail (request != NULL, -2);
1856 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1857 g_return_val_if_fail (request->sockfd != NULL, -2);
1858 g_return_val_if_fail (buf != NULL, -2);
1859
1860 params = request->protocol_data;
1861
1862 if (params->read_buffer == NULL)
1863 {
1864 params->read_buffer = g_malloc (params->handle_len + 12);
1865 num = htonl (params->handle_len);
1866 memcpy (params->read_buffer, params->handle, params->handle_len);
1867 }
1868
1869 num = htonl (params->id++);
1870 memcpy (params->read_buffer, &num, 4);
1871
1872 #ifdef G_HAVE_GINT64
1873 offset = hton64 (params->offset);
1874 memcpy (params->read_buffer + params->handle_len, &offset, 8);
1875 #else
1876 memset (params->read_buffer + params->handle_len, 0, 4);
1877 offset = htonl (params->offset);
1878 memcpy (params->read_buffer + params->handle_len + 4, &offset, 4);
1879 #endif
1880
1881 num = htonl (size);
1882 memcpy (params->read_buffer + params->handle_len + 8, &num, 4);
1883
1884 if (sshv2_send_command (request, SSH_FXP_READ, params->read_buffer, params->handle_len + 12) < 0)
1885 return (-2);
1886
1887 memset (&message, 0, sizeof (message));
1888 if (sshv2_read_response (request, &message, NULL) != SSH_FXP_DATA)
1889 {
1890 message.pos += 4;
1891 if ((num = sshv2_buffer_get_int32 (request, &message, SSH_FX_OK)) < 0)
1892 return (-2);
1893 sshv2_message_free (&message);
1894 if (num != SSH_FX_EOF)
1895 {
1896 request->logging_function (gftp_logging_error, request->user_data,
1897 _("Received wrong response from server, disconnecting\n"));
1898 gftp_disconnect (request);
1899 return (-2);
1900 }
1901 return (0);
1902 }
1903
1904 memcpy (&num, message.buffer + 4, 4);
1905 num = ntohl (num);
1906 if (num > size)
1907 {
1908 request->logging_function (gftp_logging_error, request->user_data,
1909 _("Error: Message size %d too big from server\n"),
1910 num);
1911 sshv2_message_free (&message);
1912 gftp_disconnect (request);
1913 return (-1);
1914
1915 }
1916
1917 memcpy (buf, message.buffer + 8, num);
1918 sshv2_message_free (&message);
1919 params->offset += num;
1920 return (num);
1921 }
1922
1923
1924 static size_t
1925 sshv2_put_next_file_chunk (gftp_request * request, char *buf, size_t size)
1926 {
1927 sshv2_params * params;
1928 sshv2_message message;
1929 char tempstr[32768];
1930 gint32 num;
1931 int ret;
1932
1933 #ifdef G_HAVE_GINT64
1934 gint64 offset;
1935 #else
1936 gint32 offset;
1937 #endif
1938
1939 g_return_val_if_fail (request != NULL, -2);
1940 g_return_val_if_fail (request->protonum == GFTP_SSHV2_NUM, -2);
1941 g_return_val_if_fail (request->sockfd != NULL, -2);
1942 g_return_val_if_fail (buf != NULL, -2);
1943 g_return_val_if_fail (size <= 32500, -2);
1944
1945 params = request->protocol_data;
1946
1947 num = htonl (params->handle_len);
1948 memcpy (tempstr, params->handle, params->handle_len);
1949
1950 num = htonl (params->id++);
1951 memcpy (tempstr, &num, 4);
1952
1953 #ifdef G_HAVE_GINT64
1954 offset = hton64 (params->offset);
1955 memcpy (tempstr + params->handle_len, &offset, 8);
1956 #else
1957 memset (tempstr + params->handle_len, 0, 4);
1958 offset = htonl (params->offset);
1959 memcpy (tempstr + params->handle_len + 4, &offset, 4);
1960 #endif
1961
1962 num = htonl (size);
1963 memcpy (tempstr + params->handle_len + 8, &num, 4);
1964 memcpy (tempstr + params->handle_len + 12, buf, size);
1965
1966 if (sshv2_send_command (request, SSH_FXP_WRITE, tempstr, params->handle_len + size + 12) < 0)
1967 {
1968 g_free (tempstr);
1969 return (-2);
1970 }
1971
1972 memset (&message, 0, sizeof (message));
1973 params->dont_log_status = 1;
1974 ret = sshv2_read_response (request, &message, NULL);
1975 params->dont_log_status = 0;
1976 if (ret != SSH_FXP_STATUS)
1977 {
1978 request->logging_function (gftp_logging_error, request->user_data,
1979 _("Received wrong response from server, disconnecting\n"));
1980 sshv2_message_free (&message);
1981 gftp_disconnect (request);
1982 return (-2);
1983 }
1984
1985 message.pos += 4;
1986 if ((num = sshv2_buffer_get_int32 (request, &message, SSH_FX_OK)) < 0)
1987 return (-2);
1988 sshv2_message_free (&message);
1989
1990 if (num == SSH_FX_EOF)
1991 return (0);
1992 else if (num != SSH_FX_OK)
1993 return (-1);
1994
1995 params->offset += size;
1996 return (size);
1997 }
1998