📄 ssh_ftp.c
字号:
/* Modified for use in Yafc by Martin Hedenfalk <mhe@stacken.kth.se> * * Original copyright: * * Copyright (c) 2001 Damien Miller. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "syshdr.h"#include "ftp.h"#include "ssh_ftp.h"#include "buffer.h"#include "bufaux.h"#include "getput.h"#include "atomicio.h"#include "gvars.h"int use_ssh1 = 0;#define COPY_SIZE 8192int ssh_connect(char **args, int *in, int *out, pid_t *sshpid){ int c_in, c_out;#ifdef USE_PIPES int pin[2], pout[2]; if ((pipe(pin) == -1) || (pipe(pout) == -1)) { ftp_err("pipe: %s\n", strerror(errno)); return -1; } *in = pin[0]; *out = pout[1]; c_in = pout[0]; c_out = pin[1];#else /* USE_PIPES */ int inout[2]; if(socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) { ftp_err("socketpair: %s\n", strerror(errno)); return -1; } *in = *out = inout[0]; c_in = c_out = inout[1];#endif /* USE_PIPES */ if ((*sshpid = fork()) == -1) { ftp_err("fork: %s\n", strerror(errno)); return -1; } else if (*sshpid == 0) { if ((dup2(c_in, /*STDIN_FILENO*/ 0) == -1) || (dup2(c_out, /*STDOUT_FILENO*/ 1) == -1)) { ftp_err("dup2: %s\n", strerror(errno)); exit(1); } close(*in); close(*out); close(c_in); close(c_out); execv(gvSSHProgram, args); ftp_err("exec: %s: %s\n", gvSSHProgram, strerror(errno)); exit(1); } close(c_in); close(c_out); return 0;}static const char *ssh_cmd2txt(int code){ static const char *strings[] = { "", "SSH2_FXP_INIT", /* 1 */ "", "SSH2_FXP_OPEN", /* 3 */ "SSH2_FXP_CLOSE", "SSH2_FXP_READ", "SSH2_FXP_WRITE", "SSH2_FXP_LSTAT", "SSH2_FXP_FSTAT", "SSH2_FXP_SETSTAT", "SSH2_FXP_FSETSTAT", /* 10 */ "SSH2_FXP_OPENDIR", "SSH2_FXP_READDIR", "SSH2_FXP_REMOVE", "SSH2_FXP_MKDIR", "SSH2_FXP_RMDIR", "SSH2_FXP_REALPATH", "SSH2_FXP_STAT", "SSH2_FXP_RENAME", "SSH2_FXP_READLINK", "SSH2_FXP_SYMLINK" /* 20 */ }; if(code >= 1 && code <= 20) return strings[code]; return "unknown command";}static void ssh_print_cmd(Buffer *cmd){ char code; void (*pfunc)(const char *fmt, ...); char *e; code = buffer_ptr(cmd)[4]; if(ftp_get_verbosity() == vbDebug) pfunc = ftp_err; else pfunc = ftp_trace; pfunc("--> [%s] ", ftp->url ? ftp->url->hostname : "?"); pfunc("%s", ssh_cmd2txt(code)); switch(code) { case SSH2_FXP_OPEN: cmd->offset = 9; e = buffer_get_string(cmd, 0); pfunc("(%s)", e); free(e); break; case SSH2_FXP_WRITE: cmd->offset = 9; buffer_consume(cmd, buffer_get_int(cmd)); pfunc("(offset %ld)", buffer_get_int64(cmd)); break; } pfunc("\n");}/* sends an SSH command on the control channel * returns 0 on success or -1 on error */int ssh_cmd(Buffer *m){ int mlen = buffer_len(m); int len; Buffer oqueue; buffer_init(&oqueue); buffer_put_int(&oqueue, mlen); buffer_append(&oqueue, buffer_ptr(m), mlen); buffer_consume(m, mlen); len = atomicio(write, ftp->ssh_out, buffer_ptr(&oqueue), buffer_len(&oqueue)); ssh_print_cmd(&oqueue); buffer_free(&oqueue); if(len <= 0) { ftp_err("Couldn't send packet: %s\n", strerror(errno)); return -1; } return 0;}static const char *ssh_reply2txt(int code){ static const char *strings[] = { "SSH2_FXP_VERSION", /* 2 */ "SSH2_FXP_STATUS", /* 101 */ "SSH2_FXP_HANDLE", /* 102 */ "SSH2_FXP_DATA", /* 103 */ "SSH2_FXP_NAME", /* 104 */ "SSH2_FXP_ATTRS", /* 105 */ }; if(code == 2) return strings[0]; else if(code >= 101 && code <= 105) return strings[code - 100]; return "unknown reply";}static void ssh_print_reply(int code){ verbose_t v = ftp_get_verbosity(); ftp_trace("<-- [%s] %s\n", ftp->url ? ftp->url->hostname : ftp->host->hostname, ssh_reply2txt(code)); if(v >= vbCommand || (ftp->code >= ctTransient && v == vbError)) { if(v == vbDebug) fprintf(stderr, "<-- [%s] %s\n", ftp->url ? ftp->url->hostname : ftp->host->hostname, ssh_reply2txt(code)); else fprintf(stderr, "%s\n", ssh_reply2txt(code)); }}int ssh_reply(Buffer *m){ u_int len, msg_len; char buf[4096]; bool reply_printed = false; len = atomicio(read, ftp->ssh_in, buf, 4); if(len == 0) { ftp_err("Connection closed\n"); return -1; } else if(len == -1) { ftp_err("Couldn't read packet: %s\n", strerror(errno)); return -1; } msg_len = GET_32BIT(buf); if(msg_len > 256 * 1024) { ftp_err("Received message too long %d\n", msg_len); return -1; } while(msg_len) { len = atomicio(read, ftp->ssh_in, buf, min(msg_len, sizeof(buf))); if(len == 0) { ftp_err("Connection closed\n"); return -1; } else if (len == -1) { ftp_err("Couldn't read packet: %s\n", strerror(errno)); return -1; } if(!reply_printed) { ssh_print_reply(buf[0]); reply_printed = true; } msg_len -= len; buffer_append(m, buf, len); } ftp->fullcode = 200; ftp->code = ctComplete; return 0;}/* returns SSH version on success, -1 on failure */int ssh_init(void){ int type, version; Buffer msg; buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_INIT); buffer_put_int(&msg, SSH2_FILEXFER_VERSION); if(ssh_cmd(&msg) == -1) return -1; buffer_clear(&msg); if(ssh_reply(&msg) == -1) return -1; /* Expecting a VERSION reply */ if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { ftp_err("Invalid packet back from SSH2_FXP_INIT (type %d)\n", type); buffer_free(&msg); return -1; } version = buffer_get_int(&msg); /* Check for extensions */ while(buffer_len(&msg) > 0) { char *name = buffer_get_string(&msg, NULL); char *value = buffer_get_string(&msg, NULL); ftp_err("Init extension: \"%s\"\n", name); free(name); free(value); } buffer_free(&msg); return version;}char *ssh_realpath(char *path){ Buffer msg; u_int type, expected_id, count, id; char *filename, *longname; Attrib *a; expected_id = id = ftp->ssh_id++; ssh_send_string_request(id, SSH2_FXP_REALPATH, path, strlen(path)); buffer_init(&msg); if(ssh_reply(&msg) == -1) return 0; type = buffer_get_char(&msg); id = buffer_get_int(&msg); if(id != expected_id) { ftp_err("ID mismatch (%d != %d)\n", id, expected_id); return 0; } if(type == SSH2_FXP_STATUS) { u_int status = buffer_get_int(&msg); ftp_err("Couldn't canonicalise: %s\n", fx2txt(status)); return 0; } else if(type != SSH2_FXP_NAME) { ftp_err("Expected SSH2_FXP_NAME(%d) packet, got %s (%d)\n", SSH2_FXP_NAME, ssh_reply2txt(type), type); return 0; } count = buffer_get_int(&msg); if(count != 1) { ftp_err("Got multiple names (%d) from SSH_FXP_REALPATH\n", count); return 0; } filename = buffer_get_string(&msg, NULL); longname = buffer_get_string(&msg, NULL); a = decode_attrib(&msg); free(longname); buffer_free(&msg); return filename;}Attrib *ssh_stat(const char *path){ u_int id; id = ftp->ssh_id++; ssh_send_string_request(id, SSH2_FXP_STAT, path, strlen(path)); return ssh_get_decode_stat(id);}Attrib *do_lstat(const char *path){ u_int id; id = ftp->ssh_id++; ssh_send_string_request(id, SSH2_FXP_LSTAT, path, strlen(path)); return ssh_get_decode_stat(id);}Attrib *do_fstat(char *handle, u_int handle_len){ u_int id; id = ftp->ssh_id++; ssh_send_string_request(id, SSH2_FXP_FSTAT, handle, handle_len); return ssh_get_decode_stat(id);}int ssh_setstat(const char *path, Attrib *a){ u_int status, id; id = ftp->ssh_id++; ssh_send_string_attrs_request(id, SSH2_FXP_SETSTAT, path, strlen(path), a); status = ssh_get_status(id); if(status != SSH2_FX_OK) { ftp_err("Couldn't setstat on \"%s\": %s\n", path, fx2txt(status)); return -1; } return 0;}char *ssh_get_handle(u_int expected_id, u_int *len){ Buffer msg; u_int type, id; char *handle; buffer_init(&msg); if(ssh_reply(&msg) == -1) return 0; type = buffer_get_char(&msg); id = buffer_get_int(&msg); if(id != expected_id) { ftp_err("ID mismatch (%d != %d)\n", id, expected_id); return 0; } if(type == SSH2_FXP_STATUS) { int status = buffer_get_int(&msg); ftp_err("Couldn't get handle: %s\n", fx2txt(status)); return NULL; } else if (type != SSH2_FXP_HANDLE) { ftp_err("Expected SSH2_FXP_HANDLE(%d) packet, got %s (%d)\n", SSH2_FXP_HANDLE, ssh_reply2txt(type), type); return 0; } handle = buffer_get_string(&msg, len); buffer_free(&msg); return handle;}int ssh_readdir(char *path, SFTP_DIRENT ***dir){ Buffer msg; u_int type, id, handle_len, i, expected_id, ents = 0; char *handle; id = ftp->ssh_id++; buffer_init(&msg); buffer_put_char(&msg, SSH2_FXP_OPENDIR); buffer_put_int(&msg, id); buffer_put_cstring(&msg, path); if(ssh_cmd(&msg) == -1) return -1; buffer_clear(&msg); handle = ssh_get_handle(id, &handle_len); if(handle == 0) return -1; if(dir) { ents = 0; *dir = xmalloc(sizeof(**dir)); (*dir)[0] = NULL; } while(true) { int count; id = expected_id = ftp->ssh_id++; buffer_clear(&msg); buffer_put_char(&msg, SSH2_FXP_READDIR); buffer_put_int(&msg, id); buffer_put_string(&msg, handle, handle_len); if(ssh_cmd(&msg) == -1) return -1; buffer_clear(&msg); if(ssh_reply(&msg) == -1) return -1; type = buffer_get_char(&msg); id = buffer_get_int(&msg);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -