C++の応用 - PolKit

提供:MochiuWiki - SUSE, Electronic Circuit, PCB
ナビゲーションに移動 検索に移動

概要

PolKit(以前は、PolicyKitとして知られていた)は、非特権ユーザセッションと特権システムコンテキストの間のネゴシエータとして機能するアプリケーションフレームワークである。

PolKitは、ユーザ、グループ、名前により特定のアクションを制限する機能を持つ。
ユーザセッションのプロセスが、システムコンテキストでアクションを実行するごとに、PolKitはクエリされる。 所謂、ポリシーで指定された設定に基づいて、"yes"、"no"、"needs authentication"である可能性がある。

sudoのような古典的な権限承認プログラムとは異なり、PolKitはセッション全体に対してroot権限を与えるのではなく、各アクションに対してのみ権限を与える。

Qtを使用してPolkitを利用する場合は、Qtの基礎_-_管理者権限のページを参照すること。


PolKitのインストール

パッケージ管理システムからインストール

# RHEL
sudo dnf install polkit-devel

# SUSE
sudo zypper install polkit-devel


ソースコードからインストール

多くのLinuxディストリビューションには、初期状態でPolKitがインストールされている。
もし、別途インストールする必要がある場合、ソースコードからPolKitをインストールする。

PolKitのビルドに必要なライブラリをインストールする。

# SUSE
sudo zypper install meson dbus-1-devel libexpat-devel systemd-devel glib2-devel gtk3-devel gobject-introspection-devel mozjs78-devel pam-devel duktape-devel gtk-dpc


PolKitの公式WebサイトまたはGitLabにアクセスして、ソースコードをダウンロードする。
ダウンロードしたファイルを解凍する。

tar xf polkit-<バージョン>.tar.gz
cd polkit-<バージョン>


また、git cloneコマンドを実行して、PolKitのソースコードをダウンロードする。

git clone https://gitlab.freedesktop.org/polkit/polkit.git
cd polkit


PolKitをビルドおよびインストールする。
設定可能なオプションの一覧は、meson configureコマンドで取得することができる。

# RHEL
meson setup build --prefix=<PolKitのインストールディレクトリ> -Dos_type=redhat -Dexamples=true -Dman=true -Dgtk_doc=true

# SUSE
meson setup build --prefix=<PolKitのインストールディレクトリ> -Dos_type=suse -Dexamples=true -Dman=true -Dgtk_doc=true

meson compile -C build
meson install -C build



CMakeファイルの設定

Pkg-Configを使用しない場合

 # CMakeLists.txtファイル
 
 # 実行ファイルの場合
 add_executable(<プロジェクト名>
   # ...略
 )
 
 # ライブラリの場合
 add_library(<プロジェクト名>
    # ...略
 )
 
 ## インクルードファイル
 include_directories(
    # ...略
 
    /usr/lib64/glib-2.0/include
    /usr/include/glib-2.0
    /usr/include/polkit-1
 
    # ...略
 )
 
 ## ライブラリファイル
 target_link_libraries(<プロジェクト名>
    # ...略
 
    glib-2.0
    polkit-gobject-1
    gobject-2.0
    gio-2.0
 
    # ...略
 )


Pkg-Configを使用する場合

 # CMakeLists.txtファイル
 
 find_package(PkgConfig REQUIRED)
 pkg_check_modules(GLIB2          REQUIRED glib-2.0)
 pkg_check_modules(POLKITGOBJECT2 REQUIRED polkit-gobject-1)
 pkg_check_modules(GOBJECT2       REQUIRED gobject-2.0)
 pkg_check_modules(GIO2           REQUIRED gio-2.0)
 
 # 実行ファイルの場合
 add_executable(<プロジェクト名>
   # ...略
 )
 
 # ライブラリの場合
 add_library(<プロジェクト名>
    # ...略
 )
 
 include_directories(
    ${GLIB2_INCLUDE_DIRS}
    ${POLKITGOBJECT2_INCLUDE_DIRS}
    ${GOBJECT2_INCLUDE_DIRS}
    ${GIO2_INCLUDE_DIRS}
 )
 
 link_directories(
    ${GLIB2_LIBRARY_DIRS}
    ${POLKITGOBJECT2_LIBRARY_DIRS}
    ${GOBJECT2_LIBRARY_DIRS}
    ${GIO2_LIBRARY_DIRS}
 )
 
 add_definitions(
    ${GLIB2_CFLAGS_OTHER}
    ${POLKITGOBJECT2_CFLAGS_OTHER}
    ${GOBJECT2_CFLAGS_OTHER}
    ${GIO2_CFLAGS_OTHER}
 )



QMakeファイルの設定

Pkg-Configを使用する場合

 CONFIG += link_pkgconfig
 PKGCONFIG += \
    glib-2.0          \
    polkit-gobject-1  \
    gobject-2.0       \
    gio-2.0
 
 LIBS += \
    -lglib-2.0 \
    -lpolkit-gobject-1      \
    -lgobject-2.0           \
    -lgio-2.0


Pkg-Configを使用しない場合

 LIBS += \
    -lglib-2.0 \
    -lpolkit-gobject-1      \
    -lgobject-2.0           \
    -lgio-2.0
 
 INCLUDEPATH += \
    /usr/lib64/glib-2.0/include \
    /usr/include/glib-2.0 \
    /usr/include/polkit-1



サンプルコード

 #include <polkit/polkit.h>
 
 void check_authorization(PolkitAuthority *authority, GAsyncResult *res, gpointer user_data);
 gboolean do_cancel(GCancellable *cancellable);
 
 int main()
 {
    // Action ID for PolKit
    const gchar *action_id = "org.example.policykit.do";
 
    // メインイベントループを作成
    GMainLoop *loop = g_main_loop_new(nullptr, FALSE);
 
    // 権威への参照を同期的に取得 (応答を受け取るまで呼び出し元のスレッドはブロックされる)
    // 非同期にする場合は、polkit_authority_get_async関数を使用する
    PolkitAuthority *authority = polkit_authority_get_sync(nullptr, nullptr);
 
    // 多くのクライアントはD-Busを介してメカニズムと通信するため、PolkitSystemBusNameを使用する
    // しかし、この例では、呼び出しプロセスのプロセスIDを使用する
    // 親プロセスが終了した場合、init(1)が認可されているかどうかをチェックしないように注意する (常に認可されている)
 
    // 親プロセスのPIDを取得
    auto parent_pid = getppid();
    if (parent_pid == 1) {
       g_printerr("Parent process was reaped by init(1)\n");
       return -1;
    }
 
    // 詳細情報の取得
    PolkitSubject *subject = polkit_unix_process_new_for_owner(parent_pid, 0, getuid());
 
    // PolKit認証画面でタイムアウトを使用する場合 (以下の例では、10[sec])
    GCancellable *cancellable = g_cancellable_new();
    g_timeout_add(1000 * 10, (GSourceFunc)do_cancel, cancellable);
 
    // 認証画面の表示 (タイムアウト設定なし)
    polkit_authority_check_authorization(authority, subject, action_id, nullptr,
                                         POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
                                         nullptr, (GAsyncReadyCallback)check_authorization, loop);
 
    // 認証画面の表示 (タイムアウト設定あり)
    // polkit_authority_check_authorization(authority, subject, action_id, nullptr,
    //                                      POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION,
    //                                      cancellable, (GAsyncReadyCallback)check_authorization, loop);
 
    // メインイベントループの実行
    g_main_loop_run(loop);
 
    // 終了処理
    g_object_unref(authority);
    g_object_unref(subject);
    g_object_unref(cancellable);
    g_main_loop_unref(loop);
 
    return 0;
 }
 
 // 認証処理
 void check_authorization(PolkitAuthority *authority, GAsyncResult *res, gpointer user_data)
 {
    GError *error = nullptr;
    PolkitAuthorizationResult *result = polkit_authority_check_authorization_finish(authority, res, &error);
    if (error != nullptr) {
       // タイムアウトになった場合 (タイムアウト処理を指定する必要がある)
       g_print ("Error checking authorization: %s\n", error->message);
       g_error_free(error);
    }
    else {
       const gchar *result_str;
       if (polkit_authorization_result_get_is_authorized(result)) {
          // 認証に成功した場合
          result_str = "authorized";
       }
       else if (polkit_authorization_result_get_is_challenge(result)) {
          // より詳細な情報が提供された場合に認可されているかどうかを取得
          result_str = "challenge";
       }
       else {
          // 認証をキャンセルした場合
          result_str = "not authorized";
        }
 
        g_print("Authorization result: %s\n", result_str);
    }
 
    // メインイベントループの終了
    auto loop = static_cast<GMainLoop*>(user_data);
    g_main_loop_quit(loop);
 }
 
 // タイムアウト処理
 gboolean do_cancel(GCancellable *cancellable)
 {
    g_print("Timer has expired; cancelling authorization check\n");
    g_cancellable_cancel(cancellable);
 
    return FALSE;
 }