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