こんにちは、サイオステクノロジーの藤野です。
Linux 上で Python スクリプトから D-Bus 経由でユーザーのログインセッションを監視する方法を紹介します。
動作イメージ
作業端末で仮想コンソールを2つ用意し、ホストにsshでログインしてPythonスクリプトを起動します。(画面上部)
この状態でもう片方の仮想コンソール(画面下部)からsshでホストにログインすると、スクリプトがログインセッションの開始を検知しユーザー情報を表示します。ログアウトでも同様にログインセッションの終了を検知し、ユーザー情報を表示します。
それでは実装の紹介です。今回は以下の構成で進めていきます。
作業端末
- OS X
ホスト
- CentOS 7.4
- Python 2.7.5
まずはホストで必要なパッケージを導入します。
$ sudo yum install epel-release $ sudo yum install python-gobject-base $ sudo yum install python-pip $ sudo pip install pydbus
test-dbus.py にコードを書きます。
from pydbus import SystemBus from gi.repository import GLib from functools import partial import datetime users = {} def onSessionNew(sid, path, bus): session = bus.get('org.freedesktop.login1', path) (uid, path) = session.User user = bus.get('org.freedesktop.login1', path) user = { 'name': user.Name, 'uid': user.UID, 'gid': user.GID } users[sid] = user print('sid={} uid={} user={} event={}'.format(sid, user['uid'], user['name'], 'login')) def onSessionRemoved(sid, path): user = users.get(sid) if users: del users[sid] print('sid={} uid={} user={} event={}'.format(sid, user['uid'], user['name'], 'logout')) def main(): bus = SystemBus() manager = bus.get('org.freedesktop.login1', '/org/freedesktop/login1') manager.SessionNew.connect(partial(onSessionNew, bus=bus)) manager.SessionRemoved.connect(onSessionRemoved) print('wait for session event..') loop = GLib.MainLoop() try: loop.run() except KeyboardInterrupt: loop.quit() except: sys.exit(1) main()
実装の解説
main()
D-BusのシステムワイドなイベントバスであるSystemBusを取得します。
イベントバスから logind の Manager オブジェクトを取得します。
Manager オブジェクトの SessionNew と SessionRemoved シグナルにそれぞれのコールバック関数を接続します。
https://www.freedesktop.org/wiki/Software/systemd/logind/#themanagerobject
なお、onSessionNew() ハンドラに bus を渡したかったので functools.partial を使ってハンドラ側の bus 引数に変数 bus を束縛してあります。
GLibのイベントループを開始します。ユーザーが Ctrl+C を入力することでイベントループが終了するように KeyboardInterrupt 例外を捕捉しておきましょう。
onSessionNew()
ユーザーのログインセッション作成後にこの関数をコールバックします。Session ID と Session オブジェクトのパスが引数で渡されます。
Session オブジェクトのパスを使って Session オブジェクトを取得します。
https://www.freedesktop.org/wiki/Software/systemd/logind/#sessionobjects
Session オブジェクトには User というプロパティがあり、Python のタプルで UID と User オブジェクトのパスが取得できます。
User オブジェクトのパスを使って User オブジェクトを取得します。
https://www.freedesktop.org/wiki/Software/systemd/logind/#userobjects
User オブジェクトから UID, GID, ユーザー名 をそれぞれ取得し、表示しています。
ログアウト時にもユーザー情報を出力したいので、Session ID をキーにして保持しておきます。
onSessionRemoved()
ユーザーのログインセッションの削除後にこの関数をコールバックします。Session ID と Session オブジェクトのパスが引数で渡されます。
シグナルの名前通り、この関数が呼ばれた時点で既に Session 存在していません。
そのため、ログアウトしたユーザーの情報はログイン時に保存しておいた情報を参照しています。
駆け足での紹介でしたが、D-Bus インターフェースを実装プログラムから利用する事でシステム内のイベントを購読し、情報を取り出せることができました。