VagrantでBOXファイルを読み込む際、ネットワークパス(UNCパス)を指定したら"Can't open file"エラーが出る

  • 投稿日:
  • by
  • Category:

Vagrant_PrimaryLogo_FullColor_RGB.png

Vagrant(2.2.7)を導入して遊んでいたが、以下の問題にぶち当たった。

NAS上にあるBOXファイルを読み込みたかったので、

  • vagrant box add "BOXファイルへのパス" コマンドを叩く
  • Vagrantfile内で box_url="BOXファイルへのパス" を指定する

上記の際にネットワークパス("\\192.168.0.1\share\path")やWindowsのUNCパス("\\computer-name\share\path")を指定したが、"Can't open file"というエラーが出てBOXファイルをロードできなかった。

結果としてはコマンドプロンプトのpushd、popdコマンドを使い一時的にネットワークドライブを割り当てることで対処したが、なぜUNCパスがダメなのかが気になる。

 

 

curlが原因の様子

調べてみると、BOXファイルを読み込む部分はcurlを使っているらしい。

そしてVagrant 2.2.7に付属しているcurlのバージョンは7.68。

なんとも運の悪いことに、このバージョン決め打ちでセキュリティ対策としてfile:プロトコルを使用したSMBアクセスを止められてしまったらしい。

UPDATE

As of March 2020, the curl security team has reconsidered this issue and we no longer consider this a curl security flaw. This "SMB access" (that also can be done using other network protocols) is a Windows feature that cannot be avoided or switched off by an application or library and we have stopped trying. All and any such network accesses via file accesses are no longer considered a curl bug, but a Windows feature. curl and libcurl on Windows that uses FILE:// URLs might generate such probes.

For the sake of history, we keep the advisory as it was originally stated below.

VULNERABILITY

libcurl can be told to load a file from a FILE:// URL. It will then load the file from the path specified in the URL from the local file system.

If you craft the given path so that it starts with two slashes (or backslashes) followed by a host name, Windows systems will automatically treat that as a request to access the host name using SMB instead of reading a local file with that name. This is not expected nor documented libcurl behavior.

Applications allowing users to provide URLs or parts of URLs could be vulnerable to this flaw. Both the curl tool and library.

Example URL exploiting this: file://localhost//hostname/home/secret.txt.

We are not aware of any exploit of this flaw.

これにより、"file://192.168.0.1/share/path"のようなパスでのアクセスが出来なくなったということだ。

ネットワークドライブを割り当てれば "file:///Z:/share/path"のようにローカルパス扱いになるため、こちらは問題がない模様。

 

のちに撤回

UPDATE項にある通り、このセキュリティ対応はのちに撤回された為、curl 7.69や最新の7.70では再度UNCパスが使えるようになっている。

つまり、vagrantと一緒にインストールされたcurlを最新版に置き換えれば問題は解決するということだ。

Vagrant最新版(2.2.9)に付属しているcurlのバージョンまでは調べていないが、もし引き続きcurl 7.68が同梱されているなら新しいバージョンと置き換える必要があるだろう。

 

一筋縄ではいかなかった

これで上手くいったと思いきやまたまたエラーが発生。ネットワークパスに日本語が含まれてしまっているのがダメなようだ。VagrantってかRubyはマルチバイト文字に弱いねほんと。

色々試してみたところ、Ruby(というかRFC3986)の仕様として「URLに非ASCII文字を入れるのはNG」らしく、パスに日本語を入れたままだとVagrant(Ruby)側のバリデーションチェックでURI::InvalidURIError (URI must be ascii only...)エラーが出てしまう。

となるとURLをエンコードするしかないが、そうすると今度はcurlの処理の所でエラーになってしまう。

curlはオプションを付ければエンコードにも対応しているようだが、Vagrantがcurlを呼び出す際はそのあたりは考慮されていないようだ。文字コードの問題もあるし、RubyとWindowsって相性が壊滅的に悪くないか?

 

ネットワークドライブを割り当てよう

Vagrantのソースを書き換えれば何とかなるんだろうが、わざわざ書き換えたものを他PCに展開する手間を考えたら現実的ではない。

結局無改造のまま使うにはネットワークドライブの割り当てが一番いいように思える。

pushd \\192.168.0.1\share\path

vagrant box add "BOXファイル名"

popd

このようなバッチファイルを用意しておけば、実行するだけで

ネットワークドライブ割り当て→BOXファイル取得→ネットワークドライブ解除を一連の流れで実行することができる。

スマートなやり方ではないかもしれないが、本件以外にも散々マルチバイト文字に悩まされてきた身としては沼に嵌る前にサクッと解決できる方法をとった。

 

おまけ file:///のおはなし

「file:///ってなんでスラッシュ3つなの?」と思って調べてみたら、本来は"file://hostname/filepath/"と書くが、hostnameが自分(localhost/127.0.0.1)の場合は省略して"file:///filepath"と書いてもいい、ということらしい。

なのでローカルマシン上のファイルを指定する時は"file:///filepath"と書ける。普段あまり意識してなかったけど、今回よくfile:///を目にして気になっていたので合点がいった。

コメントする