TenForward

技術ブログ。はてなダイアリーから移転しました

セサミ mini を導入してみた(2)

先日設置したセサミ mini ですが、先日も少し書いたとおり、ちょっとだけ問題がありました。

tenforward.hatenablog.com

うちの鍵は

  • サムターンが縦(12時)方向で解錠
  • サムターンが縦から右に45度回転した状態でチェーンがかかった状態
  • サムターンが横(3時)方向で施錠

となります。

サムターンの施錠、解錠状態はそれぞれ少々の遊びがあって、縦から少し行き過ぎた状態と少し手前の状態をぐらぐら動く感じです。

そしてセサミ mini のサムターンアダプターとサムターンの間には少し隙間があり、セサミ mini のつまみ自身も色々な方向に少し遊びがあります(設置が少しズレたときの対応や、色々な鍵への対応を考えてそういう設計になっているようです)。

色々な所に余裕と遊びがある関係で、うちに設置すると:

解錠状態: セサミ mini のつまみがちょうど縦になる状態だと、鍵のサムターンが解錠状態の縦にならず、少し手前で止まってしまい、開場されずにチェーンがかかった状態になる。そこで解錠状態は少し縦より行き過ぎた状態で設定する。

f:id:defiant:20190520233705p:plain
解錠状態のセサミの角度

これくらいの角度を解錠に設定します。こちらが問題になることはありません。

施錠状態: 問題は施錠状態です。

セサミのつまみが真横になった状態を「施錠状態」に設定すると、鍵のサムターンは横(3時)の少し手前で止まってしまい、きちんと施錠されずにチェーンがかかった状態になります

そこで少し行き過ぎたところ(次の画像の通り)あたりに設定します。セサミアプリを使って施錠するとこれで施錠できます

f:id:defiant:20190609133745j:plain
セサミの施錠状態のつまみ角度

ところが鍵を使って施錠すると、鍵のサムターンは横(3時)を向きますが、セサミ miniのつまみは真横のちょっと手前の状態で止まります。

f:id:defiant:20190609133721j:plain
鍵で施錠した際のセサミの角度

この状態だとセサミは施錠状態のところまでつまみが回っていないと認識し、アプリで見ると "Unlocked" という表示のままです。

この状態でアプリをタップすると、施錠状態に移行します。再度タップすると解錠されます。つまり 2 度タップしないといけないことになります。

上記ツイートを行うと、公式に補足され、ありがたいことにタダでアダプターを作成し送ってくれるとのことですので、サムターンの詳細なサイズを送りました。

届いたのでアダプターを装着しました。装着したアダプターとセサミのサムターンアダプターとの間にも少し隙間があります。

f:id:defiant:20190609132335j:plain
届いたアダプターを装着

そして設置。写真のようにアダプターをつけてもサムターンとの間には隙間があります。

f:id:defiant:20190609133839j:plain
作ってもらったアダプターを付けて設置

このため、

サムターン←(すき間)→作成してもらったアダプター←(すき間)→セサミ miniのサムターンアダプター

という状態になり、やはりいくら調整してもセサミ mini の施錠状態の角度と鍵を使った時の施錠状態の角度の間に差が出来てしまい、症状は改善されませんでした。

とはいうものの、便利さが勝っていますので、作ってもらったアダプターは取り外し、元の状態で再度装着して使っています。

アプリでの対応が待たれますね。

セサミの公式サポート手厚すぎですね。安心できる対応ですね。

セサミ mini を導入してみた

だーいぶ前に mizzy さんのブログでスマートロックなるものを知って、これはいいなと思いつつずっと買ってなかったのですが、最近は Qrio 以外にもセサミスマートロックという競合製品もあるってのを知って、これは良さげだなと思ってそろそろウチにも導入するかなーということで導入しました。

セサミはちょっと横幅もあって、結構ドアノブ(というのかこれは?)が上下に長くて設置できる幅が限られるウチでは無理じゃないかなと思ってたら、mini なるコンパクトなモデルがあるということを知ったのですが、クラウドファンディングは終わったばかりのころに気づいたので、さらにそこから待ってようやく購入しました。

f:id:defiant:20190520225314j:plain
うちのドアノブと鍵付近

Wifiアクセスポイントもあると便利そうなのでこちらとセットになったものが19,800円。

うちは鍵がふたつあるのですが、とりあえず片方の鍵に取り付けてみました。

鍵のつまみの形状や大きさに応じて高さやつまみを挟み込む部分の幅を調整しなければいけません。その場合は付属ドライバーで調整します。その調整さえすめば、あとは両面テープでぺたっと貼るだけなので 5 分もかからずに取り付けはできそうです。私はちょっと水平器でまっすぐつけたりしていたのでもう少しかかりましたが。

f:id:defiant:20190519153728j:plain
裏側

まずはアプリにセサミを登録。このときアプリから Bluetooth でつなぐのですが、なぜか私はセサミが全くアプリに表示されずに、何度か本体リセットしたり、スマホを再起動したりしてるといつの間にか表示されるようになっていました。Why??

取付後はアプリからつまみの調整を行って完了です。うちの鍵はつまみが縦になっているときが解錠状態、横になっているときが施錠ですが、これ以外に45度の時にちょうどチェーンをかけて扉を細く開けるような状態になります。つまみには少し遊びがあるので、縦よりもう少し進んだ11時方向あたりを解錠、横も4時方向に近いあたりを施錠状態として設定しました(12時を解錠、3時を施錠とすると中途半端に止まって45度状態になってしまうことがあったので)。

f:id:defiant:20190520233705p:plainf:id:defiant:20190520233647p:plain
解錠・施錠

この後はWifiアクセスポイントの登録に。これもアプリから簡単にできましたが、2.4GHz しか対応していないということでそちらを登録。

f:id:defiant:20190520105759j:plain
Wifiアクセスポイント

家族の分の登録はちょっと戸惑いました。アプリを起動してメールアドレスを登録するとすぐにセサミを追加する画面になりますが、家族分はここでペアリングさせるのか、それとも最初に登録した「オーナー」が「マネージャー」を追加するだけでよいのか。結局、マネージャー登録をすると、各スマホに登録したセサミが表示されたので、きっとこれが正しい方法なのでしょう(どっかにちゃんと書いてあるのかもしれませんが見つけられなかった&色々やるほうが早いと思った)。

簡単に感想を。機能を十分に理解しておらず、もしかしたら勘違いしてる部分はあるかもしれません。

  • 解錠、施錠の反応は良く、すぐに解錠・施錠動作が開始され、2秒程度で状態が変わります。
    • ただしアプリを起動して、BT、Wifi、インターネット経由で鍵に接続できるまでに 5 秒〜 10 秒(もしくはそれ以上)かかる場合もあるので、結構時間がかかってしまう場合があります。家の扉の前でスマホ取り出してから解錠しようとしたりする場合、鍵をポケットから出したほうが早い場合もあります。家のちょっと手前でスマホを取り出して準備するとちょうど良い感じです
    • BT は別のスマホが接続されていると接続できないので家族が短時間のうちに操作しようとするとバッティングするかも。まああまりそういうことはないでしょうが
  • Bluetooth でペアリングする代わりに、Wifi アクセスポイントと同じ Wifi につながるとそれでも解錠ができるようですが、アクセスポイントは 2.4GHz のみ対応で、イマドキはスマホは 5GHz でつなぐようにしているので、同じ Wifi につながることはなく、自宅にいてもインターネット経由で Wifi アクセスポイントを使って解錠、施錠することになってます(と思う)
    • アクセスポイントの 5GHz 対応が待たれますね
  • 何度か実際の鍵の状態と違う状態がアプリに表示されていました。もちろん、実際に操作するときは表示通りなので、施錠したつもりがされてないというようなことはありません。鍵の状態を確認しようとしたときの話です
    • 家を出て施錠してすぐにアプリを見ると Unlocked と書かれてました
    • この状態で施錠操作するとモーター動いてる音しましたが、無理な力かかって壊れない?
  • 鍵の状態が変わったらスマホに通知を送ることが出来ます。手動で操作した場合も通知が飛んできます
  • 家に近づいたら自動的に解錠とか、ノック解錠は使ってません(Android だし)
  • 解錠後、一定時間経つとオートロックできますが、その時間も設定できるので便利
    • オートロックに関してはうっかりスマホも鍵も持たずに郵便箱を見に行ってしまい閉め出されたのでオフにしました😂

家の Google Home と IFTTT を連携させて、「オッケーぐーぐる。開けごま」とかいうのも試してみました😂設定は公開されてる通りにやれば簡単でした。「開けごま」は Google アシスタントに別のキーワードとして登録されているのか、キラキラした絵文字が返事として返ってくるだけで「オープンセサミ」「クローズセサミ」でちゃんと解錠、施錠されていました。

比較的窓際に Google Home 置いてるので、外から解錠できたりしたら怖いので、5 分ほど遊んで無効化しましたけど。

xkbのファイルを書き換えてキーマップを調整する

Plamo 7.0 環境で、USB 切替器を使って USB キーボードを切り替えると、切り替え後に fcitx のオンオフができなくなってハマっていました。つまり USB キーボードを抜き差ししたあとに fcitx のオンオフができなくなっていました。

fcitx のオンオフはこのように設定していました。HHKB を使ってます。

  • Command キー(スペースの横)を "Super_L" に割り当てている
    • .Xmodmap ファイルに書いて、fcitx の "X Keyboard Integration" Addon で、その .Xmodmap を読み込ませていた
    • xmodmap -e "keycode 102 = Super_L" みたいな
  • オンオフキーを Super+Space に割り当てていた

よくよく調べると xmodmap で行った変更設定が切り替え後に消えていてデフォルトの Muhenkan に戻っていることがわかりました。

最初は udev イベントでキーボードさされたのを検知して xmodmap を実行しようかと思ったら、現在開いているデスクトップ環境と実行する環境のセッションも違うし、DISPLAY 環境変数与えたりしてもイマイチうまくいかないので、キーマップ書き換えてしまえ、ということでやりました。

まず、現在使われいてるキーボードマップを調べます。

$ setxkbmap -print
xkb_keymap {
    xkb_keycodes  { include "evdev+aliases(qwerty)"  };
    xkb_types     { include "complete"   };
    xkb_compat    { include "complete"   };
    xkb_symbols   { include "pc+us+inet(evdev)"  };
    xkb_geometry  { include "pc(pc105)"  };
};

keycode は evdevalias を使っているということで、まず /usr/share/X11/xkb/keycode/evdev を見ると、keycode 102<MUHE> であることがわかりました。

        <MUHE> = 102;   // Muhenkan

これが定義されているところを xkb_symbolspc+us+inet(evdev) の方で調べると、

$ grep MUHE pc us inet
inet:    key <MUHE>   {      [ Muhenkan               ]       };

と出ますので、ここを強引に、

$ grep MUHE pc us inet
inet:    //key <MUHE>   {      [ Muhenkan              ]       };
inet:    key <MUHE>   {      [ Super_L               ]       };

のように書き換えて、.Xmodmap の読み込みを止めて再起動すると、無事、xmodmap なしで keycode 102Super_L になりました。

参考

Linux 4.14 で導入された Namespaced file capabilities(おまけ)

4.14 で設定した Namespaced file capability を 4.13 以前のカーネルに戻したら

まあ、こんな物好きなことをする人はいないでしょうが、確認してみました。

tenforward.hatenablog.com

の環境のまま、ホスト環境のカーネルを 4.13 に戻して、コンテナを起動し、コンテナ内で一般ユーザーとなって pingping2 コマンドを両方とも実行しました。

$ ./ping www.google.com
-su: ./ping: Numerical result out of range
$ ./ping2 www.google.com
-su: ./ping2: Numerical result out of range

構造体が変わっていたので読み取れないようですね。

Namespaced file capability に設定された id で User Namespace 外から実行してみる

tenforward.hatenablog.com

で、User Namespace 内の root の id が 200000 に設定されていたので、コンテナ内で設定した File capability も 200000 という情報が記録されていました。そこで User Namespace 内の root と同じ id を持つホスト上のユーザーから、file capability を設定したコマンドを実行してみました。

今回は unshare コマンドを使います。

  • ホスト上の uid: 1000 のユーザーを User namespace 内の rootマッピング

ちょっと色々試行錯誤しながら試したので変なことしてるようだったら教えてください。

ホスト上のユーザーは 1000:100 です。ここで unshare します。

$ id -u
1000
$ id -g
100
$ unshare --user --setgroups allow
nobody@borg:~$ id
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)

マッピングがまだできていないので、この時点では User namespace 内では nobody ユーザーになります。

ここで別のシェルからホスト上の rootマッピングを投入します。(Plamo なので gid がちょっと普通と異なるかな)

# echo "0 1000 65534" > /proc/22471/uid_map 
# echo "0 100 65534" > /proc/22471/gid_map

ここで元の User namespace 内のシェルに戻ると、無事 root になりました。

$ id
uid=0(root) gid=0(root) groups=0(root),65534(nogroup)

これで他の namespace が作れますので、Network namespace を作ります(これを作らないと file capability 設定しても ping 実行できなかったので)。

$ unshare --net
# ip link set lo up
# ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever

ここで一般ユーザーになります。ping コマンドをコピーして実行してみます。当然失敗しますね。

$ su karma
$ id -u
1000
$ cd /tmp
$ cp /bin/ping .
$ ls -l ping
-rwxr-xr-x 1 karma users 56,920  32401:02 ping*
$ ./ping 127.0.0.1
ping: socket: Operation not permitted
$ exit

ここで User namespace 内の root で file capability を設定します。

# setcap cap_net_raw+ep /tmp/ping 
# getcap -n /tmp/ping 
/tmp/ping = cap_net_raw+ep [rootid=1000]

id:1000 で Namespaced file capability が設定されています。ここで再度一般ユーザーになります。

# su - karma
$ /tmp/ping -c 1 127.0.0.1
PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.012 ms

--- 127.0.0.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.012/0.012/0.012/0.000 ms

User namespace 内で実行できましたね。ここでおもむろに namespace 外のシェルから、id:1000 のユーザーでこの ping を実行してみます。

$ id -u
1000
$ /tmp/ping 127.0.0.1
ping: socket: Operation not permitted

実行はできませんね。

Linux 4.14 で導入された Namespaced file capabilities(2)

User Namespace 外から Namespaced file capability を設定する

前回、

tenforward.hatenablog.com

では、非特権ユーザで起動したコンテナ内の root ユーザーで File capability を設定しました。

ここで、自作コンテナ派の皆様が気になるのは、この capability をコンテナ外から設定するのはどうしたらいいのだろう? というところではないかと思います。コンテナランタイム側からコンテナ内の capability を設定する必要があるかもしれません。

もちろん、これも簡単にできます。先に getcap コマンドに -n オプションを付与しましたが、これと同じオプションが setcap にも存在します。

setcap -n 200000 cap_net_raw+ep ./ping

と言ったように、User Namespace 内の root の uid を指定して capability を指定します。

まず、コンテナ内からアクセスできるように、ホスト環境上で ping コマンドをコンテナの rootfs 内にコピーします。LXC の非特権コンテナは次のようなディレクトリ以下に rootfs が置かれますので、ここにコピーします。ping2 という名前でコピーしました。

$ sudo cp /bin/ping ~/.local/share/lxc/c3/rootfs/home/karma/ping2

次にコピーした ping2 バイナリに対して setcap します。

$ sudo setcap -n 200000 cap_net_raw+ep ~/.local/share/lxc/c3/rootfs/home/karma/ping2 (-nオプションでroot uidを指定)
$ sudo getcap -n ~/.local/share/lxc/c3/rootfs/home/karma/ping2
/home/karma/.local/share/lxc/c3/rootfs/home/karma/ping2 = cap_net_raw+ep [rootid=200000]
$ sudo getfattr -d -m "security" ~/.local/share/lxc/c3/rootfs/home/karma/ping2
getfattr: Removing leading '/' from absolute path names
# file: home/karma/.local/share/lxc/c3/rootfs/home/karma/ping2
security.capability=0sAQAAAwAgAAAAAAAAAAAAAAAAAABADQMA

設定されましたね。

再度コンテナ内に入ってみましょう。

$ lxc-attach c3
# su - karma
$ ls -l ./ping*
-rwxr-xr-x 1 karma  users   56,920  2月 21日  16:30 ./ping*
-rwxr-xr-x 1 nobody nogroup 56,920  2月 21日  16:39 ./ping2*

ホスト側の権限でコピーしていますので、ファイルの所有権が nobody:nogroup になっていますね。

$ sudo getcap -n ./ping2
./ping2 = cap_net_raw+ep [rootid=200000]

capability を確認すると、設定されているのがわかります。では、実行してみましょう。

$ ./ping2 -c 1 www.google.com
PING www.google.com (216.58.196.228) 56(84) bytes of data.
64 bytes from kix06s01-in-f228.1e100.net (216.58.196.228): icmp_seq=1 ttl=49 time=1.22 ms

--- www.google.com ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 1.226/1.226/1.226/0.000 ms

実行できました。

Namespace 外からでも問題なく設定できますね。

kernel のデータ構造の変更

ここからは素人なので間違ってる可能性あります。詳しくはご自分でどうぞ。

4.13 までは include/uapi/linux/capability.h を見ると、以下のような構造体がありました。

#define VFS_CAP_FLAGS_EFFECTIVE 0x000001

  : (snip)

#define VFS_CAP_REVISION_2 0x02000000

struct vfs_cap_data {
    __le32 magic_etc;            /* Little endian */
    struct {
        __le32 permitted;    /* Little endian */
        __le32 inheritable;  /* Little endian */
    } data[VFS_CAP_U32];
};

https://elixir.bootlin.com/linux/v4.13/source/include/uapi/linux/capability.h#L53 付近)

この permittedinheritable に必要な capability を設定するわけですね。effective セットは file capability の場合はオンオフだったと思いますので、magic_etc に設定します。

effective セットを設定する場合、これ(4.13)までは、

struct vfs_cap_data xattr;

xattr.magic_etc = VFS_CAP_REVISION_2 | VFS_CAP_FLAGS_EFFECTIVE;

のように設定したようです。

4.14 以降で Namespaced file capability が導入されたあとは、

#define VFS_CAP_REVISION_2  0x02000000
#define VFS_CAP_U32_2           2
#define XATTR_CAPS_SZ_2         (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2))

#define VFS_CAP_REVISION_3 0x03000000
#define VFS_CAP_U32_3           2
#define XATTR_CAPS_SZ_3         (sizeof(__le32)*(2 + 2*VFS_CAP_U32_3))

#define XATTR_CAPS_SZ           XATTR_CAPS_SZ_3
#define VFS_CAP_U32             VFS_CAP_U32_3
#define VFS_CAP_REVISION   VFS_CAP_REVISION_3

struct vfs_cap_data {
    __le32 magic_etc;            /* Little endian */
    struct {
        __le32 permitted;    /* Little endian */
        __le32 inheritable;  /* Little endian */
    } data[VFS_CAP_U32];
};

/*
 * same as vfs_cap_data but with a rootid at the end
 */
struct vfs_ns_cap_data {
    __le32 magic_etc;
    struct {
        __le32 permitted;    /* Little endian */
        __le32 inheritable;  /* Little endian */
    } data[VFS_CAP_U32];
    __le32 rootid;
};

https://elixir.bootlin.com/linux/v4.14/source/include/uapi/linux/capability.h#L64 付近)

というように struct vfs_ns_cap_data という、vfs_cap_data の最後に rootid が追加された構造体が追加されています。そう、これが setcapgetcap で追加された -n オプションの正体ですね(たぶん)。

それと同時に、従来の Namespaced されていない file capability なのか、Namespaced な file capability なのかは、magic_etc に指定する file capability の Revision で指定します。

先のコードと対応する例だと、

struct vfs_ns_cap_data xattr;

xattr.magic_etc = VFS_CAP_REVISION_3 | VFS_CAP_FLAGS_EFFECTIVE;

となるわけですね(たぶん)。

(つづく)

tenforward.hatenablog.com