Develop and Download Open Source Software

Browse Subversion Repository

Diff of /branches/ssh_chacha20poly1305/ttssh2/ttxssh/ssh.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 3073 by maya, Tue Dec 11 19:33:02 2007 UTC revision 3074 by yutakapon, Mon Dec 24 14:42:50 2007 UTC
# Line 47  SOFTWARE, EVEN IF ADVISED OF THE POSSIBI Line 47  SOFTWARE, EVEN IF ADVISED OF THE POSSIBI
47  #include "crypt.h"  #include "crypt.h"
48  #include "fwd.h"  #include "fwd.h"
49    
50    #include <sys/types.h>
51    #include <sys/stat.h>
52    #include <assert.h>
53    
54  // SSH2 macro  // SSH2 macro
55  #ifdef _DEBUG  #ifdef _DEBUG
56  #define SSH2_DEBUG  #define SSH2_DEBUG
# Line 64  SOFTWARE, EVEN IF ADVISED OF THE POSSIBI Line 68  SOFTWARE, EVEN IF ADVISED OF THE POSSIBI
68  #define CHANNEL_MAX 100  #define CHANNEL_MAX 100
69    
70  enum channel_type {  enum channel_type {
71          TYPE_SHELL, TYPE_PORTFWD,          TYPE_SHELL, TYPE_PORTFWD, TYPE_SCP,
72    };
73    
74    enum scp_state {
75            SCP_INIT, SCP_TIMESTAMP, SCP_FILEINFO, SCP_DATA, SCP_CLOSING,
76  };  };
77    
78  typedef struct bufchain {  typedef struct bufchain {
# Line 72  typedef struct bufchain { Line 80  typedef struct bufchain {
80          struct bufchain *next;          struct bufchain *next;
81  } bufchain_t;  } bufchain_t;
82    
83    typedef struct scp {
84            enum scp_state state;      // SCP state
85            char sendfile[MAX_PATH];       // sending filename
86            char sendfilefull[MAX_PATH];   // sending filename fullpath
87            FILE *sendfp;                  // file pointer
88            struct _stat filestat;         // file status information
89            HANDLE thread;                 // sending thread handle
90    } scp_t;
91    
92  typedef struct channel {  typedef struct channel {
93          int used;          int used;
94          int self_id;          int self_id;
# Line 85  typedef struct channel { Line 102  typedef struct channel {
102          enum channel_type type;          enum channel_type type;
103          int local_num;          int local_num;
104          bufchain_t *bufchain;          bufchain_t *bufchain;
105            scp_t scp;
106  } Channel_t;  } Channel_t;
107    
108  static Channel_t channels[CHANNEL_MAX];  static Channel_t channels[CHANNEL_MAX];
# Line 161  static Channel_t *ssh2_channel_new(unsig Line 179  static Channel_t *ssh2_channel_new(unsig
179          c->type = type;          c->type = type;
180          c->local_num = local_num;  // alloc_channel()の返値を保存しておく          c->local_num = local_num;  // alloc_channel()の返値を保存しておく
181          c->bufchain = NULL;          c->bufchain = NULL;
182            if (type == TYPE_SCP) {
183                    c->scp.state = SCP_INIT;
184                    c->scp.thread = (HANDLE)-1L;
185            }
186    
187          return (c);          return (c);
188  }  }
# Line 231  static void ssh2_channel_delete(Channel_ Line 253  static void ssh2_channel_delete(Channel_
253                  free(ptr);                  free(ptr);
254          }          }
255    
256            if (c->type == TYPE_SCP) {
257                    c->scp.state = SCP_CLOSING;
258                    // SCPスレッドが動いていたら終わるまで待つ
259                    if (c->scp.thread != (HANDLE)-1L) {
260                            WaitForSingleObject(c->scp.thread, INFINITE);
261                            CloseHandle(c->scp.thread);
262                            c->scp.thread = (HANDLE)-1L;
263                    }
264            }
265    
266          memset(c, 0, sizeof(Channel_t));          memset(c, 0, sizeof(Channel_t));
267          c->used = 0;          c->used = 0;
268  }  }
# Line 283  static Channel_t *ssh2_local_channel_loo Line 315  static Channel_t *ssh2_local_channel_loo
315  //  //
316  // SSH heartbeat mutex  // SSH heartbeat mutex
317  //  //
318  static CRITICAL_SECTION g_ssh_heartbeat_lock;   /* ロック用変数 */  static CRITICAL_SECTION g_ssh_heartbeat_lock;   /* 送受信用ロック */
319    static CRITICAL_SECTION g_ssh_blocking_send_lock;   /* send_packet_blocking()用ロック */
320    
321  void ssh_heartbeat_lock_initialize(void)  void ssh_heartbeat_lock_initialize(void)
322  {  {
323          InitializeCriticalSection(&g_ssh_heartbeat_lock);          InitializeCriticalSection(&g_ssh_heartbeat_lock);
324            InitializeCriticalSection(&g_ssh_blocking_send_lock);
325  }  }
326    
327  void ssh_heartbeat_lock_finalize(void)  void ssh_heartbeat_lock_finalize(void)
328  {  {
329          DeleteCriticalSection(&g_ssh_heartbeat_lock);          DeleteCriticalSection(&g_ssh_heartbeat_lock);
330            DeleteCriticalSection(&g_ssh_blocking_send_lock);
331  }  }
332    
333  void ssh_heartbeat_lock(void)  void ssh_heartbeat_lock(void)
# Line 305  void ssh_heartbeat_unlock(void) Line 340  void ssh_heartbeat_unlock(void)
340          LeaveCriticalSection(&g_ssh_heartbeat_lock);          LeaveCriticalSection(&g_ssh_heartbeat_lock);
341  }  }
342    
343    static void ssh_blocking_send_lock(void)
344    {
345            EnterCriticalSection(&g_ssh_blocking_send_lock);
346    }
347    
348    static void ssh_blocking_send_unlock(void)
349    {
350            LeaveCriticalSection(&g_ssh_blocking_send_lock);
351    }
352    
353    
354  //  //
355  // SSH memory dump (for debug)  // SSH memory dump (for debug)
# Line 830  static BOOL send_packet_blocking(PTInstV Line 875  static BOOL send_packet_blocking(PTInstV
875          // パケット送信後にバッファを使いまわすため、ブロッキングで送信してしまう必要がある。          // パケット送信後にバッファを使いまわすため、ブロッキングで送信してしまう必要がある。
876          // ノンブロッキングで送信してWSAEWOULDBLOCKが返ってきた場合、そのバッファは送信完了する          // ノンブロッキングで送信してWSAEWOULDBLOCKが返ってきた場合、そのバッファは送信完了する
877          // まで保持しておかなくてはならない。(2007.10.30 yutaka)          // まで保持しておかなくてはならない。(2007.10.30 yutaka)
878            // 以下の処理は thread-safe ではないため、失敗することがある。ゆえに、全体をロックする
879            // 必要がある。(2007.12.24 yutaka)
880          u_long do_block = 0;          u_long do_block = 0;
881          int code = 0;          int code = 0;
882          char *kind = NULL, buf[256];          char *kind = NULL, buf[256];
# Line 852  static BOOL send_packet_blocking(PTInstV Line 899  static BOOL send_packet_blocking(PTInstV
899                  return TRUE;                  return TRUE;
900          }          }
901  #else  #else
902            ssh_blocking_send_lock();
903    
904          if ((pvar->PWSAAsyncSelect) (pvar->socket, pvar->NotificationWindow,          if ((pvar->PWSAAsyncSelect) (pvar->socket, pvar->NotificationWindow,
905                                       0, 0) == SOCKET_ERROR) {                                       0, 0) == SOCKET_ERROR) {
906                          code = WSAGetLastError();                          code = WSAGetLastError();
# Line 876  static BOOL send_packet_blocking(PTInstV Line 925  static BOOL send_packet_blocking(PTInstV
925                          kind = "WSAAsyncSelect2";                          kind = "WSAAsyncSelect2";
926                          goto error;                          goto error;
927          }          }
928            ssh_blocking_send_unlock();
929    
930          return TRUE;          return TRUE;
931    
932  error:  error:
933            ssh_blocking_send_unlock();
934    
935          UTIL_get_lang_msg("MSG_SSH_SEND_PKT_ERROR", pvar,          UTIL_get_lang_msg("MSG_SSH_SEND_PKT_ERROR", pvar,
936                            "A communications error occurred while sending an SSH packet.\n"                            "A communications error occurred while sending an SSH packet.\n"
937                            "The connection will close. (%s:%d)");                            "The connection will close. (%s:%d)");
# Line 3310  void SSH_open_channel(PTInstVar pvar, ui Line 3362  void SSH_open_channel(PTInstVar pvar, ui
3362  }  }
3363    
3364    
3365    //
3366    // SCP support
3367    //
3368    // (2007.12.21 yutaka)
3369    //
3370    int SSH_start_scp(PTInstVar pvar, char *sendfile)
3371    {
3372            buffer_t *msg;
3373            char *s;
3374            unsigned char *outmsg;
3375            int len;
3376            Channel_t *c = NULL;
3377            FILE *fp = NULL;
3378            struct _stat st;
3379    
3380            // ソケットがクローズされている場合は何もしない。
3381            if (pvar->socket == INVALID_SOCKET)
3382                    goto error;
3383    
3384            if (SSHv1(pvar))      // SSH1サポートはTBD
3385                    goto error;
3386    
3387            fp = fopen(sendfile, "rb");
3388            if (fp == NULL)
3389                    goto error;
3390    
3391            // チャネル設定
3392            c = ssh2_channel_new(CHAN_SES_WINDOW_DEFAULT, CHAN_SES_PACKET_DEFAULT, TYPE_SCP, -1);
3393            if (c == NULL) {
3394                    UTIL_get_lang_msg("MSG_SSH_NO_FREE_CHANNEL", pvar,
3395                                      "Could not open new channel. TTSSH is already opening too many channels.");
3396                    notify_fatal_error(pvar, pvar->ts->UIMsg);
3397                    goto error;
3398            }
3399            // setup SCP data
3400            c->scp.state = SCP_INIT;
3401            strncpy_s(c->scp.sendfilefull, sizeof(c->scp.sendfilefull), sendfile, _TRUNCATE);  // full path
3402            ExtractFileName(sendfile, c->scp.sendfile, sizeof(c->scp.sendfile));   // file name only
3403            c->scp.sendfp = fp;     // file pointer
3404            if (_stat(c->scp.sendfilefull, &st) == 0) {
3405                    c->scp.filestat = st;
3406            } else {
3407                    goto error;
3408            }
3409    
3410            // session open
3411            msg = buffer_init();
3412            if (msg == NULL) {
3413                    goto error;
3414            }
3415            s = "session";
3416            buffer_put_string(msg, s, strlen(s));  // ctype
3417            buffer_put_int(msg, c->self_id);  // self(channel number)
3418            buffer_put_int(msg, c->local_window);  // local_window
3419            buffer_put_int(msg, c->local_maxpacket);  // local_maxpacket
3420            len = buffer_len(msg);
3421            outmsg = begin_send_packet(pvar, SSH2_MSG_CHANNEL_OPEN, len);
3422            memcpy(outmsg, buffer_ptr (msg), len);
3423            finish_send_packet(pvar);
3424            buffer_free(msg);
3425    
3426            return TRUE;
3427    
3428    error:
3429            if (c != NULL)
3430                    ssh2_channel_delete(c);
3431            if (fp != NULL)
3432                    fclose(fp);
3433    
3434            return FALSE;
3435    }
3436    
3437    
3438  /////////////////////////////////////////////////////////////////////////////  /////////////////////////////////////////////////////////////////////////////
3439  //  //
3440  // SSH2 protocol procedure in the following code:  // SSH2 protocol procedure in the following code:
# Line 6627  static BOOL handle_SSH2_open_confirm(PTI Line 6752  static BOOL handle_SSH2_open_confirm(PTI
6752                  return TRUE;                  return TRUE;
6753          }          }
6754    
6755          // ポートフォワーディングの準備 (2005.2.26, 2005.6.21 yutaka)          if (c->type == TYPE_SHELL) {
6756          // シェルオープンしたあとに X11 の要求を出さなくてはならない。(2005.7.3 yutaka)                  // ポートフォワーディングの準備 (2005.2.26, 2005.6.21 yutaka)
6757          FWD_prep_forwarding(pvar);                  // シェルオープンしたあとに X11 の要求を出さなくてはならない。(2005.7.3 yutaka)
6758          FWD_enter_interactive_mode(pvar);                  FWD_prep_forwarding(pvar);
6759                    FWD_enter_interactive_mode(pvar);
6760            }
6761    
6762          //debug_print(100, data, len);          //debug_print(100, data, len);
6763    
# Line 6648  static BOOL handle_SSH2_open_confirm(PTI Line 6775  static BOOL handle_SSH2_open_confirm(PTI
6775          }          }
6776    
6777          buffer_put_int(msg, remote_id);          buffer_put_int(msg, remote_id);
6778          s = "pty-req";  // pseudo terminalのリクエスト          if (c->type == TYPE_SCP) {
6779                    s = "exec";
6780            } else {
6781                    s = "pty-req";  // pseudo terminalのリクエスト
6782            }
6783          buffer_put_string(msg, s, strlen(s));          buffer_put_string(msg, s, strlen(s));
6784          buffer_put_char(msg, wantconfirm);  // wantconfirm (disableに変更 2005/3/28 yutaka)          buffer_put_char(msg, wantconfirm);  // wantconfirm (disableに変更 2005/3/28 yutaka)
6785    
6786            if (c->type == TYPE_SCP) {
6787                    char sbuf[MAX_PATH + 30];
6788                    _snprintf_s(sbuf, sizeof(sbuf), _TRUNCATE, "scp -t %s", c->scp.sendfile);
6789                    buffer_put_string(msg, sbuf, strlen(sbuf));
6790                    goto done;
6791            }
6792    
6793          s = pvar->ts->TermType; // TERM          s = pvar->ts->TermType; // TERM
6794          buffer_put_string(msg, s, strlen(s));          buffer_put_string(msg, s, strlen(s));
6795          buffer_put_int(msg, pvar->ssh_state.win_cols);  // columns          buffer_put_int(msg, pvar->ssh_state.win_cols);  // columns
# Line 6681  static BOOL handle_SSH2_open_confirm(PTI Line 6820  static BOOL handle_SSH2_open_confirm(PTI
6820          buffer_put_string(msg, buffer_ptr(ttymsg), buffer_len(ttymsg));          buffer_put_string(msg, buffer_ptr(ttymsg), buffer_len(ttymsg));
6821  #endif  #endif
6822    
6823    done:
6824          len = buffer_len(msg);          len = buffer_len(msg);
6825          outmsg = begin_send_packet(pvar, SSH2_MSG_CHANNEL_REQUEST, len);          outmsg = begin_send_packet(pvar, SSH2_MSG_CHANNEL_REQUEST, len);
6826          memcpy(outmsg, buffer_ptr(msg), len);          memcpy(outmsg, buffer_ptr(msg), len);
# Line 6877  static void do_SSH2_adjust_window_size(P Line 7017  static void do_SSH2_adjust_window_size(P
7017    
7018  }  }
7019    
7020    
7021    typedef struct scp_thread_parm {
7022            PTInstVar pvar;
7023            Channel_t *c;
7024    } scp_thread_parm_t;
7025    
7026    static unsigned __stdcall ssh_scp_thread(void FAR * p)
7027    {
7028            scp_thread_parm_t *parm = (scp_thread_parm_t *)p;
7029            PTInstVar pvar = parm->pvar;
7030            Channel_t *c = parm->c;
7031            char buf[8192];
7032            size_t ret;
7033            long long total_size = 0;
7034    
7035            do {
7036                    // ファイルから読み込んだデータはかならずサーバへ送信する。
7037                    ret = fread(buf, 1, sizeof(buf), c->scp.sendfp);
7038                    if (ret == 0)
7039                            break;
7040    
7041                    do {
7042                            // socket or channelがクローズされたらスレッドを終わる
7043                            if (pvar->socket == INVALID_SOCKET || c->scp.state == SCP_CLOSING || c->used == 0)
7044                                    goto done;
7045    
7046                            // サーバのウィンドウに余裕がない場合は、送信しない。SSH2_send_channel_data()で遅延送信処理が
7047                            // あるが、SCPスレッドとメインスレッドは別コンテキストであるため、SCPスレッドから遅延送信処理を
7048                            // 行おうとしてもうまく動かない。
7049                            if (ret > c->remote_window) {
7050                                    Sleep(100); // yield
7051                            }
7052                    } while (ret > c->remote_window);
7053    
7054                    // 別コンテキストで、SSHのシーケンスへ割り込まないようにロックを取る。
7055                    ssh_heartbeat_lock();
7056                    SSH2_send_channel_data(pvar, c, buf, ret);
7057                    ssh_heartbeat_unlock();
7058    
7059                    total_size += ret;
7060    
7061            } while (ret >= sizeof(buf));
7062    
7063            // EOF
7064            SSH2_send_channel_data(pvar, c, "\0", 1);
7065            c->scp.state = SCP_DATA;
7066    
7067            assert(total_size == c->scp.filestat.st_size);
7068    
7069    done:
7070            free(p);
7071    
7072            return 0;
7073    }
7074    
7075    
7076  static BOOL handle_SSH2_channel_data(PTInstVar pvar)  static BOOL handle_SSH2_channel_data(PTInstVar pvar)
7077  {        {      
7078          int len;          int len;
7079          char *data;          char *data;
7080          int id;          int id;
7081          unsigned int strlen;          unsigned int str_len;
7082          Channel_t *c;          Channel_t *c;
7083    
7084          // 6byte(サイズ+パディング+タイプ)を取り除いた以降のペイロード          // 6byte(サイズ+パディング+タイプ)を取り除いた以降のペイロード
# Line 6903  static BOOL handle_SSH2_channel_data(PTI Line 7099  static BOOL handle_SSH2_channel_data(PTI
7099          }          }
7100    
7101          // string length          // string length
7102          strlen = get_uint32_MSBfirst(data);          str_len = get_uint32_MSBfirst(data);
7103          data += 4;          data += 4;
7104    
7105          // バッファサイズのチェック          // バッファサイズのチェック
7106          if (strlen > c->local_maxpacket) {          if (str_len > c->local_maxpacket) {
7107                  // TODO: logging                  // TODO: logging
7108          }          }
7109          if (strlen > c->local_window) {          if (str_len > c->local_window) {
7110                  // TODO: logging                  // TODO: logging
7111                  // local window sizeより大きなパケットは捨てる                  // local window sizeより大きなパケットは捨てる
7112                  return FALSE;                  return FALSE;
# Line 6918  static BOOL handle_SSH2_channel_data(PTI Line 7114  static BOOL handle_SSH2_channel_data(PTI
7114    
7115          // ペイロードとしてクライアント(TeraTerm)へ渡す          // ペイロードとしてクライアント(TeraTerm)へ渡す
7116          if (c->type == TYPE_SHELL) {          if (c->type == TYPE_SHELL) {
7117                  pvar->ssh_state.payload_datalen = strlen;                  pvar->ssh_state.payload_datalen = str_len;
7118                  pvar->ssh_state.payload_datastart = 8; // id + strlen                  pvar->ssh_state.payload_datastart = 8; // id + strlen
7119    
7120          } else {          } else if (c->type == TYPE_PORTFWD) {
7121                  //debug_print(0, data, strlen);                  //debug_print(0, data, strlen);
7122                  FWD_received_data(pvar, c->local_num, data, strlen);                  FWD_received_data(pvar, c->local_num, data, str_len);
7123    
7124            } else if (c->type == TYPE_SCP) {  // SCP
7125                    if (str_len == 1 && data[0] == '\0') {  // OK
7126    
7127                            if (c->scp.state == SCP_INIT) {
7128                                    char buf[128];
7129    
7130                                    _snprintf_s(buf, sizeof(buf), _TRUNCATE, "T%lu 0 %lu 0\n",
7131                                            (unsigned long)c->scp.filestat.st_mtime,  (unsigned long)c->scp.filestat.st_atime);
7132    
7133                                    c->scp.state = SCP_TIMESTAMP;
7134                                    SSH2_send_channel_data(pvar, c, buf, strlen(buf));
7135    
7136                            } else if (c->scp.state == SCP_TIMESTAMP) {
7137                                    char buf[128];
7138    
7139                                    _snprintf_s(buf, sizeof(buf), _TRUNCATE, "C0644 %lld %s\n",
7140                                            (long long)c->scp.filestat.st_size, c->scp.sendfile);
7141    
7142                                    c->scp.state = SCP_FILEINFO;
7143                                    SSH2_send_channel_data(pvar, c, buf, strlen(buf));
7144    
7145                            } else if (c->scp.state == SCP_FILEINFO) {
7146                                    HANDLE thread;
7147                                    unsigned tid;
7148                                    scp_thread_parm_t *parm = malloc(sizeof(scp_thread_parm_t));
7149    
7150                                    if (parm == NULL) {
7151                                            // TODO:
7152                                    }
7153                                    parm->pvar = pvar;
7154                                    parm->c = c;
7155    
7156                                    thread = (HANDLE)_beginthreadex(NULL, 0, ssh_scp_thread, parm, 0, &tid);
7157                                    if (thread == (HANDLE)-1) {
7158                                            // TODO:
7159                                    }
7160                                    c->scp.thread = thread;
7161    
7162                            } else if (c->scp.state == SCP_DATA) {
7163                                    // 送信完了
7164                                    ssh2_channel_delete(c);  // free channel
7165    
7166                                    MessageBox(NULL, "SCP sending done.", "TTSSH", MB_OK);
7167                            }
7168    
7169                    } else {  // error
7170                            char msg[2048];
7171                            unsigned int i;
7172    
7173                            for (i = 0 ; i < str_len ; i++) {
7174                                    msg[i] = data[i];
7175                            }
7176                            msg[i] = '\0';
7177    
7178                            ssh2_channel_delete(c);  // free channel
7179    
7180                            MessageBox(NULL, msg, "TTSSH: SCP error", MB_OK | MB_ICONEXCLAMATION);
7181                    }
7182          }          }
7183    
7184          //debug_print(200, data, strlen);          //debug_print(200, data, strlen);
7185    
7186          // ウィンドウサイズの調整          // ウィンドウサイズの調整
7187          c->local_window -= strlen;          c->local_window -= str_len;
7188    
7189          do_SSH2_adjust_window_size(pvar, c);          do_SSH2_adjust_window_size(pvar, c);
7190    

Legend:
Removed from v.3073  
changed lines
  Added in v.3074

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