2009/01/06

Recent entries from same category

  1. Zenn で Twitter bot 作成入門を書いた。
  2. プログラマーのための新しい情報共有コミュニティ Zenn で本を書いてみた。
  3. Windows ユーザは cmd.exe で生きるべき 2020年版
  4. Let's Encrypt を簡単操作できる CLI、Lego が MyDNS に対応した。
  5. golang でメモ専用コマンド「memo」作った。

WindowsでGitを使う場合、msysGitというMSYS(Minimal SYStem)ポーティングされたGitを使うのですが、これにはssh-askpassが付いてきません。以前書いた「Big Sky :: Windowsでもssh-agentとssh-addを使ってパスフレーズ入力を省略する。」でご紹介した方法は、開いたコマンドプロンプト内でしか有効になりません。これは新しく起動したコマンドプロンプトに、ssh-agentから引き渡されるSSH_AGENT_PID/SSH_AUTH_SOCKといった環境変数が引き継がれていないのが原因です。これを解決する方法のひとつとして、win-ssh-askpassという物があります。
win-ssh-askpass 1.05 (GANAware)

GUI ssh-agent for cygwin.

http://www.ganaware.jp/archives/2006/04/winsshaskpass_1.html
win-ssh-askpass バージョンアップについてあれこれ (GANAware)

ずいぶん久しぶりに win-ssh-askpass をバージョンアップしました。

http://www.ganaware.jp/archives/2006/04/winsshaskpass_2.html
このwin-ssh-askpassは、ssh-agent起動時に得た環境変数情報をWindowsのユーザ環境変数に登録してくれ、次回起動するコマンドプロンプトでもパスフレーズを聞かれなくするという物です。UNIXだとx11-ssh-askpassとか、ssh-askpass-gnomeというGUIバージョンも存在しますが、これのWindows版という所ですね。
但し、win-ssh-agentはcygwinを使っており、cygwin配下でunix domain socketを使った通信を行っています。unix domain socketを使わず実装されているmsysGitでは動かないのです。他に、puttyのpagent/plinkを使った方法もありますが私が使いたい条件
  • OpenSSH for windows
  • msysGit付属のbashではなく、コマンドプロンプト
  • cygwinは使いたくない
には適応出来なかったりします。
という事で、win-ssh-askpass-1.05のcygwin依存を無くすパッチを書いてみました。
気を付ける所は
  • setenv/putenvの置き換え
  • fork/execからsystemへ
だけです。
以下パッチ diff -u win-ssh-askpass-1.05.orig/agent.cpp win-ssh-askpass-1.05/agent.cpp
--- win-ssh-askpass-1.05.orig/agent.cpp 2006-04-02 10:42:24.000000000 +0900
+++ win-ssh-askpass-1.05/agent.cpp  2009-01-06 17:21:35.953125000 +0900
@@ -2,8 +2,10 @@
 #include <stdlib.h>
 #include <string.h>
 #include <string>
+#ifdef __CYGWIN__
 #include <sys/cygwin.h>
 #include <sys/wait.h>
+#endif
 #include <unistd.h>
 #include <list>
 #include <stdarg.h>
@@ -56,6 +58,7 @@
 // run ssh-add
 int run_ssh_add(const char *i_identityFile)
 {
+#ifdef __CYGWIN__
   pid_t childPID = fork();
   setenv("SSH_ASKPASS", getAskpassPath().c_str(), 1);
   verbose("export SSH_ASKPASS=%s\n", getAskpassPath().c_str());
@@ -95,6 +98,25 @@
       else
    return -1;
   }
+#else
+  std::string str;
+
+  str = "SSH_ASKPASS=";
+  str += getAskpassPath().c_str();
+  putenv(str.c_str());
+  verbose("export SSH_ASKPASS=%s\n", getAskpassPath().c_str());
+
+  str = "DISPLAY=localhost:0";
+  putenv(str.c_str());
+  verbose("exec ssh-add %s\n", i_identityFile ? i_identityFile : "");
+  if (i_identityFile && !i_identityFile[0])
+    i_identityFile = NULL;
+  str = "ssh-add ";
+  if (i_identityFile) str += i_identityFile;
+  str += " < NUL 2> NUL";
+  verbose(str.c_str());
+  system(str.c_str());
+#endif
 }
 
 // http://sourceware.org/ml/cygwin/2006-02/msg00289.html
@@ -118,6 +140,7 @@
       /* Convert POSIX to Win32 where necessary */
       if (!strcmp(var, "PATH") ||
      !strcmp(var, "LD_LIBRARY_PATH")) {
+#ifdef __CYGWIN__
    winpathlist = (char *)
      malloc(cygwin_posix_to_win32_path_list_buf_size(val) + 1);
    if (winpathlist) {
@@ -125,12 +148,19 @@
      SetEnvironmentVariable(var, winpathlist);
      free(winpathlist);
    }
+#else
+   SetEnvironmentVariable(var, val);
+#endif
       } else if (!strcmp(var, "HOME") ||
         !strcmp(var, "TMPDIR") ||
         !strcmp(var, "TMP") ||
         !strcmp(var, "TEMP")) {
+#ifdef __CYGWIN__
    cygwin_conv_to_win32_path(val, winpath);
    SetEnvironmentVariable(var, winpath);
+#else
+   SetEnvironmentVariable(val, winpath);
+#endif
       } else {
    SetEnvironmentVariable(var, val);
       }
@@ -144,7 +174,11 @@
 void run_program(char **i_argv)
 {
   char win32_pathname[1024];
+#ifdef __CYGWIN__
   cygwin_conv_to_win32_path(i_argv[0], win32_pathname);
+#else
+  strcpy(win32_pathname, i_argv[0]);
+#endif
   setup_win_environ();
  
   if (i_argv[1])
@@ -386,7 +420,7 @@
           NULL, NULL, g_hInst, this);
    
     // show tasktray icon
-    std::memset(&m_ni, 0, sizeof(m_ni));
+    memset(&m_ni, 0, sizeof(m_ni));
     m_ni.cbSize = sizeof(m_ni);
     m_ni.uID    = ID_TaskTrayIcon;
     m_ni.hWnd   = m_hwndTaskTray;
@@ -513,7 +547,13 @@
       verbose("DISPLAY=%s\n", getenv("DISPLAY"));
    
     std::string askpassPath(getAskpassPath());
+#ifdef __CYGWIN__
     setenv("SSH_ASKPASS", askpassPath.c_str(), 1);
+#else
+    std::string str("SSH_ASKPASS=");
+    str += askpassPath;
+    putenv(str.c_str());
+#endif
     writeRegistry(HKEY_CURRENT_USER, "Environment", "SSH_AGENT_PID",
          getenv("SSH_AGENT_PID"));
     verbose("export SSH_AGENT_PID=%s\n", getenv("SSH_AGENT_PID"));
diff -u win-ssh-askpass-1.05.orig/misc.cpp win-ssh-askpass-1.05/misc.cpp
--- win-ssh-askpass-1.05.orig/misc.cpp  2002-09-23 03:32:39.000000000 +0900
+++ win-ssh-askpass-1.05/misc.cpp   2009-01-06 17:18:43.656250000 +0900
@@ -1,5 +1,7 @@
 #include "misc.h"
+#ifdef __CYGWIN__
 #include <sys/cygwin.h>
+#endif
 
 // instance
 HINSTANCE g_hInst = NULL;
@@ -74,9 +76,16 @@
 // get the path of win-ssh-askpass.exe
 std::string getSelfPath()
 {
+#ifdef __CYGWIN__
   char win32_pathname[1024];
   GetModuleFileName(NULL, win32_pathname, NUMBER_OF(win32_pathname));
   char posix_pathname[1024];
   cygwin_conv_to_posix_path(win32_pathname, posix_pathname);
   return posix_pathname;
+#else
+  char win32_pathname[1024], *ptr = win32_pathname;
+  GetModuleFileName(NULL, win32_pathname, NUMBER_OF(win32_pathname));
+  while (*ptr++) if (*ptr == '\\') *ptr = '/';
+  return win32_pathname;
+#endif
 }
これを適応すると、mingw32だけでビルド出来る様になります(mingw32-make)。なお、cygwinでビルドすればこれまで通りのモジュールが出来上がります。
ビルド出来たら、win-ssh-agentを起動します。すると
win-ssh-askpass
の様に入力ダイアログが表示されます。ここにパスフレーズを入力すれば、後は次回から起動するコマンドプロンプトで
win-ssh-askpass-console
と環境変数が引き継がれる事になります。
Big Sky :: Windowsでもssh-agentとssh-addを使ってパスフレーズ入力を省略する。」で書いた、setxがあればwin-ssh-agentを使わなくても美味く行くのですが、コマンドプロンプトが出ないので少しカッコよくなりました。
これをWindowsのスタートアップに入れておけば初回にパスフレーズを入力した後は、sshパスフレーズを聞かれる事無くsshが行える様になります。

win-ssh-agent++

よろしければどうぞ。
というか私くらいしか、必要ないか...
Posted at by