Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/ttssh2/ttxssh/sftp.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9048 - (show annotations) (download) (as text)
Wed Dec 16 12:24:13 2020 UTC (3 years, 3 months ago) by nmaya
File MIME type: text/x-csrc
File size: 31968 byte(s)
ソースファイルの著作権表記の "最後の発行の年" を削除

ticket #40996
1 /*
2 * (C) 2008- TeraTerm Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "ttxssh.h"
30 #include "util.h"
31 #include "resource.h"
32
33 #include <openssl/bn.h>
34 #include <openssl/evp.h>
35 #include <openssl/dh.h>
36 #include <openssl/engine.h>
37 #include <openssl/rsa.h>
38 #include <openssl/dsa.h>
39 #include <limits.h>
40 #include <malloc.h>
41 #include <string.h>
42 #include <stdlib.h>
43 #include <process.h>
44 #include <time.h>
45 #include "buffer.h"
46 #include "ssh.h"
47 #include "crypt.h"
48 #include "fwd.h"
49 #include "ssh.h"
50 #include "sftp.h"
51
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <assert.h>
55
56
57 #define WM_USER_CONSOLE (WM_USER + 1)
58
59 /* Separators for interactive commands */
60 #define WHITESPACE " \t\r\n"
61
62 /* Commands for interactive mode */
63 #define I_CHDIR 1
64 #define I_CHGRP 2
65 #define I_CHMOD 3
66 #define I_CHOWN 4
67 #define I_DF 24
68 #define I_GET 5
69 #define I_HELP 6
70 #define I_LCHDIR 7
71 #define I_LINK 25
72 #define I_LLS 8
73 #define I_LMKDIR 9
74 #define I_LPWD 10
75 #define I_LS 11
76 #define I_LUMASK 12
77 #define I_MKDIR 13
78 #define I_PUT 14
79 #define I_PWD 15
80 #define I_QUIT 16
81 #define I_RENAME 17
82 #define I_RM 18
83 #define I_RMDIR 19
84 #define I_SHELL 20
85 #define I_SYMLINK 21
86 #define I_VERSION 22
87 #define I_PROGRESS 23
88
89 /* Type of completion */
90 #define NOARGS 0
91 #define REMOTE 1
92 #define LOCAL 2
93
94 struct CMD {
95 char *c;
96 int n;
97 int t;
98 };
99
100 static const struct CMD cmds[] = {
101 { "bye", I_QUIT, NOARGS },
102 { "cd", I_CHDIR, REMOTE },
103 { "chdir", I_CHDIR, REMOTE },
104 { "chgrp", I_CHGRP, REMOTE },
105 { "chmod", I_CHMOD, REMOTE },
106 { "chown", I_CHOWN, REMOTE },
107 { "df", I_DF, REMOTE },
108 { "dir", I_LS, REMOTE },
109 { "exit", I_QUIT, NOARGS },
110 { "get", I_GET, REMOTE },
111 { "help", I_HELP, NOARGS },
112 { "lcd", I_LCHDIR, LOCAL },
113 { "lchdir", I_LCHDIR, LOCAL },
114 { "lls", I_LLS, LOCAL },
115 { "lmkdir", I_LMKDIR, LOCAL },
116 { "ln", I_LINK, REMOTE },
117 { "lpwd", I_LPWD, LOCAL },
118 { "ls", I_LS, REMOTE },
119 { "lumask", I_LUMASK, NOARGS },
120 { "mkdir", I_MKDIR, REMOTE },
121 { "mget", I_GET, REMOTE },
122 { "mput", I_PUT, LOCAL },
123 { "progress", I_PROGRESS, NOARGS },
124 { "put", I_PUT, LOCAL },
125 { "pwd", I_PWD, REMOTE },
126 { "quit", I_QUIT, NOARGS },
127 { "rename", I_RENAME, REMOTE },
128 { "rm", I_RM, REMOTE },
129 { "rmdir", I_RMDIR, REMOTE },
130 { "symlink", I_SYMLINK, REMOTE },
131 { "version", I_VERSION, NOARGS },
132 { "!", I_SHELL, NOARGS },
133 { "?", I_HELP, NOARGS },
134 { NULL, -1, -1 }
135 };
136
137
138
139 static PTInstVar g_pvar;
140 static Channel_t *g_channel;
141
142 static void sftp_console_message(PTInstVar pvar, Channel_t *c, char *fmt, ...)
143 {
144 char tmp[1024];
145 va_list arg;
146
147 va_start(arg, fmt);
148 _vsnprintf_s(tmp, sizeof(tmp), _TRUNCATE, fmt, arg);
149 va_end(arg);
150
151 SendMessage(c->sftp.console_window, WM_USER_CONSOLE, 0, (LPARAM)tmp);
152 logputs(LOG_LEVEL_VERBOSE, tmp);
153 }
154
155 #define sftp_do_syslog(pvar, level, ...) logprintf(level, __VA_ARGS__)
156 #define sftp_syslog(pvar, ...) logprintf(LOG_LEVEL_VERBOSE, __VA_ARGS__)
157
158 // SFTP���p�o�b�t�@���m�������BSCP�����������A�������������f�[�^�T�C�Y�����������B
159 //
160 // buffer_t
161 // +---------+------------------------------------+
162 // | msg_len | data |
163 // +---------+------------------------------------+
164 // 4byte <------------- msg_len ------------->
165 //
166 static void sftp_buffer_alloc(buffer_t **message)
167 {
168 buffer_t *msg;
169
170 msg = buffer_init();
171 if (msg == NULL) {
172 goto error;
173 }
174 // Message length(4byte)
175 buffer_put_int(msg, 0);
176
177 *message = msg;
178
179 error:
180 assert(msg != NULL);
181 return;
182 }
183
184 static void sftp_buffer_free(buffer_t *message)
185 {
186 buffer_free(message);
187 }
188
189 // �T�[�o��SFTP�p�P�b�g�����M�����B
190 static void sftp_send_msg(PTInstVar pvar, Channel_t *c, buffer_t *msg)
191 {
192 char *p;
193 int len;
194
195 len = buffer_len(msg);
196 p = buffer_ptr(msg);
197 // ���������b�Z�[�W�T�C�Y���i�[�����B
198 set_uint32(p, len - 4);
199 // �y�C���[�h�����M�B
200 SSH2_send_channel_data(pvar, c, p, len, 0);
201 }
202
203 // �T�[�o�������M����SFTP�p�P�b�g���o�b�t�@���i�[�����B
204 static void sftp_get_msg(PTInstVar pvar, Channel_t *c, unsigned char *data, unsigned int buflen, buffer_t **message)
205 {
206 buffer_t *msg = *message;
207 int msg_len;
208
209 // �o�b�t�@���m�����A�f�[�^�����������������B���~�� buffer_t �^�����������������B
210 // �������������� OpenSSH ���R�[�h�����e�a�����������������B
211 buffer_clear(msg);
212 buffer_append(msg, data, buflen);
213 buffer_rewind(msg);
214
215 msg_len = buffer_get_int(msg);
216 if (msg_len > SFTP_MAX_MSG_LENGTH) {
217 // TODO:
218 sftp_syslog(pvar, "Received message too long %u", msg_len);
219 goto error;
220 }
221 if (msg_len + 4 != buflen) {
222 // TODO:
223 sftp_syslog(pvar, "Buffer length %u is invalid", buflen);
224 goto error;
225 }
226
227 error:
228 return;
229 }
230
231 static void sftp_send_string_request(PTInstVar pvar, Channel_t *c, unsigned int id, unsigned int code,
232 char *s, unsigned int len)
233 {
234 buffer_t *msg;
235
236 sftp_buffer_alloc(&msg);
237 buffer_put_char(msg, code);
238 buffer_put_int(msg, id);
239 buffer_put_string(msg, s, len);
240 sftp_send_msg(pvar, c, msg);
241 sftp_syslog(pvar, "Sent message fd %d T:%u I:%u", c->remote_id, code, id);
242 sftp_buffer_free(msg);
243 }
244
245
246 // SFTP���M�J�n�O���l�S�V�G�[�V����
247 // based on do_init()#sftp-client.c(OpenSSH 6.0)
248 void sftp_do_init(PTInstVar pvar, Channel_t *c)
249 {
250 buffer_t *msg;
251
252 // SFTP�����\������������
253 memset(&c->sftp, 0, sizeof(c->sftp));
254 c->sftp.state = SFTP_INIT;
255 c->sftp.transfer_buflen = DEFAULT_COPY_BUFLEN;
256 c->sftp.num_requests = DEFAULT_NUM_REQUESTS;
257 c->sftp.exts = 0;
258 c->sftp.limit_kbps = 0;
259
260 // �l�S�V�G�[�V�������J�n
261 sftp_buffer_alloc(&msg);
262 buffer_put_char(msg, SSH2_FXP_INIT);
263 buffer_put_int(msg, SSH2_FILEXFER_VERSION);
264 sftp_send_msg(pvar, c, msg);
265 sftp_buffer_free(msg);
266
267 sftp_syslog(pvar, "SFTP client version %u", SSH2_FILEXFER_VERSION);
268 }
269
270 static void sftp_do_init_recv(PTInstVar pvar, Channel_t *c, buffer_t *msg)
271 {
272 unsigned int type;
273
274 type = buffer_get_char(msg);
275 if (type != SSH2_FXP_VERSION) {
276 goto error;
277 }
278 c->sftp.version = buffer_get_int(msg);
279 sftp_syslog(pvar, "SFTP server version %u, remote version %u", type, c->sftp.version);
280
281 while (buffer_remain_len(msg) > 0) {
282 char *name = buffer_get_string_msg(msg, NULL);
283 char *value = buffer_get_string_msg(msg, NULL);
284 int known = 0;
285
286 if (strcmp(name, "posix-rename@openssh.com") == 0 &&
287 strcmp(value, "1") == 0) {
288 c->sftp.exts |= SFTP_EXT_POSIX_RENAME;
289 known = 1;
290 } else if (strcmp(name, "statvfs@openssh.com") == 0 &&
291 strcmp(value, "2") == 0) {
292 c->sftp.exts |= SFTP_EXT_STATVFS;
293 known = 1;
294 } else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
295 strcmp(value, "2") == 0) {
296 c->sftp.exts |= SFTP_EXT_FSTATVFS;
297 known = 1;
298 } else if (strcmp(name, "hardlink@openssh.com") == 0 &&
299 strcmp(value, "1") == 0) {
300 c->sftp.exts |= SFTP_EXT_HARDLINK;
301 known = 1;
302 }
303 if (known) {
304 sftp_syslog(pvar, "Server supports extension \"%s\" revision %s",
305 name, value);
306 } else {
307 sftp_syslog(pvar, "Unrecognised server extension \"%s\"", name);
308 }
309
310 free(name);
311 free(value);
312 }
313
314 if (c->sftp.version == 0) {
315 c->sftp.transfer_buflen = min(c->sftp.transfer_buflen, 20480);
316 }
317 c->sftp.limit_kbps = 0;
318 if (c->sftp.limit_kbps > 0) {
319 // TODO:
320 }
321
322 sftp_syslog(pvar, "Connected to SFTP server.");
323
324 error:
325 return;
326 }
327
328 // �p�X�����M
329 // based on do_realpath()#sftp-client.c(OpenSSH 6.0)
330 static void sftp_do_realpath(PTInstVar pvar, Channel_t *c, char *path)
331 {
332 unsigned int id;
333
334 strncpy_s(c->sftp.path, sizeof(c->sftp.path), path, _TRUNCATE);
335 id = c->sftp.msg_id++;
336 sftp_send_string_request(pvar, c, id, SSH2_FXP_REALPATH, path, strlen(path));
337 }
338
339 /* Convert from SSH2_FX_ status to text error message */
340 static const char *fx2txt(int status)
341 {
342 switch (status) {
343 case SSH2_FX_OK:
344 return("No error");
345 case SSH2_FX_EOF:
346 return("End of file");
347 case SSH2_FX_NO_SUCH_FILE:
348 return("No such file or directory");
349 case SSH2_FX_PERMISSION_DENIED:
350 return("Permission denied");
351 case SSH2_FX_FAILURE:
352 return("Failure");
353 case SSH2_FX_BAD_MESSAGE:
354 return("Bad message");
355 case SSH2_FX_NO_CONNECTION:
356 return("No connection");
357 case SSH2_FX_CONNECTION_LOST:
358 return("Connection lost");
359 case SSH2_FX_OP_UNSUPPORTED:
360 return("Operation unsupported");
361 default:
362 return("Unknown status");
363 }
364 /* NOTREACHED */
365 }
366
367 static char *sftp_do_realpath_recv(PTInstVar pvar, Channel_t *c, buffer_t *msg)
368 {
369 unsigned int type, expected_id, count, id;
370 char *filename = NULL, *longname;
371
372 type = buffer_get_char(msg);
373 id = buffer_get_int(msg);
374
375 expected_id = c->sftp.msg_id - 1;
376 if (id != expected_id) {
377 sftp_syslog(pvar, "ID mismatch (%u != %u)", id, expected_id);
378 goto error;
379 }
380
381 if (type == SSH2_FXP_STATUS) {
382 unsigned int status = buffer_get_int(msg);
383
384 sftp_syslog(pvar, "Couldn't canonicalise: %s", fx2txt(status));
385 goto error;
386 } else if (type != SSH2_FXP_NAME) {
387 sftp_syslog(pvar, "Expected SSH2_FXP_NAME(%u) packet, got %u",
388 SSH2_FXP_NAME, type);
389 goto error;
390 }
391
392 count = buffer_get_int(msg);
393 if (count != 1) {
394 sftp_syslog(pvar, "Got multiple names (%d) from SSH_FXP_REALPATH", count);
395 goto error;
396 }
397
398 filename = buffer_get_string_msg(msg, NULL);
399 longname = buffer_get_string_msg(msg, NULL);
400 //a = decode_attrib(&msg);
401
402 sftp_console_message(pvar, c, "SSH_FXP_REALPATH %s -> %s", c->sftp.path, filename);
403
404 free(longname);
405
406 error:
407 return (filename);
408 }
409
410
411 u_int
412 sftp_proto_version(struct sftp *conn)
413 {
414 return conn->version;
415 }
416
417 static void
418 help(void)
419 {
420 sftp_console_message(g_pvar, g_channel,
421 "Available commands:\r\n"
422 "bye Quit sftp\r\n"
423 "cd path Change remote directory to 'path'\r\n"
424 "chgrp grp path Change group of file 'path' to 'grp'\r\n"
425 "chmod mode path Change permissions of file 'path' to 'mode'\r\n"
426 "chown own path Change owner of file 'path' to 'own'\r\n"
427 "df [-hi] [path] Display statistics for current directory or\r\n"
428 " filesystem containing 'path'\r\n"
429 "exit Quit sftp\r\n"
430 "get [-Ppr] remote [local] Download file\r\n"
431 "help Display this help text\r\n"
432 "lcd path Change local directory to 'path'\r\n"
433 "lls [ls-options [path]] Display local directory listing\r\n"
434 "lmkdir path Create local directory\r\n"
435 "ln [-s] oldpath newpath Link remote file (-s for symlink)\r\n"
436 "lpwd Print local working directory\r\n"
437 "ls [-1afhlnrSt] [path] Display remote directory listing\r\n"
438 "lumask umask Set local umask to 'umask'\r\n"
439 "mkdir path Create remote directory\r\n"
440 "progress Toggle display of progress meter\r\n"
441 "put [-Ppr] local [remote] Upload file\r\n"
442 "pwd Display remote working directory\r\n"
443 "quit Quit sftp\r\n"
444 "rename oldpath newpath Rename remote file\r\n"
445 "rm path Delete remote file\r\n"
446 "rmdir path Remove remote directory\r\n"
447 "symlink oldpath newpath Symlink remote file\r\n"
448 "version Show SFTP version\r\n"
449 "!command Execute 'command' in local shell\r\n"
450 "! Escape to local shell\r\n"
451 "? Synonym for help\r\n");
452 }
453
454 /*
455 * Split a string into an argument vector using sh(1)-style quoting,
456 * comment and escaping rules, but with some tweaks to handle glob(3)
457 * wildcards.
458 * The "sloppy" flag allows for recovery from missing terminating quote, for
459 * use in parsing incomplete commandlines during tab autocompletion.
460 *
461 * Returns NULL on error or a NULL-terminated array of arguments.
462 *
463 * If "lastquote" is not NULL, the quoting character used for the last
464 * argument is placed in *lastquote ("\0", "'" or "\"").
465 *
466 * If "terminated" is not NULL, *terminated will be set to 1 when the
467 * last argument's quote has been properly terminated or 0 otherwise.
468 * This parameter is only of use if "sloppy" is set.
469 */
470 #define MAXARGS 128
471 #define MAXARGLEN 8192
472 static char **
473 makeargv(const char *arg, int *argcp, int sloppy, char *lastquote,
474 u_int *terminated)
475 {
476 int argc, quot;
477 size_t i, j;
478 static char argvs[MAXARGLEN];
479 static char *argv[MAXARGS + 1];
480 enum { MA_START, MA_SQUOTE, MA_DQUOTE, MA_UNQUOTED } state, q;
481
482 *argcp = argc = 0;
483 if (strlen(arg) > sizeof(argvs) - 1) {
484 args_too_longs:
485 sftp_syslog(g_pvar, "string too long");
486 return NULL;
487 }
488 if (terminated != NULL)
489 *terminated = 1;
490 if (lastquote != NULL)
491 *lastquote = '\0';
492 state = MA_START;
493 i = j = 0;
494 for (;;) {
495 if (isspace(arg[i])) {
496 if (state == MA_UNQUOTED) {
497 /* Terminate current argument */
498 argvs[j++] = '\0';
499 argc++;
500 state = MA_START;
501 } else if (state != MA_START)
502 argvs[j++] = arg[i];
503 } else if (arg[i] == '"' || arg[i] == '\'') {
504 q = arg[i] == '"' ? MA_DQUOTE : MA_SQUOTE;
505 if (state == MA_START) {
506 argv[argc] = argvs + j;
507 state = q;
508 if (lastquote != NULL)
509 *lastquote = arg[i];
510 } else if (state == MA_UNQUOTED)
511 state = q;
512 else if (state == q)
513 state = MA_UNQUOTED;
514 else
515 argvs[j++] = arg[i];
516 } else if (arg[i] == '\\') {
517 if (state == MA_SQUOTE || state == MA_DQUOTE) {
518 quot = state == MA_SQUOTE ? '\'' : '"';
519 /* Unescape quote we are in */
520 /* XXX support \n and friends? */
521 if (arg[i + 1] == quot) {
522 i++;
523 argvs[j++] = arg[i];
524 } else if (arg[i + 1] == '?' ||
525 arg[i + 1] == '[' || arg[i + 1] == '*') {
526 /*
527 * Special case for sftp: append
528 * double-escaped glob sequence -
529 * glob will undo one level of
530 * escaping. NB. string can grow here.
531 */
532 if (j >= sizeof(argvs) - 5)
533 goto args_too_longs;
534 argvs[j++] = '\\';
535 argvs[j++] = arg[i++];
536 argvs[j++] = '\\';
537 argvs[j++] = arg[i];
538 } else {
539 argvs[j++] = arg[i++];
540 argvs[j++] = arg[i];
541 }
542 } else {
543 if (state == MA_START) {
544 argv[argc] = argvs + j;
545 state = MA_UNQUOTED;
546 if (lastquote != NULL)
547 *lastquote = '\0';
548 }
549 if (arg[i + 1] == '?' || arg[i + 1] == '[' ||
550 arg[i + 1] == '*' || arg[i + 1] == '\\') {
551 /*
552 * Special case for sftp: append
553 * escaped glob sequence -
554 * glob will undo one level of
555 * escaping.
556 */
557 argvs[j++] = arg[i++];
558 argvs[j++] = arg[i];
559 } else {
560 /* Unescape everything */
561 /* XXX support \n and friends? */
562 i++;
563 argvs[j++] = arg[i];
564 }
565 }
566 } else if (arg[i] == '#') {
567 if (state == MA_SQUOTE || state == MA_DQUOTE)
568 argvs[j++] = arg[i];
569 else
570 goto string_done;
571 } else if (arg[i] == '\0') {
572 if (state == MA_SQUOTE || state == MA_DQUOTE) {
573 if (sloppy) {
574 state = MA_UNQUOTED;
575 if (terminated != NULL)
576 *terminated = 0;
577 goto string_done;
578 }
579 sftp_syslog(g_pvar, "Unterminated quoted argument");
580 return NULL;
581 }
582 string_done:
583 if (state == MA_UNQUOTED) {
584 argvs[j++] = '\0';
585 argc++;
586 }
587 break;
588 } else {
589 if (state == MA_START) {
590 argv[argc] = argvs + j;
591 state = MA_UNQUOTED;
592 if (lastquote != NULL)
593 *lastquote = '\0';
594 }
595 if ((state == MA_SQUOTE || state == MA_DQUOTE) &&
596 (arg[i] == '?' || arg[i] == '[' || arg[i] == '*')) {
597 /*
598 * Special case for sftp: escape quoted
599 * glob(3) wildcards. NB. string can grow
600 * here.
601 */
602 if (j >= sizeof(argvs) - 3)
603 goto args_too_longs;
604 argvs[j++] = '\\';
605 argvs[j++] = arg[i];
606 } else
607 argvs[j++] = arg[i];
608 }
609 i++;
610 }
611 *argcp = argc;
612 return argv;
613 }
614
615 static int parse_args(const char **cpp, int *pflag, int *rflag, int *lflag, int *iflag,
616 int *hflag, int *sflag, unsigned long *n_arg, char **path1, char **path2)
617 {
618 const char *cmd, *cp = *cpp;
619 char *cp2 = NULL, **argv;
620 int base = 0;
621 long l = 0;
622 int i, cmdnum, optidx, argc;
623
624 /* Skip leading whitespace */
625 cp = cp + strspn(cp, WHITESPACE);
626
627 /* Check for leading '-' (disable error processing) */
628 *iflag = 0;
629 if (*cp == '-') {
630 *iflag = 1;
631 cp++;
632 cp = cp + strspn(cp, WHITESPACE);
633 }
634
635 /* Ignore blank lines and lines which begin with comment '#' char */
636 if (*cp == '\0' || *cp == '#')
637 return (0);
638
639 if ((argv = makeargv(cp, &argc, 0, NULL, NULL)) == NULL)
640 return -1;
641
642 /* Figure out which command we have */
643 for (i = 0; cmds[i].c != NULL; i++) {
644 if (_strcmpi(cmds[i].c, argv[0]) == 0)
645 break;
646 }
647 cmdnum = cmds[i].n;
648 cmd = cmds[i].c;
649
650 /* Special case */
651 if (*cp == '!') {
652 cp++;
653 cmdnum = I_SHELL;
654 } else if (cmdnum == -1) {
655 sftp_syslog(g_pvar, "Invalid command.");
656 return -1;
657 }
658
659 /* Get arguments and parse flags */
660 *lflag = *pflag = *rflag = *hflag = *n_arg = 0;
661 *path1 = *path2 = NULL;
662 optidx = 1;
663 switch (cmdnum) {
664 #if 0
665 case I_GET:
666 case I_PUT:
667 if ((optidx = parse_getput_flags(cmd, argv, argc,
668 pflag, rflag)) == -1)
669 return -1;
670 /* Get first pathname (mandatory) */
671 if (argc - optidx < 1) {
672 error("You must specify at least one path after a "
673 "%s command.", cmd);
674 return -1;
675 }
676 *path1 = xstrdup(argv[optidx]);
677 /* Get second pathname (optional) */
678 if (argc - optidx > 1) {
679 *path2 = xstrdup(argv[optidx + 1]);
680 /* Destination is not globbed */
681 undo_glob_escape(*path2);
682 }
683 break;
684 case I_LINK:
685 if ((optidx = parse_link_flags(cmd, argv, argc, sflag)) == -1)
686 return -1;
687 case I_SYMLINK:
688 case I_RENAME:
689 if (argc - optidx < 2) {
690 error("You must specify two paths after a %s "
691 "command.", cmd);
692 return -1;
693 }
694 *path1 = xstrdup(argv[optidx]);
695 *path2 = xstrdup(argv[optidx + 1]);
696 /* Paths are not globbed */
697 undo_glob_escape(*path1);
698 undo_glob_escape(*path2);
699 break;
700 case I_RM:
701 case I_MKDIR:
702 case I_RMDIR:
703 case I_CHDIR:
704 case I_LCHDIR:
705 case I_LMKDIR:
706 /* Get pathname (mandatory) */
707 if (argc - optidx < 1) {
708 error("You must specify a path after a %s command.",
709 cmd);
710 return -1;
711 }
712 *path1 = xstrdup(argv[optidx]);
713 /* Only "rm" globs */
714 if (cmdnum != I_RM)
715 undo_glob_escape(*path1);
716 break;
717 case I_DF:
718 if ((optidx = parse_df_flags(cmd, argv, argc, hflag,
719 iflag)) == -1)
720 return -1;
721 /* Default to current directory if no path specified */
722 if (argc - optidx < 1)
723 *path1 = NULL;
724 else {
725 *path1 = xstrdup(argv[optidx]);
726 undo_glob_escape(*path1);
727 }
728 break;
729 case I_LS:
730 if ((optidx = parse_ls_flags(argv, argc, lflag)) == -1)
731 return(-1);
732 /* Path is optional */
733 if (argc - optidx > 0)
734 *path1 = xstrdup(argv[optidx]);
735 break;
736 case I_LLS:
737 /* Skip ls command and following whitespace */
738 cp = cp + strlen(cmd) + strspn(cp, WHITESPACE);
739 case I_SHELL:
740 /* Uses the rest of the line */
741 break;
742 case I_LUMASK:
743 case I_CHMOD:
744 base = 8;
745 case I_CHOWN:
746 case I_CHGRP:
747 /* Get numeric arg (mandatory) */
748 if (argc - optidx < 1)
749 goto need_num_arg;
750 errno = 0;
751 l = strtol(argv[optidx], &cp2, base);
752 if (cp2 == argv[optidx] || *cp2 != '\0' ||
753 ((l == LONG_MIN || l == LONG_MAX) && errno == ERANGE) ||
754 l < 0) {
755 need_num_arg:
756 error("You must supply a numeric argument "
757 "to the %s command.", cmd);
758 return -1;
759 }
760 *n_arg = l;
761 if (cmdnum == I_LUMASK)
762 break;
763 /* Get pathname (mandatory) */
764 if (argc - optidx < 2) {
765 error("You must specify a path after a %s command.",
766 cmd);
767 return -1;
768 }
769 *path1 = xstrdup(argv[optidx + 1]);
770 break;
771 #endif
772 case I_QUIT:
773 case I_PWD:
774 case I_LPWD:
775 case I_HELP:
776 case I_VERSION:
777 case I_PROGRESS:
778 break;
779 default:
780 //fatal("Command not implemented");
781 return -1;
782 }
783
784 *cpp = cp;
785 return(cmdnum);
786 }
787
788
789 /*
790 * SFTP �R�}���h���C���R���\�[��
791 */
792 static WNDPROC hEditProc;
793
794 static LRESULT CALLBACK EditProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
795 {
796 char buf[512];
797 char *cmd;
798 char *path1, *path2, *tmp = NULL;
799 int pflag = 0, rflag = 0, lflag = 0, iflag = 0, hflag = 0, sflag = 0;
800 int cmdnum, i = 0;
801 unsigned long n_arg = 0;
802 //Attrib a, *aa;
803 char path_buf[1024] = {0};
804 int err = 0;
805 //glob_t g;
806 int err_abort;
807
808 switch (uMsg) {
809 case WM_KEYDOWN:
810 if ((int)wParam == VK_RETURN) {
811 GetWindowText(hwnd, buf, sizeof(buf));
812 SetWindowText(hwnd, "");
813 if (buf[0] != '\0') {
814 SendDlgItemMessage(GetParent(hwnd), IDC_SFTP_CONSOLE, EM_REPLACESEL, 0, (LPARAM) buf);
815 SendDlgItemMessage(GetParent(hwnd), IDC_SFTP_CONSOLE, EM_REPLACESEL, 0,
816 (LPARAM) (char *) "\r\n");
817 goto cmd_parsed;
818 }
819 }
820 break;
821 default:
822 return (CallWindowProc(hEditProc, hwnd, uMsg, wParam, lParam));
823 }
824 return 0L;
825
826 cmd_parsed:
827 // �R�}���h���C������
828 path1 = path2 = NULL;
829 cmd = buf;
830 cmdnum = parse_args(&cmd, &pflag, &rflag, &lflag, &iflag, &hflag,
831 &sflag, &n_arg, &path1, &path2);
832
833 if (iflag != 0)
834 err_abort = 0;
835
836 //memset(&g, 0, sizeof(g));
837
838 /* Perform command */
839 switch (cmdnum) {
840 case 0:
841 /* Blank line */
842 break;
843 case -1:
844 /* Unrecognized command */
845 err = -1;
846 break;
847 #if 0
848 case I_GET:
849 err = process_get(conn, path1, path2, *pwd, pflag, rflag);
850 break;
851 case I_PUT:
852 err = process_put(conn, path1, path2, *pwd, pflag, rflag);
853 break;
854 case I_RENAME:
855 path1 = make_absolute(path1, *pwd);
856 path2 = make_absolute(path2, *pwd);
857 err = do_rename(conn, path1, path2);
858 break;
859 case I_SYMLINK:
860 sflag = 1;
861 case I_LINK:
862 path1 = make_absolute(path1, *pwd);
863 path2 = make_absolute(path2, *pwd);
864 err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
865 break;
866 case I_RM:
867 path1 = make_absolute(path1, *pwd);
868 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
869 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
870 printf("Removing %s\n", g.gl_pathv[i]);
871 err = do_rm(conn, g.gl_pathv[i]);
872 if (err != 0 && err_abort)
873 break;
874 }
875 break;
876 case I_MKDIR:
877 path1 = make_absolute(path1, *pwd);
878 attrib_clear(&a);
879 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
880 a.perm = 0777;
881 err = do_mkdir(conn, path1, &a, 1);
882 break;
883 case I_RMDIR:
884 path1 = make_absolute(path1, *pwd);
885 err = do_rmdir(conn, path1);
886 break;
887 case I_CHDIR:
888 path1 = make_absolute(path1, *pwd);
889 if ((tmp = do_realpath(conn, path1)) == NULL) {
890 err = 1;
891 break;
892 }
893 if ((aa = do_stat(conn, tmp, 0)) == NULL) {
894 xfree(tmp);
895 err = 1;
896 break;
897 }
898 if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
899 error("Can't change directory: Can't check target");
900 xfree(tmp);
901 err = 1;
902 break;
903 }
904 if (!S_ISDIR(aa->perm)) {
905 error("Can't change directory: \"%s\" is not "
906 "a directory", tmp);
907 xfree(tmp);
908 err = 1;
909 break;
910 }
911 xfree(*pwd);
912 *pwd = tmp;
913 break;
914 case I_LS:
915 if (!path1) {
916 do_ls_dir(conn, *pwd, *pwd, lflag);
917 break;
918 }
919
920 /* Strip pwd off beginning of non-absolute paths */
921 tmp = NULL;
922 if (*path1 != '/')
923 tmp = *pwd;
924
925 path1 = make_absolute(path1, *pwd);
926 err = do_globbed_ls(conn, path1, tmp, lflag);
927 break;
928 case I_DF:
929 /* Default to current directory if no path specified */
930 if (path1 == NULL)
931 path1 = xstrdup(*pwd);
932 path1 = make_absolute(path1, *pwd);
933 err = do_df(conn, path1, hflag, iflag);
934 break;
935 case I_LCHDIR:
936 if (chdir(path1) == -1) {
937 error("Couldn't change local directory to "
938 "\"%s\": %s", path1, strerror(errno));
939 err = 1;
940 }
941 break;
942 case I_LMKDIR:
943 if (mkdir(path1, 0777) == -1) {
944 error("Couldn't create local directory "
945 "\"%s\": %s", path1, strerror(errno));
946 err = 1;
947 }
948 break;
949 case I_LLS:
950 local_do_ls(cmd);
951 break;
952 case I_SHELL:
953 local_do_shell(cmd);
954 break;
955 case I_LUMASK:
956 umask(n_arg);
957 printf("Local umask: %03lo\n", n_arg);
958 break;
959 case I_CHMOD:
960 path1 = make_absolute(path1, *pwd);
961 attrib_clear(&a);
962 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
963 a.perm = n_arg;
964 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
965 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
966 printf("Changing mode on %s\n", g.gl_pathv[i]);
967 err = do_setstat(conn, g.gl_pathv[i], &a);
968 if (err != 0 && err_abort)
969 break;
970 }
971 break;
972 case I_CHOWN:
973 case I_CHGRP:
974 path1 = make_absolute(path1, *pwd);
975 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
976 for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
977 if (!(aa = do_stat(conn, g.gl_pathv[i], 0))) {
978 if (err_abort) {
979 err = -1;
980 break;
981 } else
982 continue;
983 }
984 if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
985 error("Can't get current ownership of "
986 "remote file \"%s\"", g.gl_pathv[i]);
987 if (err_abort) {
988 err = -1;
989 break;
990 } else
991 continue;
992 }
993 aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
994 if (cmdnum == I_CHOWN) {
995 printf("Changing owner on %s\n", g.gl_pathv[i]);
996 aa->uid = n_arg;
997 } else {
998 printf("Changing group on %s\n", g.gl_pathv[i]);
999 aa->gid = n_arg;
1000 }
1001 err = do_setstat(conn, g.gl_pathv[i], aa);
1002 if (err != 0 && err_abort)
1003 break;
1004 }
1005 break;
1006 case I_PWD:
1007 printf("Remote working directory: %s\n", *pwd);
1008 break;
1009 case I_LPWD:
1010 if (!getcwd(path_buf, sizeof(path_buf))) {
1011 error("Couldn't get local cwd: %s", strerror(errno));
1012 err = -1;
1013 break;
1014 }
1015 printf("Local working directory: %s\n", path_buf);
1016 break;
1017 #endif
1018 case I_QUIT:
1019 /* Processed below */
1020 break;
1021 case I_HELP:
1022 help();
1023 break;
1024 case I_VERSION:
1025 printf("SFTP protocol version %u\n", sftp_proto_version(&g_channel->sftp));
1026 break;
1027 #if 0
1028 case I_PROGRESS:
1029 showprogress = !showprogress;
1030 if (showprogress)
1031 printf("Progress meter enabled\n");
1032 else
1033 printf("Progress meter disabled\n");
1034 break;
1035 #endif
1036 default:
1037 //fatal("%d is not implemented", cmdnum);
1038 err = -1;
1039 }
1040
1041 #if 0
1042 if (g.gl_pathc)
1043 globfree(&g);
1044 if (path1)
1045 xfree(path1);
1046 if (path2)
1047 xfree(path2);
1048
1049 /* If an unignored error occurs in batch mode we should abort. */
1050 if (err_abort && err != 0)
1051 return (-1);
1052 else if (cmdnum == I_QUIT)
1053 return (1);
1054 #endif
1055
1056 return 0L;
1057 }
1058
1059 static LRESULT CALLBACK OnSftpConsoleDlgProc(HWND hDlgWnd, UINT msg, WPARAM wp, LPARAM lp)
1060 {
1061 static HFONT DlgDragDropFont = NULL;
1062 LOGFONT logfont;
1063 HFONT font;
1064 HWND hEdit;
1065
1066 switch (msg) {
1067 case WM_INITDIALOG:
1068 font = (HFONT)SendMessage(hDlgWnd, WM_GETFONT, 0, 0);
1069 GetObject(font, sizeof(LOGFONT), &logfont);
1070 DlgDragDropFont = NULL;
1071
1072 hEdit = GetDlgItem(hDlgWnd, IDC_SFTP_EDIT);
1073 SetFocus(hEdit);
1074
1075 // �G�f�B�b�g�R���g���[�����T�u�N���X��
1076 hEditProc = (WNDPROC)GetWindowLongPtr(hEdit, GWLP_WNDPROC);
1077 SetWindowLongPtr(hEdit, GWLP_WNDPROC, (LONG_PTR)EditProc);
1078
1079 CenterWindow(hDlgWnd, GetParent(hDlgWnd));
1080
1081 return TRUE;
1082
1083 case WM_COMMAND:
1084 switch (LOWORD(wp)) {
1085 case IDOK:
1086 break;
1087
1088 case IDCANCEL:
1089 if (DlgDragDropFont != NULL) {
1090 DeleteObject(DlgDragDropFont);
1091 }
1092 EndDialog(hDlgWnd, IDCANCEL);
1093 DestroyWindow(hDlgWnd);
1094 break;
1095
1096 default:
1097 return FALSE;
1098 }
1099 return TRUE;
1100
1101 case WM_USER_CONSOLE:
1102 SendDlgItemMessage(hDlgWnd, IDC_SFTP_CONSOLE, EM_REPLACESEL, 0, (LPARAM) lp);
1103 SendDlgItemMessage(hDlgWnd, IDC_SFTP_CONSOLE, EM_REPLACESEL, 0,
1104 (LPARAM) (char *) "\r\n");
1105 return TRUE;
1106
1107 #if 0
1108 case WM_SIZE:
1109 {
1110 // ���z�u
1111 int dlg_w, dlg_h;
1112 RECT rc_dlg;
1113 RECT rc;
1114 POINT p;
1115
1116 // �V�����_�C�A���O���T�C�Y������
1117 GetClientRect(hDlgWnd, &rc_dlg);
1118 dlg_w = rc_dlg.right;
1119 dlg_h = rc_dlg.bottom;
1120
1121 // �R�}���h�v�����v�g
1122 GetWindowRect(GetDlgItem(hDlgWnd, IDC_SFTP_EDIT), &rc);
1123 p.x = rc.left;
1124 p.y = rc.top;
1125 ScreenToClient(hDlgWnd, &p);
1126 SetWindowPos(GetDlgItem(hDlgWnd, IDC_SFTP_EDIT), 0,
1127 0, 0, dlg_w, p.y,
1128 SWP_NOSIZE | SWP_NOZORDER);
1129 }
1130 return TRUE;
1131 #endif
1132
1133 default:
1134 return FALSE;
1135 }
1136 return TRUE;
1137 }
1138
1139 // SFTP���M���� -�X�e�[�g�}�V�[��-
1140 void sftp_response(PTInstVar pvar, Channel_t *c, unsigned char *data, unsigned int buflen)
1141 {
1142 buffer_t *msg;
1143 HWND hDlgWnd;
1144
1145 /*
1146 * Allocate buffer
1147 */
1148 sftp_buffer_alloc(&msg);
1149 sftp_get_msg(pvar, c, data, buflen, &msg);
1150
1151 if (c->sftp.state == SFTP_INIT) {
1152 // �O���[�o�����������������B
1153 g_pvar = pvar;
1154 g_channel = c;
1155
1156 sftp_do_init_recv(pvar, c, msg);
1157
1158 // �R���\�[�����N�������B
1159 hDlgWnd = CreateDialog(hInst, MAKEINTRESOURCE(IDD_SFTP_DIALOG),
1160 pvar->cv->HWin, (DLGPROC)OnSftpConsoleDlgProc);
1161 if (hDlgWnd != NULL) {
1162 c->sftp.console_window = hDlgWnd;
1163 ShowWindow(hDlgWnd, SW_SHOW);
1164 }
1165
1166 sftp_do_realpath(pvar, c, ".");
1167 c->sftp.state = SFTP_CONNECTED;
1168
1169 } else if (c->sftp.state == SFTP_CONNECTED) {
1170 char *remote_path;
1171 remote_path = sftp_do_realpath_recv(pvar, c, msg);
1172
1173 c->sftp.state = SFTP_REALPATH;
1174
1175 }
1176
1177 /*
1178 * Free buffer
1179 */
1180 sftp_buffer_free(msg);
1181 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26