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