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