PythonスクリプトとD-Busでユーザーのログイン・ログアウトを検知する

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
【4/18開催】VSCode Dev Containersで楽々開発環境構築祭り〜Python/Reactなどなど〜
Visual Studio Codeの拡張機能であるDev Containersを使ってReactとかPythonとかSpring Bootとかの開発環境をラクチンで構築する方法を紹介するイベントです。
https://tech-lab.connpass.com/event/311864/

こんにちは、サイオステクノロジーの藤野です。

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 インターフェースを実装プログラムから利用する事でシステム内のイベントを購読し、情報を取り出せることができました。

アバター画像
About 藤野 治 1 Article
開発エンジニア。2000年台初頭からSNS系Webサービスの開発と運用に従事、そのキャリアを活かしてSIを支えるアプリケーションやWebサービス開発を担当しています。Linux愛好家、座右の銘は「混ぜるな危険」。
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。


ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる