その際、 sudoers で許可されているユーザならば
- :write ! sudo tee % > /dev/null
で sudo を使って root として書き込むことができます。
ですが、 neovim では
- :write ! sudo tee % > /dev/null
- sudo: no tty present and no askpass program specified
- shell returned 1
と言われて sudo が使えません。
このコマンドは vim と neovim の両方で利用できます。
解決策
以下のようなコマンドを定義することで対応できます。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function! s:sudo_write_current_buffer() abort | |
if has('nvim') | |
let s:askpass_path = '/tmp/askpass' | |
let s:password = inputsecret("Enter Password: ") | |
let $SUDO_ASKPASS = s:askpass_path | |
try | |
call delete(s:askpass_path) | |
call writefile(['#!/bin/sh'], s:askpass_path, 'a') | |
call writefile(["echo '" . s:password . "'"], s:askpass_path, 'a') | |
call setfperm(s:askpass_path, "rwx------") | |
write ! sudo -A tee % > /dev/null | |
finally | |
unlet s:password | |
call delete(s:askpass_path) | |
endtry | |
else | |
write ! sudo tee % > /dev/null | |
endif | |
endfunction | |
command! SudoWriteCurrentBuffer call s:sudo_write_current_buffer() |
neovim で利用する場合は ~/.cofig/nvim/init.vim に追記します。
使い方
- $ nvim /etc/hosts
- root 権限が必要なファイルを開いて編集します。保存の際は
- :SudoWriteCurrentBuffer
- を実行します。
- パスワードを入力すれば root で書き込む事ができます。
動作確認をした環境
大元の環境(vim と neovim で動作確認済)
- OS: macOS Mojave 10.14.6 (18G95)
- Homebrew: 2.1.11
- Homebrew/homebrew-core: (git revision 883ee; last commit 2019-09-01)
- neovim: v0.3.8
- vim: 8.0.1365
- sudo: version 1.8.17p1
- Sudoers policy plugin version 1.8.17p1
- Sudoers file grammar version 45
- Sudoers I/O plugin version 1.8.17p1
- docker: 19.03.1, build 74b1e89
docker を使っていくつかの distribution でも動作を確認
- Alpine linux: 3.10.2
- neovim: v0.3.7
- vim: 8.1.1365
- sudo: version 1.8.27
- Sudoers policy plugin version 1.8.27
- Sudoers file grammar version 46
- Sudoers I/O plugin version 1.8.27
- CentOS: release 7.6.1810 (Core)
- vim: 7.4.1099
- sudo: version 1.8.23
- Sudoers policy plugin version 1.8.23
- Sudoers file grammar version 46
- Sudoers I/O plugin version 1.8.23
- Fedora: release 30
- vim: 8.1.1912
- sudo: version 1.8.27
- Sudoers policy plugin version 1.8.27
- Sudoers file grammar version 46
- Sudoers I/O plugin version 1.8.27
- Ubuntu: 18.04.3
- vim: 8.0.1453
- sudo: version 1.8.21p2
- Sudoers policy plugin version 1.8.21p2
- Sudoers file grammar version 46
- Sudoers I/O plugin version 1.8.21p2
- Debian: 10.0 (buster-20190812)
- vim: 8.1.1401
- sudo: version 1.8.27
- Sudoers policy plugin version 1.8.27
- Sudoers file grammar version 46
- Sudoers I/O plugin version 1.8.27
何故 neovim では sudo が使えないのか
ここから先は先程の Vimscript を作るに至った経緯を書きます。
興味のある方はご覧ください。
まず sudo の error message
- sudo: no tty present and no askpass program specified
を見ると、 tty と askpass が無いと言っています。
tty と askpass
実際、vim では
- : ! tty
- /dev/ttys004
などが得られますが、 neovim では
- : ! tty
- not a tty
- shell returned 1
と言われてしまいます。
askpass は使ったことが無いのですが、fedora の container で dnf search すると
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@9015bf44beee /]# dnf search askpass | |
Fedora Modular 30 - x86_64 1.5 MB/s | 1.9 MB 00:01 | |
Fedora Modular 30 - x86_64 - Updates 2.0 MB/s | 2.8 MB 00:01 | |
Fedora 30 - x86_64 - Updates 5.0 MB/s | 23 MB 00:04 | |
Fedora 30 - x86_64 5.2 MB/s | 61 MB 00:11 | |
Last metadata expiration check: 0:00:01 ago on Sat Aug 31 00:41:37 2019. | |
=============================== Name & Summary Matched: askpass ================================ | |
lxqt-openssh-askpass-l10n.x86_64 : Translations for lxqt-openssh-askpass | |
lxqt-openssh-askpass.x86_64 : Askpass openssh transition dialog for LXQt desktop suite | |
==================================== Name Matched: askpass ===================================== | |
R-askpass.x86_64 : Safe Password Entry for R, Git, and SSH | |
ksshaskpass.x86_64 : A ssh-add helper that uses kwallet and kpassworddialog | |
openssh-askpass.x86_64 : A passphrase dialog for OpenSSH and X | |
x11-ssh-askpass.x86_64 : A passphrase dialog for X and not only for OpenSSH |
- x11-ssh-askpass
- openssh-askpass
- ksshaskpass
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# dnf install -y x11-ssh-askpass | |
# find . -name '*askpass*' -type f | |
./etc/profile.d/x11-ssh-askpass.sh | |
./etc/profile.d/x11-ssh-askpass.csh | |
./usr/libexec/openssh/x11-ssh-askpass | |
# /usr/libexec/openssh/x11-ssh-askpass | |
Error: Can't open display: | |
# /usr/libexec/openssh/x11-ssh-askpass --help | |
Error: Can't open display: | |
# dnf remove -y x11-ssh-askpass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# dnf install -y openssh-askpass | |
# find . -name '*askpass*' -type f | |
./etc/profile.d/gnome-ssh-askpass.csh | |
./etc/profile.d/gnome-ssh-askpass.sh | |
./usr/libexec/openssh/gnome-ssh-askpass | |
# /usr/libexec/openssh/gnome-ssh-askpass | |
(gnome-ssh-askpass:112): Gtk-WARNING **: 00:51:47.072: cannot open display: | |
# /usr/libexec/openssh/gnome-ssh-askpass --help | |
(gnome-ssh-askpass:113): Gtk-WARNING **: 00:52:10.596: cannot open display: | |
# dnf remove -y openssh-askpass |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# dnf install -y ksshaskpass | |
# find . -name '*askpass*' -type f | |
./etc/xdg/plasma-workspace/env/ksshaskpass.sh | |
./usr/share/locale/en_GB/LC_MESSAGES/ksshaskpass.mo | |
./usr/bin/ksshaskpass | |
/usr/bin/ksshaskpass | |
# /usr/bin/ksshaskpass --help | |
qt.qpa.xcb: could not connect to display | |
qt.qpa.plugin: Could not load the Qt platform plugin "xcb" in "" even though it was found. | |
This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem. | |
Available platform plugins are: eglfs, linuxfb, minimal, minimalegl, offscreen, vnc, xcb. | |
Aborted | |
# dnf remove -y ksshaskpass |
ですがエラーの内容的に display を開こうとしているのが分かります。
なので、おそらく GUI で password を聞くような物だと思われます。
askpass を作る
askpass について調べていると、どうやら
- password を stdout に出力するもの
であることが分かりました。
よって
- neovim 内で password を取得
- password を stdout に出力する
- password の履歴はどこにも残さない
ようなものを作れば解決できそうです。
それで完成したのが /tmp/askpass を作るこの Vimscript です。
本当はファイル名は固定でなく tempfile 的な物で対応するなど、改善点はいくつも存在するかと思います。
ですが私は Vimscript に明るくないので、"3つの条件を満たして動けばOK" という条件で作成しました。
他により良い対応方法があればご指摘頂けると幸いです。
その他の解決策
これを使わなかった理由としては
- docker のコンテナ内で作業をする事が多々ある
- init.vim を配置するスクリプトは既にある
- plugin を install するスクリプトはまだ無い
- 全コンテナに plugin を入れるのも面倒だし結構サイズがある
- $ du -sh ~/.config/nvim/repos
- 100M /Users/atton/.config/nvim/repos
などがあります。
また、"sudo が使えるならこの際 root になってしまう" という解決策もあるのですが
また、"sudo が使えるならこの際 root になってしまう" という解決策もあるのですが
- 前述した理由の後半3つ
- 複数人数のユーザが使う環境だと、 /root 配下に自分専用の設定を置くことになる
のでこちらも無しで。
他には、 "sudoers で NOPASSWD を設定する" という解決策もあります。
が、sudo を no password でガンガン使えば実質 root で作業しているのと変わらず、危険すぎるのでこちらも無し。
ということでこの Vimscript を書くに至った、という訳なのです。
他には、 "sudoers で NOPASSWD を設定する" という解決策もあります。
が、sudo を no password でガンガン使えば実質 root で作業しているのと変わらず、危険すぎるのでこちらも無し。
ということでこの Vimscript を書くに至った、という訳なのです。
おまけ: 環境変数の unlet
スクリプト内部では askpass の場所を示す SUDO_ASKPASS を設定している部分があります。
具体的には
具体的には
- let $SUDO_ASKPASS = s:askpass_path
ですね。
この環境変数を定義していると、 sudo -A した際に指定したファイルが実行されます。
この環境変数を定義していると、 sudo -A した際に指定したファイルが実行されます。
一応、 :SudoWriteCurrentBuffer の実行後にはなるべく元の環境に戻すために
- unlet $SUDO_ASKPASS
を書いていた時もありました。
ですが動作確認中、 Vim 8.0.1365 で unlet 時にエラーが出てしまいました。
ですが動作確認中、 Vim 8.0.1365 で unlet 時にエラーが出てしまいました。
また 、-A を指定しなければ sudo の動作は変わらないので 、残っていても無害と判断して unlet しない形になりました。
おまけ: shebang を指定しないとどうなるのか
ちなみに askpass の shebang を消すと
- sudo: unable to run /tmp/askpass: Exec format error
- sudo: no password was provided
と言われる為、きちんと書いておく必要があります。
おまけ: x flag を付けないとどうなるのか
setfperm(s:askpass_path, "rwxr-xr-x") をせずに 644 のままだと- sudo: unable to run /tmp/askpass: Permission denied
- sudo: no password was provided
と言われるので、こちらもきちんと指定しておく必要があります。
参考
- Checking the Current TTY
- sudo: no tty present and no askpass program specified · Issue #8527 · neovim/neovim · GitHub
- GitHub - lambdalisue/suda.vim: An alternative sudo.vim for Vim and Neovim, limited support sudo in Windows
- GitHub - vim-scripts/sudo.vim: Allows one to edit a file with prevledges from an unprivledged session.
- askpassのことを書いておく - なんかかきたい
- man sudo
- neovim :help
- User input from a script | Vim Tips Wiki | FANDOM powered by Wikia
- Vim documentation: eval
0 件のコメント:
コメントを投稿