2009/01/06


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



2008/12/18


Perlerと呼ばれる程のスキルは無いのですが...
Perlプログラマーの皆さん - Perl入門~サンプルコードによるPerl入門~

Perlをやっている人のブログをRSSリーダーに登録しておくと最新の事情がわかったりします。

http://d.hatena.ne.jp/perlcodesample/20081217/1229522517
Plaggerで上記リンクからOPML作るYAML書きました。
perler-in-japan.yaml
plugins:
  - module: Subscription::XPath
    config:
      url: http://d.hatena.ne.jp/perlcodesample/20081217/1229522517
      xpath: //div[@class="body"]/div[@class="section"]/blockquote/p/a

  - module: Publish::OPML
    config:
      filename: perler-in-japan.opml
出来上がったOPMLも置いておきます。2008/12/17 14:30:00時点のOPMLです。
Plagger Subscriptions - Perler in Japan
よろしければどうぞ。
Posted at by



2008/12/17


いつも面倒臭いなぁと思いながらブラウザでログインしてバージョン書いたりしてたんですが、勢い余ってスクリプトを書いてしまいました。
使い方は # vim-release.pl -sv=<スクリプトのバージョン> -vv=<vimのバージョン> -msg=<メッセージ> <ファイル>
です。-vvを省略すると7.0が、-msgを省略すると入力プロンプトが表示されます。ユーザおよびパスワードはConfig::Pitで管理します。
実際には、このスクリプトの-svを省略する為の補助が欲しい所ですが、前のバージョンから+1では不味いし、スクリプトから調べるのは無理があるし...で引数にしました。
おそらく私くらいしか使わないかと思いますが、よろしければどうぞ。
gist: 36989 — GitHub
#!perl
use strict;
use warnings;
use Config::Pit;
use Getopt::Long;
use WWW::Mechanize;
use Perl6::Say;

my $conf = pit_get("vim.com", require => {
  "username" => "your username on vim.org", # NOTE: do not edit this line
  "password" => "your password on vim.org", # NOTE: do not edit this line
});

my %args = ( id => '', sv => '', vv => '7.0', msg => '' );
die "invalid args"
  unless GetOptions(\%args, 'id=i', 'sv=s', 'vv=f', 'msg=s');
unless ($args{msg}) {
  print "message: ";
  $args{msg} = <STDIN>;
}

my $file = shift;
die "script version not specified" unless $args{id};
die "message not specified" unless $args{msg};
die "file not specified" unless $file;

my $mech = WWW::Mechanize->new;
$mech->get('http://www.vim.org/login.php');
$mech->submit_form(
    form_name => 'login',
    fields    => {
        userName => $conf->{username},
        password => $conf->{password},
    },
);

$mech->get("http://www.vim.org/scripts/add_script_version.php?script_id=$args{id}");
$mech->form_name('script');
$mech->field(script_file => $file);
$mech->select('vim_version', $args{vv});
$mech->field(script_version => $args{sv});
$mech->field(version_comment => $args{msg});
my $res = $mech->click('add_script');
say $res->is_success ? "uploaded" : $res->status_line;
Gist.vim version 1.1 への更新で上手く動いてそげです。
Posted at by