macOS, Linux で Dropbox を fuse mount する dbxfs を少し試す

Dropbox を FUSE mount 出来る dbxfs というものを見つけたので試してみました.

Doropbox の Linux client はファイルシステムがext4のみと制限されます.dbxfs であればおそらくこの制限も問題ないのではないかと思います.(未確認)

The Dropbox folder will need to be on an ext4-formatted hard drive or partition
Note: ecryptfs is not supported, but Dropbox will continue to sync with supported file systems that are encrypted via full disk encryption (e.g. LUKS)

導入
$ sudo apt install libfuse2 python3-pip
help
$ ~/.local/bin/dbxfs -h
usage: dbxfs [-h] [-f] [-v] [-s] [-n] [-l SMB_LISTEN_ADDRESS] [-c CONFIG_FILE]
			 [-e ENCRYPTED_FOLDERS] [--print-default-config-file]
			 [mount_point]

positional arguments:
  mount_point

optional arguments:
  -h, --help            show this help message and exit
  -f, --foreground      keep filesystem server in foreground
  -v, --verbose         show log messages, use twice for maximum verbosity
  -s, --smb             force mounting via SMB
  -n, --smb-no-mount    export filesystem via SMB but don't mount it
  -l SMB_LISTEN_ADDRESS, --smb-listen-address SMB_LISTEN_ADDRESS
						address that SMB service should listen on, append
						colon to specify port
  -c CONFIG_FILE, --config-file CONFIG_FILE
						config file path
  -e ENCRYPTED_FOLDERS, --encrypted-folder ENCRYPTED_FOLDERS
						relative paths of encrypted folders, can be used
						multiple times. requires safefs
  --print-default-config-file
						print default config file path to standard out and
						quit
初回mount
$ ~/.local/bin/dbxfs ~/fuse/dbxfs
We need an access token. Perform the following steps:
1. Go to https://www.dropbox.com/oauth2/authorize?response_type=code&client_id=vinkudorurc8kno
2. Click "Allow" (you may have to log in first)
3. Copy the authorization code.
Enter authoritization code (Ctrl-C to quit): NodigIOndefkiwitshOrackazEuweavirtyedCibEdI
We're all connected. Do you want to save your credentials for future runs? [Y/n] Y
Would you like to help us improve dbxfs by providing anonymous error reports? [Y/n] Y
Mount point "/home/matoken/fuse/dbxfs" doesn't exist, do you want to create it? [Y/n] Y
  1. のurl をブラウザで開いて認証を行う
    認証後の画面で cli-dbxfs のアクセスを許可する.

45084023501 7cfd7c4058

許可後に表示されるトークンを 3. の後ろにコピー&ペーストする.

  • We’re all connected. Do you want to save your credentials for future runs?
    次回以降のために資格情報を保存するか?
  • Would you like to help us improve dbxfs by providing anonymous error reports?
    匿名のエラー報告を行いdbxfsに改善の支援を行うか?
  • Mount point “/home/matoken/fuse/dbxfs” doesn’t exist, do you want to create it?
    マウントポイントが存在しないので作成するか?
マウント確認
$ ls ~/fuse/dbxfs/
アンマウントする
$ fusermount -u ~/fuse/dbxfs
資格情報を保存していた場合2回目以降のマウントは何も聞かれない
$ ~/.local/bin/dbxfs ~/fuse/dbxfs

.

アクセストークンをpgpファイルに格納することも出来るようだが手元の環境では未だうまく行っていない(多分何か勘違いをしている)

EDIT: やはり使い方が間違っていた.次の記事に書いた -> Dropbox を FUSE mount する dbxfs のアクセストークンを gpg で暗号化する – matoken’s meme

設定ファイルの場所確認
$ ~/.local/bin/dbxfs --print-default-config-file
/home/matoken/.config/dbxfs/config.json
アクセストークンをpgpファイルにする
$ jq . /home/matoken/.config/dbxfs/config.json
{
  "keyring_user": "yigwulbaf6shnutugaivkilj",
  "send_error_reports": true,
  "asked_send_error_reports": true
}
$ gpg -r EAA13B982D937827 -e /home/matoken/.config/dbxfs/config.json
$ ls -l /home/matoken/.config/dbxfs/config.json*
-rw-r--r-- 1 matoken matoken 115 10月  4 07:19 /home/matoken/.config/dbxfs/config.json
-rw-r--r-- 1 matoken matoken 685 10月  4 07:22 /home/matoken/.config/dbxfs/config.json.gpg
$ shred /home/matoken/.config/dbxfs/config.json
$ echo '"access_token_command": ["gpg", "--decrypt", "/home/matoken/.config/dbxfs/config.json.gpg"]' > /home/matoken/.config/dbxfs/config.json
マウント
$ ~/.local/bin/dbxfs ~/fuse/dbxfs
Running 'gpg --decrypt /home/matoken/.config/dbxfs/config.json.gpg' for access token
gpg: 4096-ビットRSA鍵, ID EAA13B982D937827, 日付2015-06-11に暗号化されました
      "K.I.Matohara <matoken@gmail.com>"
Traceback (most recent call last):
  File "/home/matoken/.local/bin/dbxfs", line 11, in <module>
    sys.exit(main())
  File "/home/matoken/.local/lib/python3.6/site-packages/dbxfs/main.py", line 212, in main
    dropbox.Dropbox(access_token).users_get_current_account()
  File "/home/matoken/.local/lib/python3.6/site-packages/dropbox/base.py", line 4245, in users_get_current_account
    None,
  File "/home/matoken/.local/lib/python3.6/site-packages/dropbox/dropbox.py", line 274, in request
    timeout=timeout)
  File "/home/matoken/.local/lib/python3.6/site-packages/dropbox/dropbox.py", line 365, in request_json_string_with_retry
    timeout=timeout)
  File "/home/matoken/.local/lib/python3.6/site-packages/dropbox/dropbox.py", line 449, in request_json_string
    timeout=timeout,
  File "/home/matoken/.local/lib/python3.6/site-packages/requests/sessions.py", line 559, in post
    return self.request('POST', url, data=data, json=json, **kwargs)
  File "/home/matoken/.local/lib/python3.6/site-packages/requests/sessions.py", line 498, in request
    prep = self.prepare_request(req)
  File "/home/matoken/.local/lib/python3.6/site-packages/requests/sessions.py", line 441, in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "/home/matoken/.local/lib/python3.6/site-packages/requests/models.py", line 310, in prepare
    self.prepare_headers(headers)
  File "/home/matoken/.local/lib/python3.6/site-packages/requests/models.py", line 444, in prepare_headers
    check_header_validity(header)
  File "/home/matoken/.local/lib/python3.6/site-packages/requests/utils.py", line 941, in check_header_validity
    raise InvalidHeader("Invalid return character or leading space in header: %s" % name)
requests.exceptions.InvalidHeader: Invalid return character or leading space in header: Authorization

持ち運びモバイルPCだと辛いでしょうが,据え置きデスクトップ環境などのオンラインのマシンでは便利そうです.

環境
$ grep ^Version: ~/.local/lib/python3.6/site-packages/dbxfs-1.0.4.dist-info/METADATA
Version: 1.0.4
$ dpkg-query -W libfuse2 python3-pip
libfuse2:amd64  2.9.8-2
python3-pip     9.0.1-2.3
$ lsb_release -d
Description:    Debian GNU/Linux unstable (sid)
$ uname -m
x86_64

ADSLモデムのNATテーブル溢れで困る

古いADSL モデムで自宅サーバを立てている場合の話なので現代では役に立たないでしょうが健忘録として書いておきます.(光回線?圏外なのですorz)

環境
ADSLモデム-SV3
Hardware Revision: 0001
Software Version: 03.20 (Tue Jul 27 20:45:13 JST 2010)
Boot ROM Version: 01.00 (Thu Jun 3 17:07:20 JST 2004)
DSP Firmware Version: 42.20
VDSP Firmware Version: 9.1.60.12

最近よく家のネットワークで名前解決できなくなることがあります.
DNSが多段になっていて無駄が多いのでそのへんの問題かなと思ったのですが,直接ISP や 8.8.8.8 とか 1.1.1.1 とかの PublicDNS に問い合わせても引けません.

ISP — Unbound — PiHole — PC

ip 直なら繋がるだろうと試すとhttpもsshも駄目です.タイムアウトになります.

ルータを再起動すると直ることもあれば,直ってもすぐに元に戻ってしまうこともあります.

ルータのログみると tcp80 に大量のアクセスがあってそれで NAT table が溢れてしまって繋がらないということのようです.NAT table は 1024 しかないのですが,一度に 1 ipから200〜400回くらいのアクセスが来てこれが複数回来ると NAT table が溢れてしまい通信ができなくなるようです.
#NAT table を増やす設定変更項目は見当たらない

31167785778 8d6ed1d3d7

とりあえずルータを再起動しなくてもNAT table をクリアすると一時的に通信できるようになります.でもどんどんこのアクセスが来てすぐに元に戻ります.おまけにこのアクセスは「有効期限(秒)」が9000とかになっているのでなかなかクリアされません.(ほかは60のよう)
#有効期限の設定変更項目は見当たらない

ip を逆引きしてみると大抵は一般の利用者のようで名前が振られていないレンジや,ipアドレス-domain みたいな名前です.おそらく何かのウィルスに感染して攻撃をしているのではないかと思います.(Google Cloud とかもあったけど……)
幸い自宅サーバのtcp80はhttpsへのリダイレクトとテスト用なのでこれらのアクセスをブロックしてみました.
whois で inetnum を確認して,CIDR を計算して「パケットフィルタ設定」でこのネットワークの tcp80 へのアクセスを drop するように設定してNAT table クリアでドロップされるようにありました.ドロップは「セキュリティログ」で確認できます.

44992821992 770d5444e2

これを繰り返していたのですが設定は64個しか書けません.すぐに溢れました…….

別のアプローチを考えます.
このADSLモデムのweb管理画面はレガシーでcurlでアクセスできます.

NAT table の登録件数を求める
$ echo $(curl  -s -u 'user:password' 'http://192.168.1.1/cgi-bin/main.cgi?mbg_webname=nattbl'|lynx -stdin -dump -width=256|grep -m1 '現在の登録件数'|sed -e 's/^.*:\(.*\)\/.*$/\1/')
308

NATクリアも同様に出来ます.

NATテーブル消去
$ curl  -s -u 'user:password' -F 'mbg_webname=natclear' -F 'nat_clear=消去' 'http://192.168.1.1/cgi-bin/main.cgi' | lynx -stdin -dump
   NATテーブル消去
   [1]ヘルプ [2]help
   -----

   NATテーブルの消去を行いました。

   戻る

参照

   1. file:///cgi-bin/main.cgi?mbg_webname=help&mbg_helpname=natclear
   2. file:///cgi-bin/main.cgi?mbg_webname=help&mbg_helpname=natclear

これを使って NAT table を確認して,溢れそうだったらクリアするscriptを用意してみました.

script の中に書きたくないので ID/PASSWORDは ~/.netrc に書いておきます.

// EDIT : wgetに怒られたので netrc の machine を ADSL ROUTER から ADSL_ROUTER に変更(scriptも)
// wget: /home/mk/.netrc:1: "ROUTER" は不明な区切り記号(token)です

~/.netrc に追記
$ echo 'machine ADSL_ROUTER
> login user
> password  password
> ' | tee -a ~/.netrc
machine ADSL_ROUTER
login user
password  password

適当な script を用意して,

nat_clear.bash
#!/bin/bash

# ~/.netrc 読み込み
usrinfo=(`awk 'c&&c--;/ADSL_ROUTER/{c=2}' $HOME/.netrc | awk '{printf "%s ", $2}'`)
USER=${usrinfo[0]}
PASS=${usrinfo[1]}

# NAT table 登録数確認
NAT_TABLE=$(curl  -s -u "${USER}:${PASS}" 'http://192.168.1.1/cgi-bin/main.cgi?mbg_webname=nattbl'|lynx -stdin -dump -width=256|grep -m1 '現在の登録件数'|sed -e 's/^.*:\(.*\)\/.*$/\1/')

# NAT table が 750 より大きいとNAT table clear
if[ 750 -lt $NAT_TABLE ]; then
  echo "NAT table clrar(${NAT_TABLE})"
  # tcp:80 にアクセスしている ip を確認して表示
  curl  -s -u "${USER}:${PASS}" 'http://192.168.1.1/cgi-bin/main.cgi?mbg_webname=nattbl' | lynx -stdin -dump -width=256 | grep 192.168.1.102/80 | awk {'print $6'} | cut -f1 -d\/ | sort | uniq -c
  # NAT table clear
  curl  -s -u "${USER}:${PASS}" -F 'mbg_webname=natclear' -F 'nat_clear=消去' 'http://192.168.1.1/cgi-bin/main.cgi' | lynx -stdin -dump
fi

実行権を付与.

$ chmod +x nat_clear.bash

crontab に登録して5分毎に呼ぶように設定.

// EDIT: 1024使い切ってからクリアが多いので3分毎に変更した

$ crontab -e
crontab: installing new crontab
$ crontab -l | grep nat_clear.bash
*/5 * * * *     /home/mk/bin/nat_clear.bash

// EDIT: 実際に動作したときのログ追記

NAT table clrar(1024)
    837 103.234.73.6
    102 51.254.167.83
   NATテーブル消去
   [1]ヘルプ [2]help
   -----

   NATテーブルの消去を行いました。

   戻る

References

   1. file:///cgi-bin/main.cgi?mbg_webname=help&mbg_helpname=natclear
   2. file:///cgi-bin/main.cgi?mbg_webname=help&mbg_helpname=natclear

とりあえずこれで様子見中です.しかし対処療法でアクセスが増えたら耐えられなくりますね…….
サーバ機能を引っ越して外部からのアクセスを遮断したらこの問題は解決するはずですが出来たら選びたくないです.
ADSLモデムを高機能なものに置き換えると設定でどうにかなるかもとか,しかしそもそもADSL自体が収束なので製品が存在するのか?

とか思いながら設定項目を見ていると「PPPoEブリッジ機能」というものがありました.これを使うとADSLモデムの裏のサーバ等からPPPoEで繋げそうな感じがします.それが出来たらn分以内にn回アクセスがあったらしばらく無視するとか柔軟な設定が出来るようになります.次はこれを試してみたいと思います.

30105335967 6ed05163ae

#光回線はよ……

Nautilus が起動しなくなって困る

Nautilus が起動しなくなりました.nemo は起動するんだけど……
$ nautilus

(nautilus:16178): Tracker-ERROR **: 19:36:23.259: Unable to find default domain ontology rule /usr/share/tracker/domain-ontologies/default.rule
Trace/breakpoint trap
このファイルはなんだろうと中を覗こうとしたら存在しない
$ lv /usr/share/tracker/domain-ontologies/default.rule
/usr/share/tracker/domain-ontologies/default.rule: No such file or directory
tracker pkg に含まれるらしい
$ apt-file search /usr/share/tracker/domain-ontologies/default.rule
tracker: /usr/share/tracker/domain-ontologies/default.rule
インデックスや検索関連
$ apt show tracker
Package: tracker
Version: 2.1.4-1
Priority: optional
Section: utils
Maintainer: Debian GNOME Maintainers <pkg-gnome-maintainers@lists.alioth.debian.org>
Installed-Size: 3,453 kB
Depends: libc6 (>= 2.4), libglib2.0-0 (>= 2.45.3), libtracker-control-2.0-0 (= 2.1.4-1), libtracker-sparql-2.0-0 (= 2.1.4-1), dconf-gsettings-backend | gsettings-backend, shared-mime-info, libglib2.0-bin, default-dbus-session-bus | dbus-session-bus
Recommends: tracker-miner-fs
Homepage: https://wiki.gnome.org/Projects/Tracker
Tag: implemented-in::c, interface::commandline, interface::daemon,
 network::client, network::server, role::program, scope::utility,
 use::organizing, use::searching, works-with::db, works-with::file,
 works-with::pim
Download-Size: 1,009 kB
APT-Manual-Installed: yes
APT-Sources: http://ftp.jp.debian.org/debian sid/main amd64 Packages
Description: メタデータデータベース、索引付けおよび検索ツール
 Tracker は、メタデータとタグに関連付けられた第一クラスオブジェクト用の
 先進的なフレームワークです。全てのメタデータ、タグ、共有オブジェクト
 データベース、検索ツールと索引に対する統一されたソリューションを提供します。

N: 追加レコードが 1 件あります。表示するには '-a' スイッチを付けてください。
導入したら起動するようになりました
$ sudo apt install tracker
環境
$ dpkg-query -W $(dpkg -l nautilus* | grep ^ii | awk {'print $2'} ) tracker nemo
nautilus        3.30.0-4
nautilus-actions        3.2.3-1+b2
nautilus-compare        0.0.4+po1-1
nautilus-data   3.30.0-4
nautilus-filename-repairer      0.2.0-1
nautilus-gtkhash        1.1.1-3.1
nautilus-hide   0.2.3-4
nautilus-image-converter        0.3.1~git20110416-2
nautilus-image-manipulator      1.3-2
nautilus-scripts-manager        2.0-1
nautilus-share  0.7.3-2
nautilus-wipe   0.3-1
nemo    3.8.5-1
tracker 2.1.4-1
$ lsb_release -d
Description:    Debian GNU/Linux unstable (sid)
$ uname -m
x86_64

ssh環境での誤ったシステム停止を防ぐmolly-guard

最近 shutdown の man を見比べたりしてたのですが,そのときに systemd, sysvinit 以外に molly-guard という見知らぬものが.

$ apt-file search /sbin/shutdown
molly-guard: /sbin/shutdown
systemd-sysv: /sbin/shutdown
sysvinit-core: /sbin/shutdown

パッケージ情報をみると shutdown コマンドなどを置き換えて ssh 接続時には確認のためにホスト名を聞くようになるようです.
これにより手元のPCの再起動をしたつもりがリモートのサーバを再起動してしまうなどといったことが防げるようになります.

$ apt show molly-guard
Package: molly-guard
Version: 0.6.4
Priority: extra
Section: admin
Maintainer: Francois Marier <francois@debian.org>
Installed-Size: 57.3 kB
Depends: procps
Enhances: init, kexec-tools, mosh, openssh-server, pm-utils, systemd, sysvinit, upstart
Tag: implemented-in::shell, interface::commandline, network::server,
 protocol::ssh, role::program, scope::utility
Download-Size: 13.8 kB
APT-Manual-Installed: yes
APT-Sources: http://ftp.jp.debian.org/debian stretch/main amd64 Packages
Description: protects machines from accidental shutdowns/reboots
 The package installs a shell script that overrides the existing
 shutdown/reboot/halt/poweroff/coldreboot/pm-hibernate/pm-suspend* commands
 and first runs a set of scripts, which all have to exit successfully,
 before molly-guard invokes the real command.
 .
 One of the scripts checks for existing SSH sessions. If any of the four
 commands are called interactively over an SSH session, the shell script
 prompts you to enter the name of the host you wish to shut down. This should
 adequately prevent you from accidental shutdowns and reboots.
 .
 molly-guard diverts the real binaries to /lib/molly-guard/.  You can bypass
 molly-guard by running those binaries directly.

早速試してみます.

$ sudo apt install molly-guard
    :
package diverts others to: /lib/molly-guard/coldreboot
/sbin/halt
package diverts others to: /lib/molly-guard/halt
/sbin/pm-hibernate
/sbin/pm-suspend
/sbin/pm-suspend-hybrid
/sbin/poweroff
package diverts others to: /lib/molly-guard/poweroff
/sbin/reboot
package diverts others to: /lib/molly-guard/reboot
/sbin/shutdown
package diverts others to: /lib/molly-guard/shutdown

このあたりのコマンドが置き換わっています.

$ ls -l /sbin | grep molly
lrwxrwxrwx 1 root root        28 Aug 16  2016 coldreboot -> /lib/molly-guard/molly-guard
lrwxrwxrwx 1 root root        28 Aug 16  2016 halt -> /lib/molly-guard/molly-guard
lrwxrwxrwx 1 root root        28 Aug 16  2016 pm-hibernate -> /lib/molly-guard/molly-guard
lrwxrwxrwx 1 root root        28 Aug 16  2016 pm-suspend -> /lib/molly-guard/molly-guard
lrwxrwxrwx 1 root root        28 Aug 16  2016 pm-suspend-hybrid -> /lib/molly-guard/molly-guard
lrwxrwxrwx 1 root root        28 Aug 16  2016 poweroff -> /lib/molly-guard/molly-guard
lrwxrwxrwx 1 root root        28 Aug 16  2016 reboot -> /lib/molly-guard/molly-guard
lrwxrwxrwx 1 root root        28 Aug 16  2016 shutdown -> /lib/molly-guard/molly-guard

コマンド類は /lib/molly-guard 以下に退避されるようです.

sysvinit
$ ls -lA /lib/molly-guard
total 48
-rwxr-xr-x 1 root root 18952 Feb 13  2017 halt
-rwxr-xr-x 1 root root  2767 Aug 16  2016 molly-guard
lrwxrwxrwx 1 root root     4 Feb 13  2017 poweroff -> halt
lrwxrwxrwx 1 root root     4 Feb 13  2017 reboot -> halt
-rwxr-xr-x 1 root root 23368 Feb 13  2017 shutdown
systemd
$ ls -lA /lib/molly-guard
total 4
lrwxrwxrwx 1 root root   14 Jun 14 05:20 halt -> /bin/systemctl
-rwxr-xr-x 1 root root 2767 Aug 16  2016 molly-guard
lrwxrwxrwx 1 root root   14 Jun 14 05:20 poweroff -> /bin/systemctl
lrwxrwxrwx 1 root root   14 Jun 14 05:20 reboot -> /bin/systemctl
lrwxrwxrwx 1 root root   14 Jun 14 05:20 shutdown -> /bin/systemctl

ssh 経由で shutdown(sysvinit) を試みるとこのように hostname を求められます.ここで誤った hostname を書くと shutdown がキャンセルされました.

$ sudo shutdown -f -P -h +10 "kernel update (`uname -r`)"
W: molly-guard: SSH session detected!
Please type in hostname of the machine to shutdown: desktop
Good thing I asked; I won't shutdown debian ...
W: aborting shutdown due to 30-query-hostname exiting with code 1.

正しい hostname を指定すると shutdown が呼ばれます.

$ sudo shutdown -f -P -h +10 "kernel update (`uname -r`)"
W: molly-guard: SSH session detected!
Please type in hostname of the machine to shutdown: debian

Broadcast message from root@debian (pts/0) (Thu Sep 27 06:15:28 2018):

kernel update (4.9.0-3-amd64)
The system is going DOWN for system halt in 10 minutes!
^C
Shutdown cancelled.

ssh経由でない場合は molly-guard はすぐに shutdown を呼びます.

$ sudo shutdown -f -P -h +10 'poweroff'
^C
Shutdown cancelled.

環境

$ dpkg-query -W systemd-sysv molly-guard
molly-guard     0.6.4
systemd-sysv    232-25+deb9u4
$ dpkg-query -W sysvinit-core
sysvinit-core   2.88dsf-59.9
$ cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 9 (stretch)"
NAME="Debian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"
$ cat /etc/debian_version
9.5
$ uname -m
x86_64

qcow2 イメージをマウント

qemuやKVMでよく使われるqcow2イメージのマウントを行いました.

イメージの確認
$ sudo qemu-img info /var/lib/libvirt/images/Debian.qcow2
image: /var/lib/libvirt/images/Debian.qcow2
file format: qcow2
virtual size: 20G (21474836480 bytes)
disk size: 20G
cluster_size: 65536
Format specific information:
	compat: 1.1
	lazy refcounts: true
	refcount bits: 16
	corrupt: false
nbd モジュールの読み込み
$ sudo modprobe nbd
qcow2 イメージのバインド
$ sudo qemu-nbd -c /dev/nbd0 /var/lib/libvirt/images/Debian.qcow2
$ sudo fdisk -l /dev/nbd0
ディスク /dev/nbd0: 20 GiB, 21474836480 バイト, 41943040 セクタ
単位: セクタ (1 * 512 = 512 バイト)
セクタサイズ (論理 / 物理): 512 バイト / 512 バイト
I/O サイズ (最小 / 推奨): 512 バイト / 512 バイト
ディスクラベルのタイプ: dos
ディスク識別子: 0x3c0808c8

デバイス    起動 開始位置 終了位置   セクタ サイズ Id タイプ
/dev/nbd0p1 *        2048   499711   497664   243M 83 Linux
/dev/nbd0p2        501758 41940991 41439234  19.8G  5 拡張領域
/dev/nbd0p5        501760 41940991 41439232  19.8G 83 Linux
kpartx でデバイスマッピング
$ sudo kpartx /dev/nbd0
nbd0p1 : 0 497664 /dev/nbd0 2048
nbd0p2 : 0 2 /dev/nbd0 501758
nbd0p5 : 0 41439232 /dev/dm-1 2
dm-crypt で暗号化されているのでデバイスをオープン
$ sudo cryptsetup open /dev/nbd0p5 crypt
Enter passphrase for /dev/nbd0p5:
lvm領域なのでスキャンする
$ sudo lvmdiskscan
    :
  /dev/mapper/crypt                                     [     <19.76 GiB] LVM physical volume
  /dev/nbd0p5                                           [     <19.76 GiB]
  /dev/debian-vg/root                                   [      18.75 GiB]
  /dev/debian-vg/swap_1                                 [       1.00 GiB]
    :
マウントして内容確認
$ sudo mount -o ro /dev/debian-vg/root /mnt
$ ls /mnt/
bin   dev  home        initrd.img.old  lib64       media  opt   root  sbin  sys  usr  vmlinuz
boot  etc  initrd.img  lib             lost+found  mnt    proc  run   srv   tmp  var  vmlinuz.old
Table of Contents

環境

$ dpkg-query -W kpartx qemu-utils fdisk cryptsetup lvm2 mount linux-image-`uname -r`
cryptsetup      2:2.0.4-2
fdisk   2.32.1-0.1
kpartx  0.7.7-1
linux-image-4.18.0-1-amd64      4.18.8-1
lvm2    2.02.176-4.1
mount   2.32.1-0.1
qemu-utils      1:2.12+dfsg-3
$ lsb_release -d
Description:    Debian GNU/Linux unstable (sid)
$ uname -m
x86_64

Linuxの Google Chrome/Chromium でサインインと同期を無効にする

を見てなるほどと思ったのだけど,macOS, Windows の手順はあるけれどLinux の手順がないなてことで調べてみました.

参考にしたのはこちら.

/etc/opt/chrome, /etc/opt/chromium 以下に json 形式で設定ファイルを設定するだけでした.

Google Chrome の場合

ディレクトリ作成
$ sudo mkdir -p /etc/opt/chrome/policies/managed /etc/opt/chrome/policies/recommended
/etc/opt/chrome/policies/managed/disablesync.json に設定ファイル設置
{
        "SyncDisabled":true,
        "RestrictSigninToPattern":".*@example.com"
}

Chromium の場合

ディレクトリ作成
$ sudo mkdir -p /etc/opt/chromium/policies/managed /etc/opt/chromium/policies/recommended
/etc/opt/chromium/policies/managed/disablesync.json に設定ファイル設置
{
        "SyncDisabled":true,
        "RestrictSigninToPattern":".*@example.com"
}

環境

$ dpkg-query -W google-chrome-stable chromium
chromium        69.0.3497.92-1
google-chrome-stable    69.0.3497.100-1
$ lsb_release -d
Description:    Debian GNU/Linux unstable (sid)
$ uname -m
x86_64

CLI なワンタイムパスワードマネージャの cloak を試す

Rust製のコマンドラインで動作するワンタイムパスワードマネージャです.TOTP/HOTP に対応しています.

Table of Contents

導入

Rust package managerのcargoを導入
$ sudo apt install cargo
cargoでcloakを導入
$ cargo install cloak

~/.cargo/ 以下に導入される

試してみる

help
$ ~/.cargo/bin/cloak --help
cloak 0.1.0
Evans Murithi <murithievans80@gmail.com>
A Command Line OTP Authenticator application.

USAGE:
	cloak [SUBCOMMAND]

FLAGS:
	-h, --help       Prints help information
	-V, --version    Prints version information

SUBCOMMANDS:
	add               Add a new account
	delete            Delete an account
	help              Prints this message or the help of the given subcommand(s)
	list              List OTP for all accounts
	recovery_codes    View recovery codes for an account
	view              View the OTP for an account
add サブコマンドで登録する
$ ~/.cargo/bin/cloak add --help
cloak-add
Add a new account

USAGE:
	cloak add [FLAGS] [OPTIONS] <account> <key>

FLAGS:
	-h, --help       Prints help information
		--hotp       Counter based account
		--totp       Time based account (default)
	-V, --version    Prints version information

OPTIONS:
	-a, --algorithm <ALGORITHM>    Algorithm to use to generate the OTP code [possible values: SHA1, SHA256, SHA384,
								   SHA512, SHA512_256]

ARGS:
	<account>    Name of the account
	<key>        Secret key of the OTP
$ ~/.cargo/bin/cloak add matoken@home.nextcloud M0KMYFVOZY7AGX47
Account successfully created
登録情報確認
$ ~/.cargo/bin/cloak list
Account: matoken@home.nextcloud
TOTP: 538273
アカウントを指定してTOTPトークン表示
$ ~/.cargo/bin/cloak view matoken@home.nextcloud
370696
設定ファイルには生で情報が格納されるので取扱注意
$ cat ~/.cloak/accounts
["matoken@home.nextcloud"]
key = "M0KMYFVOZY7AGX47"
totp = true
hash_function = "SHA1"
アクセス権もそのままでは危ないので注意
$ ls -l ~/.cloak/accounts
-rw-r--r-- 1 matoken matoken 87  9月 22 06:19 /home/matoken/.cloak/accounts
$ chmod -R go-rx ~/.cloak
$ chattr +s ~/.cloak/accounts
$ ls -la ~/.cloak
合計 12
drwx------  2 matoken matoken 4096  9月 22 06:19 .
drwxr-xr-x 62 matoken matoken 4096  9月 23 19:58 ..
-rw-------  1 matoken matoken   87  9月 22 06:19 accounts

秘密鍵が平文でそのままファイルに格納されるので最低でもecryptfsは設定しておかないとかなな感じ?

私は現在はoathtoolを使ったscriptを使っています.秘密鍵はファイルに手で書いて暗号化しておきscript実行時に復号してoathtoolに渡してTOTP表示という感じ.若しくはKeePassCX.

環境

$ ~/.cargo/bin/cloak -V
cloak 0.1.0
$ dpkg-query -W cargo
cargo   0.29.0-1
$ lsb_release -d
Description:    Debian GNU/Linux unstable (sid)
$ uname -m
x86_64

Nextcloud 14 の Telegram を使った2要素認証

先日ファイル共有ソフトの Nextcloud 14がリリースされました.

新機能のうちSignal/Telegram/SMS による2要素認証のサポートが気になります.

Signal/Telegram/SMS 2FA support
A new 2-factor authentication provider named ‘gateway’ was introduced which allows users to use the secure messaging apps Signal and Telegram as well as various SMS gateways as second factor to secure their authentication.

SMSはplaySMS, websms.deを利用するようです.SignalもTelegramもセキュアなメッセージングサービスなのでこういう用途に向いていそうです.どちらも公式でLinux x86_64のデスクトップアプリが提供されています.アプリの出来は今の所Telegramのほうが上だと思います.Arm Linuxだと公式のものはないのですが,TelegramについてはCLIのアプリがあり,Raspberry Pi の Raspbian stretch でも要patchで動作しました.(Webアプリもあるのでそちらでも動作すると思うが未確認)

SMSはやったことがあるし,Telegram が使いやすい.てことでTelegramの設定をしてみました.まだ未実装な機能が多くちょっと面倒なのでメモしておきます.

Two-Factor Gateway の導入

Nextcloud 14に Two-Factor Gateway アプリを導入します.管理者アカウントで「アプリ」の「セキュリティ」から導入するのが楽でしょう.

導入するとNextcloudの「設定」の「セキュリティ」の中に「Message gateway second-factor auth」という項目が現れますが,設定が出来ません.

GitHubのドキュメントをみると未だ未実装の機能が多いようです.

Telegram Bot の作成

TOTPコードの送信する Telegram Bot を作成します.作成はTelegram のドキュメントを参照して作成します.

BotFather と会話してbot作成

BotFather という bot 管理用の bot が居るので,会話してbot を作成します.

アイコンちょっと怖い

44062365934 5aabe8f64d m

/newbot コマンドで新しい bot の作成が始まります.botの名前を効かれるので答えます.続いて bot の username を求められます.この username は最後に bot とつける必要があります.
成功するとアクセストークンが表示されるのでメモして次の手旬に移ります.以下の例では 640093430:AAFTa_pSAcKCZWeFoVDt-l7h7ewqzNe0Luo がトークンです.

Done! Congratulations on your new bot. You will find it at t.me/matoken_bot. You can now add a description, about section and profile picture for your bot, see /help for a list of commands. By the way, when you've finished creating your cool bot, ping our Bot Support if you want a better username for it. Just make sure the bot is fully operational before you do this.

Use this token to access the HTTP API:
640093430:AAFTa_pSAcKCZWeFoVDt-l7h7ewqzNe0Luo

For a description of the Bot API, see this page: https://core.telegram.org/bots/api

30910879338 4609b7a707
44781979421 aac86c72de

occ コマンドで Telegram bot のトークン設定

Nextcloud のインストールされている場所に Nextcloud 管理用の occ コマンドがあります.このコマンドで Telegram bot のトークンを設定します.
トークンの 640093430: 部分は省いてその後ろだけを入力します.

$ sudo -u www-data php ./occ twofactorauth:gateway:configure telegram
Please enter your Telegram bot token: AAFTa_pSAcKCZWeFoVDt-l7h7ewqzNe0Luo
Using AAFTa_pSAcKCZWeFoVDt-l7h7ewqzNe0Luo.
$ sudo -u www-data php ./occ twofactorauth:gateway:status
Signal gateway: not configured
SMS gateway: not configured
Telegram gateway: configured

ひとまずこれで管理者側の設定は終了です.

Telegram bot の chat_id を調べて登録する

ここからはNextcloud の利用アカウントでの操作になります.

Telegram
In order to receive authentication codes via Telegram, you first have to start a new chat with the bot set up by your admin.
Secondly, you have to obtain your Telegram ID via the ID Bot. Enter this ID to receive your verification code below.

You are not using Telegram for two-factor authentication at the moment. Enable

Telegram アプリを利用して,Telegram の bot から TOTPコードを受け取りたい Telegram アカウントに適当なメッセージを投げます.

@matoken hello

その後,Telegram API を利用してメッセージを取得して chat_id を調べます.
以下の例では 475721977 です.

$ curl https://api.telegram.org/bot640093430:AAHu9u_c12KC2PY8g22QZoA94u4tAJvxsvY/getUpdates | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   358  100   358    0     0    315      0  0:00:01  0:00:01 --:--:--   315
{
  "ok": true,
  "result": [
    {
      "update_id": 612249686,
      "message": {
        "message_id": 9,
        "from": {
          "id": 475721977,
          "is_bot": false,
          "first_name": "matoken",
          "username": "matoken",
          "language_code": "En"
        },
        "chat": {
          "id": 475721977,
          "first_name": "matoken",
          "username": "matoken",
          "type": "private"
        },
        "date": 1537282406,
        "text": "@matoken hello",
        "entities": [
          {
            "offset": 0,
            "length": 8,
            "type": "mention"
          }
        ]
      }
    }
  ]
}

試しに送信してみて Telegram アプリに bot からメッセージが飛んできたら chat id が正しいはず.

$ curl -X POST "https://api.telegram.org/bot640093430:AAHu9u_c12KC2PY8g22QZoA94u4tAJvxsvY" -d "chat_id=475721977&text=hello" | jq
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   274  100   246  100    28    179     20  0:00:01  0:00:01 --:--:--   200
{
  "ok": true,
  "result": {
    "message_id": 15,
    "from": {
      "id": 640093430,
      "is_bot": true,
      "first_name": "matoken_bot",
      "username": "matoken_bot"
    },
    "chat": {
      "id": 475721977,
      "first_name": "matoken",
      "username": "matoken",
      "type": "private"
    },
    "date": 1537312183,
    "text": "hello"
  }
}

Nextcloud にログインして,「設定」→「セキュリティ」の下部に「Message gateway second-factor auth」という項目が出来ているので「Enable」を押す.

Telegram
In order to receive authentication codes via Telegram, you first have to start a new chat with the bot set up by your admin.
Secondly, you have to obtain your Telegram ID via the ID Bot. Enter this ID to receive your verification code below.

You are not using Telegram for two-factor authentication at the moment. Enable

以下のメッセージが表示されたら chat_id を入力して Verify します.

Enter your identification (e.g. phone number to start the verification):
 Verify

Telegram で TOTPコードが飛んで来るのでそれを入力したらOKです.
一旦ログアウトして試してみましょう.

Telegram 認証を試す

いつものようにユーザ名,パスワードで認証すると以下のような画面に遷移します.
「Authenticate via Telegram」を押します.

44781965201 94bd9ca33e

Telegram から認証コードが飛んでくるのでそれを入力して認証完了です.

30910872108 2d5e8c21eb

めんどくさい……

未だ手順が面倒で一般ユーザに試してくれと言える状態ではないですね.でも次のリリースあたりでは簡単になるんじゃないでしょうか.

環境

$ sudo -u www-data php ./occ app:list|grep twofactor_|grep :
  - twofactor_backupcodes: 1.3.1
  - twofactor_gateway: 0.9.0
  - twofactor_totp: 1.5.0
$ sudo -u www-data php ./occ -V
Nextcloud 14.0.0
$ lsb_release -d
Description:    Ubuntu 16.04.5 LTS
$ uname -m
x86_64

Telegram の非公式cli client の telegram-cli を試す

Arm でも動くかな?と試してみました.

必要パッケージの導入
$ sudo apt install libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev make libssl1.0-dev
sourceをcloneする
$ git clone --recursive https://github.com/vysheng/tg.git && cd tg
configure & make
$ ./configure
$ make
build error1
tgl/crypto/rsa_pem_openssl.c: In function ‘TGLC_rsa_new’:
tgl/crypto/rsa_pem_openssl.c:41:6: error: dereferencing pointer to incomplete type ‘RSA {aka struct rsa_st}’
   ret->e = unwrap_bn (TGLC_bn_new ());
      ^~
tgl/crypto/rsa_pem_openssl.c: In function ‘TGLC_rsa_n’:
tgl/crypto/rsa_pem_openssl.c:52:1: error: control reaches end of non-void function [-Werror=return-type]
 RSA_GETTER(n);
 ^~~~~~~~~~
tgl/crypto/rsa_pem_openssl.c: In function ‘TGLC_rsa_e’:
tgl/crypto/rsa_pem_openssl.c:53:1: error: control reaches end of non-void function [-Werror=return-type]
 RSA_GETTER(e);
 ^~~~~~~~~~
cc1: all warnings being treated as errors
Makefile.tgl:20: recipe for target 'objs/crypto/rsa_pem_openssl.o' failed
make: *** [objs/crypto/rsa_pem_openssl.o] Error 1

libssl-dev(1.1.1)では動作しないのでlibssl1.0-devに入れ替える. sudo apt install libssl1.0-dev

build error2
gcc -I. -I. -I./tgl -w  -I/usr/local/include -I/usr/include -I/usr/include -I/usr/include/lua5.2  -DHAVE_CONFIG_H -Wall -Werror -Wextra -Wno-missing-field-initializers -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb -Wno-unused-parameter -fPIC -iquote ./tgl/tl-parser -c -MP -MD -MF dep/tl-parser.d -MQ objs/tl-parser.o -o objs/tl-parser.o tgl/tl-parser/tl-parser.c
tgl/tl-parser/tl-parser.c:37:10: fatal error: zlib.h: そのようなファイルやディレクトリはありません
 #include <zlib.h>
          ^~~~~~~~
compilation terminated.
make: *** [Makefile.tl-parser:4: objs/tl-parser.o] エラー 1

zlib1g-dev を導入する. sudo apt install zlib1g-dev

Raspbian stretchでの実行時エラー(32bit環境での不具合?)
$ bin/telegram-cli
Telegram-cli version 1.4.1, Copyright (C) 2013-2015 Vitaly Valtman
Telegram-cli comes with ABSOLUTELY NO WARRANTY; for details type `show_license'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show_license' for details.
Telegram-cli uses libtgl version 2.1.0
Telegram-cli includes software developed by the OpenSSL Project
for use in the OpenSSL Toolkit. (http://www.openssl.org/)
I: config dir=[/home/pi/.telegram-cli]
> telegram-cli: tgl/mtproto-utils.c:101: BN2ull: Assertion `0' failed.
SIGNAL received

以下の修正を行い, make clean して build しなおす.

$ diff -ud tgl/mtproto-utils.c.org tgl/mtproto-utils.c
--- tgl/mtproto-utils.c.org     2018-09-19 21:01:44.878560077 +0900
+++ tgl/mtproto-utils.c 2018-09-19 20:59:55.778295550 +0900
@@ -98,13 +98,13 @@
   if (sizeof (unsigned long) == 8) {
	 return TGLC_bn_get_word (b);
   } else if (sizeof (unsigned long long) == 8) {
-    assert (0); // As long as nobody ever uses this code, assume it is broken.
+    assert (0);  As long as nobody ever uses this code, assume it is broken.
	 unsigned long long tmp;
	 /* Here be dragons, but it should be okay due to be64toh */
	 TGLC_bn_bn2bin (b, (unsigned char *) &tmp);
	 return be64toh (tmp);
   } else {
-    assert (0);
+//    assert (0);
   }
 }
$ make clean
$ ./configure
$ make
初回実行時はSMS認証が必要
$ bin/telegram-cli
Telegram-cli version 1.4.1, Copyright (C) 2013-2015 Vitaly Valtman
Telegram-cli comes with ABSOLUTELY NO WARRANTY; for details type `show_license'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show_license' for details.
Telegram-cli uses libtgl version 2.1.0
Telegram-cli includes software developed by the OpenSSL Project
for use in the OpenSSL Toolkit. (http://www.openssl.org/)
I: config dir=[/home/mk/.telegram-cli]
[/home/mk/.telegram-cli] created
[/home/mk/.telegram-cli/downloads] created
phone number: +81-9000000000
code ('CALL' for phone code): 16802
User matoken updated flags
User matoken online (was online [2018/09/18 23:55:32])
User matoken offline (was online [2018/09/18 23:50:35])
認証を行うとメッセージが飛んでくる
matoken,

We detected a login into your account from a new device on 19/09/2018 at 12:28:55 UTC.

Device: Unix Console
Location: Shizuoka, Japan (IP = 180.131.110.140)

If this wasn't you, you can go to Settings - Privacy and Security - Sessions and terminate that session.

If you think that somebody logged in to your account against your will, you can enable two-step verification in Privacy and Security settings.

Sincerely,
The Telegram Team
メッセージを送信してみる
> msg @matoken hello
telegram-cli の help
$ bin/telegram-cli --help
telegram-cli Usage
  --phone/-u                           specify username (would not be asked during authorization)
  --rsa-key/-k                         specify location of public key (possible multiple entries)
  --verbosity/-v                       increase verbosity (0-ERROR 1-WARNIN 2-NOTICE 3+-DEBUG-levels)
  --enable-msg-id/-N                   message num mode
  --config/-c                          config file name
  --profile/-p                         use specified profile
  --log-level/-l                       log level
  --sync-from-start/-f                 during authorization fetch all messages since registration
  --disable-auto-accept/-E             disable auto accept of encrypted chats
  --lua-script/-s                      lua script file
  --wait-dialog-list/-W                send dialog_list query and wait for answer before reading input
  --disable-colors/-C                  disable color output
  --disable-readline/-R                disable readline
  --alert/-A                           enable bell notifications
  --daemonize/-d                       daemon mode
  --logname/-L <log-name>              log file name
  --username/-U <user-name>            change uid after start
  --groupname/-G <group-name>          change gid after start
  --disable-output/-D                  disable output
  --tcp-port/-P <port>                 port to listen for input commands
  --udp-socket/-S <socket-name>        unix socket to create
  --exec/-e <commands>                 make commands end exit
  --disable-names/-I                   use user and chat IDs in updates instead of names
  --enable-ipv6/-6                     use ipv6 (may be unstable)
  --help/-h                            prints this help
  --accept-any-tcp                     accepts tcp connections from any src (only loopback by default)
  --disable-link-preview               disables server-side previews to links
  --bot/-b                             bot mode
  --json                               prints answers and values in json format
  --permanent-msg-ids                  use permanent msg ids
  --permanent-peer-ids                 use permanent peer ids
telegram-cli 起動時のhelp
$ bin/telegram-cli -e help
Telegram-cli version 1.4.1, Copyright (C) 2013-2015 Vitaly Valtman
Telegram-cli comes with ABSOLUTELY NO WARRANTY; for details type `show_license'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show_license' for details.
Telegram-cli uses libtgl version 2.1.0
Telegram-cli includes software developed by the OpenSSL Project
for use in the OpenSSL Toolkit. (http://www.openssl.org/)
I: config dir=[/home/pi/.telegram-cli]
[33;1maccept_secret_chat <secret chat>  Accepts secret chat. Only useful with -E option
add_contact <phone> <first name> <last name>    Tries to add user to contact list
block_user <user>       Blocks user
broadcast <user>+ <text>        Sends text to several users at once
channel_get_admins <channel> [limit=100] [offset=0]     Gets channel admins
channel_get_members <channel> [limit=100] [offset=0]    Gets channel members
channel_info <channel>  Prints info about channel (id, members, admin, etc.)
channel_invite <channel> <user> Invites user to channel
channel_join <channel>  Joins to channel
channel_kick <channel> <user>   Kicks user from channel
channel_leave <channel> Leaves from channel
channel_list [limit=100] [offset=0]     List of last channels
channel_set_about <channel> <about>     Sets channel about info.
channel_set_admin <channel> <admin> <type>      Sets channel admin. 0 - not admin, 1 - moderator, 2 - editor
channel_set_username <channel> <username>       Sets channel username info.
channel_set_photo <channel> <filename>  Sets channel photo. Photo will be cropped to square
chat_add_user <chat> <user> [msgs-to-forward]   Adds user to chat. Sends him last msgs-to-forward message from this chat. Default 100
chat_del_user <chat> <user>     Deletes user from chat
chat_info <chat>        Prints info about chat (id, members, admin, etc.)
chat_set_photo <chat> <filename>        Sets chat photo. Photo will be cropped to square
chat_upgrade <chat>     Upgrades chat to megagroup
chat_with_peer <peer>   Interface option. All input will be treated as messages to this peer. Type /quit to end this mode
clear   Clears all data and exits. For debug.
contact_list    Prints contact list
contact_search username Searches user by username
create_channel <name> <about> <user>+   Creates channel with users
create_group_chat <name> <user>+        Creates group chat with users
create_secret_chat <user>       Starts creation of secret chat
del_contact <user>      Deletes contact from contact list
delete_msg <msg-id>     Deletes message
dialog_list [limit=100] [offset=0]      List of last conversations
export_card     Prints card that can be imported by another user with import_card method
export_channel_link     Prints channel link that can be used to join to channel
export_chat_link        Prints chat link that can be used to join to chat
fwd <peer> <msg-id>+    Forwards message to peer. Forward to secret chats is forbidden
fwd_media <peer> <msg-id>       Forwards message media to peer. Forward to secret chats is forbidden. Result slightly differs from fwd
get_terms_of_service    Prints telegram's terms of service
get_message <msg-id>    Get message by id
get_self        Get our user info
help [command]  Prints this help
history <peer> [limit] [offset] Prints messages with this peer (most recent message lower). Also marks messages as read
import_card <card>      Gets user by card and prints it name. You can then send messages to him as usual
import_chat_link <hash> Joins to chat by link
import_channel_link <hash>      Joins to channel by link
load_audio <msg-id>     Downloads file to downloads dirs. Prints file name after download end
load_channel_photo <channel>    Downloads file to downloads dirs. Prints file name after download end
load_chat_photo <chat>  Downloads file to downloads dirs. Prints file name after download end
load_document <msg-id>  Downloads file to downloads dirs. Prints file name after download end
load_document_thumb <msg-id>    Downloads file to downloads dirs. Prints file name after download end
load_file <msg-id>      Downloads file to downloads dirs. Prints file name after download end
load_file_thumb <msg-id>        Downloads file to downloads dirs. Prints file name after download end
load_photo <msg-id>     Downloads file to downloads dirs. Prints file name after download end
load_user_photo <user>  Downloads file to downloads dirs. Prints file name after download end
load_video <msg-id>     Downloads file to downloads dirs. Prints file name after download end
load_video_thumb <msg-id>       Downloads file to downloads dirs. Prints file name after download end
main_session    Sends updates to this connection (or terminal). Useful only with listening socket
mark_read <peer>        Marks messages with peer as read
msg <peer> <text>       Sends text message to peer
msg <peer> <kbd> <text> Sends text message to peer with custom kbd
post <peer> <text>      Sends text message to peer as admin
post_audio <peer> <file>        Posts audio to peer
post_document <peer> <file>     Posts document to peer
post_file <peer> <file> Sends document to peer
post_location <peer> <latitude> <longitude>     Sends geo location
post_photo <peer> <file>       Sends photo to peer
post_text <peer> <file> Sends contents of text file as plain text message
post_video <peer> <file>       Sends video to peer
quit    Quits immediately
rename_channel <channel> <new name>     Renames channel
rename_chat <chat> <new name>   Renames chat
rename_contact <user> <first name> <last name>  Renames contact
reply <msg-id> <text>   Sends text reply to message
reply_audio <msg-id> <file>     Sends audio to peer
reply_contact <msg-id> <phone> <first-name> <last-name> Sends contact (not necessary telegram user)
reply_document <msg-id> <file>  Sends document to peer
reply_file <msg-id> <file>      Sends document to peer
reply_location <msg-id> <latitude> <longitude>  Sends geo location
reply_photo <msg-id> <file>    Sends photo to peer
reply_video <msg-id> <file>     Sends video to peer
resolve_username username       Searches user by username
safe_quit       Waits for all queries to end, then quits
search [peer] [limit] [from] [to] [offset] pattern      Search for pattern in messages from date from to date to (unixtime) in messages with peer (if peer not
present, in all messages)
send_audio <peer> <file>        Sends audio to peer
send_contact <peer> <phone> <first-name> <last-name>    Sends contact (not necessary telegram user)
send_document <peer> <file>     Sends document to peer
send_file <peer> <file> Sends document to peer
send_location <peer> <latitude> <longitude>     Sends geo location
send_photo <peer> <file>       Sends photo to peer
send_text <peer> <file> Sends contents of text file as plain text message
send_typing <peer> [status]     Sends typing notification. You can supply a custom status (range 0-10): none, typing, cancel, record video, upload video, recor
d audio, upload audio, upload photo, upload document, geo, choose contact.
send_typing_abort <peer>        Sends typing notification abort
send_video <peer> <file>       Sends video to peer
set <param> <value>     Sets value of param. Currently available: log_level, debug_verbosity, alarm, msg_num
set_password <hint>     Sets password
set_profile_name <first-name> <last-name>       Sets profile name.
set_profile_photo <filename>    Sets profile photo. Photo will be cropped to square
set_ttl <secret chat>   Sets secret chat ttl. Client itself ignores ttl
set_username <name>     Sets username.
set_phone_number <phone>        Changes the phone number of this account
show_license    Prints contents of GPL license
start_bot <bot> <chat> <data>   Adds bot to chat
stats   For debug purpose
status_online   Sets status as online
status_offline  Sets status as offline
unblock_user <user>     Unblocks user
user_info <user>        Prints info about user (id, last online, phone)
version Prints client and library version
view_audio <msg-id>     Downloads file to downloads dirs. Then tries to open it with system default action
view_channel_photo <channel>    Downloads file to downloads dirs. Then tries to open it with system default action
view_chat_photo <chat>  Downloads file to downloads dirs. Then tries to open it with system default action
view_document <msg-id>  Downloads file to downloads dirs. Then tries to open it with system default action
view_document_thumb <msg-id>    Downloads file to downloads dirs. Then tries to open it with system default action
view_file <msg-id>      Downloads file to downloads dirs. Then tries to open it with system default action
view_file_thumb <msg-id>        Downloads file to downloads dirs. Then tries to open it with system default action
view_photo <msg-id>     Downloads file to downloads dirs. Then tries to open it with system default action
view_user_photo <user>  Downloads file to downloads dirs. Then tries to open it with system default action
view_video <msg-id>     Downloads file to downloads dirs. Then tries to open it with system default action
view_video_thumb <msg-id>       Downloads file to downloads dirs. Then tries to open it with system default action
view <msg-id>   Tries to view message contents
visualize_key <secret chat>     Prints visualization of encryption key (first 16 bytes sha1 of it in fact)
[0mAll done. Exit
halt

大抵のことは出来る感じです.

試した環境1
$ git log --decorate|head -7
commit 6547c0b21b977b327b3c5e8142963f4bc246187a (HEAD -> master, origin/master, origin/HEAD)
Merge: 443793d 160231b
Author: V V <vvaltman@aurum>
Date:   Wed Mar 23 14:42:53 2016 +0300
Merge github.com:vysheng/tg
$ dpkg-query -W libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev make libssl1.0-dev
libconfig-dev:armhf     1.5-0.3
libevent-dev    2.0.21-stable-3
libjansson-dev:armhf    2.9-1
liblua5.2-dev:armhf     5.2.4-1.1
libpython-dev:armhf     2.7.13-2
libreadline-dev:armhf   7.0-3
libssl-dev
libssl1.0-dev:armhf     1.0.2l-2+deb9u3
lua5.2  5.2.4-1.1
make    4.1-9.1
$ lsb_release -d
Description:    Raspbian GNU/Linux 9.4 (stretch)
$ uname -m
armv7l
$ cat /proc/device-tree/model ;echo
Raspberry Pi 2 Model B Rev 1.1
試した環境2
$ git log --decorate|head -7
commit 6547c0b21b977b327b3c5e8142963f4bc246187a (HEAD -> master, origin/master, origin/HEAD)
Merge: 443793d 160231b
Author: V V <vvaltman@aurum>
Date:   Wed Mar 23 14:42:53 2016 +0300
Merge github.com:vysheng/tg
$ dpkg-query -W libreadline-dev libconfig-dev libssl-dev lua5.2 liblua5.2-dev libevent-dev libjansson-dev libpython-dev make libssl1.0-dev
libconfig-dev:amd64     1.5-0.4
libevent-dev    2.1.8-stable-4build1
libjansson-dev:amd64    2.11-1
liblua5.2-dev:amd64     5.2.4-1.1build1
libpython-dev:amd64     2.7.15~rc1-1
libreadline-dev:amd64   7.0-3
libssl-dev
libssl1.0-dev:amd64     1.0.2n-1ubuntu5.1
lua5.2  5.2.4-1.1build1
make    4.1-9.1ubuntu1
$ lsb_release -d
Description:    Ubuntu 18.04.1 LTS
(mk)-(jobs:0)-(~/src/tg)
$ uname -m
x86_64

デーモンの起動しないSMTPクライアントの msmtp を試す(sSMTP乗り換え)

sSMTP から msmtp へ

現在メールを受け取らずメールを送信するだけのホストではsSMTPをよく使っています.MTAはeximやPostfix等でも良いのですが,デーモンが起動しないのでその分セキュアで設定も楽です.
しかし,sSMTPは最近メンテされていません,Debian などのディストリビューションではまだメンテナンスされていますが新機能が入ったりはしないでしょう.

ssmtp is unmaintained. Consider using something like msmtp instead.
バージョンも据え置きでUpstreamも無さそう
$ w3m -dump https://packages.qa.debian.org/s/ssmtp.html|grep versions -A11
versions ... ...pool
o-o-stable
save 2.64-7
oldstable
save 2.64-8
stable
save 2.64-8
unstable
save 2.64-8
Ubuntu
2.64-8ubuntu2
$ apt show ssmtp 2>/dev/null |grep Homepage
Homepage: http://packages.qa.debian.org/s/ssmtp.html

そこで,alternativeto.net で挙げられている msmtp を試してみました.

以下では色々試していますが,システムメールを送るだけなら msmtp, msmtp-mta pkg を導入,/etc/msmtprc の設定だけでokです.

msmtp の導入

Debian sid/Ubuntu 18.04 LTS などではパッケージがあったのでこれを導入しました.

$ sudo apt install msmtp

mstpの設定

設定例が /usr/share/doc/msmtp/examples/ 以下にあるので
システム設定の場合は msmtprc-system.example`/etc/msmtprc にcpして設定.
ユーザ設定の場合は msmtprc-user.example~/.msmtprc にcpして設定する.

システムでの設定例

以下の例では root が読み書きできて,一般ユーザのmatokenアカウントは読み込みが可能な設定ファイル /etc/msmtprc を作成している.
defaults セクションに共通設定を書き,account セクションにメールサーバ固有の設定を書く.account セクションは複数書けて,account default に規定account を指定する.以下の例ではgmail が規定値となる.

/etc/msmtprc の作成
$ sudo install /dev/null /etc/msmtprc -o root -g root -m 600
$ sudo setfacl -m u:matoken:r /etc/msmtprc
$ getfacl /etc/msmtprc
getfacl: Removing leading '/' from absolute path names
# file: etc/msmtprc
# owner: root
# group: root
user::rw-
user:matoken:r--
group::---
mask::r--
other::---
$ sudo vi /etc/msmtprc
$ sudo grep -v ^# /etc/msmtprc
defaults
syslog on
aliases /etc/aliases
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
auth on
syslog LOG_MAIL
account gmail
host smtp.gmail.com
port 587
from example@gmail.com
user example
password porseypacdoadwif
account default : gmail

※gmailの多要素認証を利用している場合は以下からアプリパスワードを生成する.(使い回しができちゃうけれど流出したときの影響を考えて設定毎に発行する)

ユーザでの設定

ユーザの設定ファイルは`~/.msmtprc` 若しくは $XDG_CONFIG_HOME/msmtp/config でシステムと違い,alias file と log を適当なファイルにした.
アカウントも増やしてみた.
gmailのアプリパスワードも新たに発行した.

~/.msmtprc の作成
$ install /dev/null ~/.msmtprc -o matoken -g matoken -m 600
$ vi ~/.msmtprc
$ grep -v ^# ~/.msmtprc
defaults
logfile ~/.msmtp.log
aliases ~/.msmtp.aliases
tls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
auth on
syslog LOG_MAIL
account gmail
host smtp.gmail.com
port 587
from example@gmail.com
user example
password igeinleedafchygy
account yandex
tls_starttls off
host smtp.yandex.com
port 465
from example@yandex.com
user example
password throjfeekdewxeib
account nifty
tls_starttls off
host smtp.nifty.com
port 465
from example@nifty.com
user aaa99999
password 9Z#9999X
account default : gmail

送信テスト

msmtp コマンドで送信テストが出来る.
-a オプションでアカウントが指定できる.
-C オプションで設定ファイルが指定できる.(システムとユーザの設定を両方テストする)

$ echo "hello system msmtp" | msmtp -C /etc/msmtprc matohara@gmail.com
$ echo "hello user msmtp" | msmtp -C ~/.msmtprc -a gmail matohara@gmail.com

大抵のMTAでは . でmail body 終了となるが,msmtpでは`.`は普通にbody に含まれる.Ctrl + d で終了.

$ msmtp -a gmail matohara@gmail.com
Subject: hello
msmtp test
.
dot では終了にならない
Ctrl+d で終了
^d

aliases file

msmtp設定ファイルの alias で設定できる.

$ grep alias ~/.msmtprc
aliases ~/.msmtp.alias
$ sudo grep alias /etc/msmtprc
aliases /etc/aliases

このalias fileは通常のaliases ファイルと同じ形式の plain text で newaliases コマンドでの変換は不要.

メールアドレスは複数指定できる.default という名前は規定アドレスとなる.

root: hoge@example.com, fuga@example.com
default: piyo@example.com

以前のaliases ファイルを流用して以下のようにしてみたところ,

# /etc/aliases
mailer-daemon: postmaster
postmaster: root
nobody: root
hostmaster: root
usenet: root
news: root
webmaster: root
www: root
ftp: root
abuse: root
noc: root
security: root
root: matohara@gmail.com
default: matohara@gmail.com

以下のようにエラーとなった.alias先はユーザ名ではエラーとなるよう.

$ echo hello | sudo msmtp -C /etc/msmtprc root
msmtp: /etc/aliases: line 2: invalid address 'postmaster'

以下のようにそれぞれにメールアドレスを指定すると期待した動作となった.

$ sudo sed -i -e 's/ root$\| postmaster$/matohara@gmail.com/' /etc/aliases
$ cat /etc/aliases
# /etc/aliases
mailer-daemon:matohara@gmail.com
postmaster:matohara@gmail.com
nobody:matohara@gmail.com
hostmaster:matohara@gmail.com
usenet:matohara@gmail.com
news:matohara@gmail.com
webmaster:matohara@gmail.com
www:matohara@gmail.com
ftp:matohara@gmail.com
abuse:matohara@gmail.com
noc:matohara@gmail.com
security:matohara@gmail.com
root: matohara@gmail.com
default: matohara@gmail.com

パスワードをGnuPG暗号化ファイルに格納して利用する

パスワードをgpgで暗号化したファイルに格納することが可能.この場合アカウントごとにファイルが必要なのが少し面倒.
password porseypacdoadwif の場合 porseypacdoadwif 部分だけを暗号化してファイルに格納する.(はじめpassword も含めてしまい失敗した)

$ grep ^password\  ~/.msmtprc | head -1 | awk {'print $2'} | gpg2 --default-recipient-self -e - > ~/.msmtp-password-gmail.gpg
$ grep ^password\  ~/.msmtprc | head -2 | tail -1 | awk {'print $2'} | gpg2 --default-recipient-self -e - > ~/.msmtp-password-yandex.gpg
$ grep ^password\  ~/.msmtprc | tail -1 | awk {'print $2'} | gpg2 --default-recipient-self -e - > ~/.msmtp-password-nifty.gpg

msmtprc の password を削除して,代わりに passwordeval gpg2 --no-tty -q -d 暗号ファイル と設定を変更する.

$ grep ^passworde ~/.msmtprc
passwordeval gpg2 --no-tty -q -d ~/.msmtp-password-gmail.gpg
passwordeval gpg2 --no-tty -q -d ~/.msmtp-password-yandex.gpg
passwordeval gpg2 --no-tty -q -d ~/.msmtp-password-nifty.gpg

後はこれまでのようにmsmtpを呼ぶとgpg-agentが起動する.

※システム側はシステムメールが送れなくなるのでこの設定をしないほうがいいと思う.

パスワードをopenssl暗号化ファイルに格納

システムメールでgpg agentを利用するのは多分無理なのでopensslで暗号化してみる.パスワードはNICのmac addressにしてある.気休めレベルだけど試しに設定.
マシンが乗っ取られた場合はどうしようもないけれど /etc/msmtprc, /etc/msmtp-password ファイル流出時の時間稼ぎくらいにはなる?
NIC が使っていないものも含め増減したり変更になった場合は復元できなくなるので注意.

mac address をパスワードとしてopensslで暗号化
$ umask 0077; grep ^password\  /etc/msmtprc | head -1 | awk {'print $2'} | sudo openssl enc -e -md sha256 -aes-256-cbc -a -A -salt -pbkdf2 -in /dev/stdin -out /etc/msmtp-password -pass pass:`hwinfo --network | grep 'Permanent HW Address' | sed 's/^.*: //' | sort -n | tr -d '\n'`
復元テスト
$ sudo openssl enc -d -md sha256 -aes-256-cbc -a -A -salt -pbkdf2 -in /etc/msmtp-password -pass pass:`hwinfo --network | grep 'Permanent HW Address' | sed 's/^.*: //' | sort -n | tr -d '\n'`
igeinleedafchygy
/etc/msmtprc の password を削除して passwordeval に書き換え
$ grep passworde /etc/msmtprc
passwordeval openssl enc -d -md sha256 -aes-256-cbc -a -A -salt -pbkdf2 -in /etc/msmtp-password -pass pass:`hwinfo --network | grep 'Permanent HW Address' | sed 's/^.*: //' | sort -n | tr -d '\n'`

※ifconfigやiproute2を使わずhwinfoを使ってPermanent HW Addressを使っているのはmac address偽装対策

MTA パッケージの導入

msmtp コマンドでメールが送信できるようになったら,msmtp-mta pkg を導入する.これでsendmailコマンドにシンボリックリンクが張られて同様に利用できるようになる.システムメールも飛ぶようになる.

$ sudo apt install msmtp-mta
$ ls -l /usr/sbin/sendmail
lrwxrwxrwx 1 root root 12 11月 29  2016 /usr/sbin/sendmail -> ../bin/msmtp

オフライン時にmsmtpを利用する

msmtpはオフライン時に実行するとエラーとなる.通常は常にオンラインなので問題はないが,持ち運びNotePCなどではオフラインオンラインが発生してメールの送信に失敗することがある.

$ echo 'hoge' | msmtp -a gmail matoken@gmail.com
msmtp: cannot locate host smtp.gmail.com: 名前またはサービスが不明です
msmtp: could not send mail (account gmail from /etc/msmtprc)

/usr/share/doc/msmtp/examples/ 以下の msmtpq 若しくは msmtpqueue に格納されているscriptを利用することでオフライン時にキューとして貯めておいてオンライン時に送信といったことが出来る.

どちらもsendmailと置き換えが可能なので,ネットワークダウン時に`/usr/sbin/sendmail`をこれに置き換えてオンライン時に戻してqueueをフラッシュするようにするといいかもしれない.

Debian/Ubuntuなら以下のあたりで,

  • /etc/network/if-down.d/
    /usr/sbin/sendmail を msmtpq or msmtpqueue に向ける

  • /etc/network/if-pre-up.d/
    /usr/sbin/sendmail を msmtp に向ける

  • /etc/network/if-up.d/
    queueをフラッシュ

NetworkManagerだと /etc/NetworkManager/dispatcher.d/ 以下で同じことが出来る.

msmtpq

圧縮されているmsmtpqを展開して実行権を付与する
$ sudo gunzip /usr/share/doc/msmtp/examples/msmtpq/msmtpq.gz
$ sudo chmod 755 /usr/share/doc/msmtp/examples/msmtpq/msmtpq
使いやすい場所にシンボリックリンクを張る
$ sudo ln -s /usr/share/doc/msmtp/examples/msmtpq/msmtpq /usr/local/bin/msmtpq
$ sudo ln -s /usr/share/doc/msmtp/examples/msmtpq/msmtp-queue /usr/local/bin/msmtp-queue
queueとlogディレクトリを作成
$ install -d -m 700 ~/.msmtp.queue
$ install -d -m 700 ~/log
オフライン時に送信しようとする
$ echo 'msmtpq' | msmtpq -C ~/.msmtprc -a gmail matoken@gmail.com
mail for [ -C /home/matoken/.msmtprc -a gmail matoken@gmail.com ] : couldn't be sent - host not connected
enqueued mail as : [ 2018-09-18-06.21.48 ] ( -C /home/matoken/.msmtprc -a gmail matoken@gmail.com ) : successful
queueを確認する
$ msmtp-queue -d
mail  num=[ 1 ]  id=[ 2018-09-18-06.21.18 ]
mail  num=[ 2 ]  id=[ 2018-09-18-06.21.48 ]
queueをフラッシュする
$ msmtp-queue -r
mail [ 1 ] [ 2018-09-18-06.21.18 ] from queue ; send was successful ; purged from queue
mail [ 2 ] [ 2018-09-18-06.21.48 ] from queue ; send was successful ; purged from queue
$ msmtp-queue -d
no mail in queue

msmtpqueue

使いやすい場所にシンボリックリンクを張る
$ sudo ln -s /usr/share/doc/msmtp/examples/msmtpqueue/msmtp-enqueue.sh /usr/local/bin/msmtp-enqueue.sh
$ sudo ln -s /usr/share/doc/msmtp/examples/msmtpqueue/msmtp-listqueue.sh /usr/local/bin/msmtp-listqueue.sh
~$ sudo ln -s /usr/share/doc/msmtp/examples/msmtpqueue/msmtp-runqueue.sh /usr/local/bin/msmtp-runqueue.sh
`msmtp`コマンドの代わりに`msmtp-enqueue.sh`を使う
$ echo 'queue' | msmtp-enqueue.sh -C ~/.msmtprc -a gmail matoken@gmail.com
queueを確認する
$ msmtp-listqueue.sh
No mail in queue
今回のようにメールの内容がbodyだけでFrom, To, Subject が存在しないとこのscriptはうまく機能しない><
         egrep -s --colour -h '(^From:|^To:|^Subject:)' "$i" || echo "No mail in queue";
直接`~/.msmtpqueue/`を確認するとqueueが溜まっているのがわかる
$ ls -lA ~/.msmtpqueue/
合計 8
-rw------- 1 matoken matoken  7  9月 18 00:15 2018-09-18-00.15.53.mail
-rw------- 1 matoken matoken 53  9月 18 00:15 2018-09-18-00.15.53.msmtp
Subjectの付いたメールがある時
$ msmtp-listqueue.sh
No mail in queue
Subject: offline><
オンライン時にqueueをフラッシュする
$ msmtp-runqueue.sh
*** Sending 2018-09-18-00.15.53.mail to -C /home/matoken/.msmtprc -a gmail matoken@gmail.com ...
2018-09-18-00.15.53.mail sent successfully
*** Sending 2018-09-18-00.27.21.mail to -C /home/matoken/.msmtprc -a gmail matoken@gmail.com ...
2018-09-18-00.27.21.mail sent successfully

#sudoの場合も ~root/.msmtpqueue/ だった.

tips

gmailで以下のエラーとなった場合 tls_starttls on ( tls onのときの既定値? )と設定すると送信できた
$ echo "hello msmtp" | sudo msmtp -a gmail matohara@gmail.com
msmtp: envelope from address matohara@gmail.com not accepted by the server
msmtp: server message: 530 5.7.0 Must issue a STARTTLS command first. k126-v6sm14991126pgk.26 - gsmtp
msmtp: could not send mail (account gmail from /etc/msmtprc)
Yandexでメール送信時に帰ってこない場合 tls_starttls off と設定すると送信できた

niftyで以下のエラーとなった場合 tls_starttls off と設定すると送信できた
msmtp: network read error: 接続が相手からリセットされました
msmtp: could not send mail (account nifty from /etc/msmtprc)

試した環境

環境1(Raspberry Pi 2B/Raspbian stretch)
$ dpkg-query -W msmtp msmtp-mta gnupg2 openssl
gnupg2  2.1.18-8~deb9u2
msmtp   1.6.6-1
msmtp-mta       1.6.6-1
openssl 1.1.0f-3+deb9u2
$ lsb_release -d
Description:    Raspbian GNU/Linux 9.4 (stretch)
$ uname -m
armv7l
環境2(Ubuntu 18.04 LTS)
$ dpkg-query -W msmtp msmtp-mta gnupg2 openssl
gnupg2  2.2.4-1ubuntu1.1
msmtp   1.6.6-1
msmtp-mta       1.6.6-1
openssl 1.1.0g-2ubuntu4.1
$ lsb_release -d
Description:    Ubuntu 18.04.1 LTS
$ uname -m
x86_64
環境3(Debian sid)
$ dpkg-query -W msmtp msmtp-mta gnupg2 openssl
gnupg2  2.2.10-1
msmtp   1.6.7-1
msmtp-mta
openssl 1.1.1-1
$ lsb_release -d
Description:    Debian GNU/Linux unstable (sid)
$ uname -m
x86_64