SMJobBless
戻る
概要
MacOSアプリで、特権モード(PriviledgeMode) で実行しなければならない場合
アプリケーションをGUI部分とヘルパツールの2つに分けて、
ヘルパ部分に特権が必要な機能を集め、GUI部分からヘルパツールを起動することが推奨されてます。
いくらセキュリティに気をつけてプログラミングしても、GUIアプリはリンクされる
ライブラリが膨大であり、ライブラリの中にセキュリティホールが含まれている
危険性が高く、GUI アプリ部分では特権を得られないようにする配慮です。
ヘルパツールは一種のデーモンとして記述され、アプリから間接的に起動されます。
直接起動しても、ユーザ権限のまま実行しても特権は得られません。
そこでヘルパツールは、直接的にはlaunchd がルート権限で起動します。
ヘルパツールはルート権限で起動されます。それを実現するために、ヘルパツールは
/Library/PrivilegedHelperTool/ というフォルダにインストールされます。
このインストール作業を行ってくれるのがSMJobBless というAPIです。
SMJobBlessはヘルパツールのインストールのみで、起動までは行いません。
SMJobBless API
アプリケーションとヘルパツールはひとつのアプリケーションパッケージの中に
含まれています。このままでは、launchd はヘルパツールの名前や保存場所が
分かりません。
そこで図のようにアプリケーションはヘルパツールを起動する前に、
SMJobBless APIを用いて
ヘルパツールを指定の場所である/Library/PrivilegedHelperTools フォルダにコピーして、
その名前を記述した plist を/Library/LaunchDaemonsに生成してlaunchdに登録します。
/Library/PrivilegedHelperTools フォルダにコピーされたヘルパーツールの実行可能ファイルの
所有者とグループは、root/wheel になっており、 launchdにより起動されるとルート権限で
実行されることになります。
SMJobBlessサンプルのビルドの流れ
Apple のDevelopers サイトから、 SMJobBless Sampleと
EvenBetterAuthorizationSample
がダウンロードできます。SMJobBless だけの簡単な例で、EvenBetterAuthorizationSample
はSMJobBless とNSXPCConnectionを使った完全なサンプルです。
これらのサンプルを利用するにあたって必要となる条件があります。それはビルドした
実行可能ファイルに署名をしなければならないので、 署名可能なAppleIDを取得しておかなければ
ならないということです。アプリケーションとヘルパツールは別個のファイルになっていますが、
アプリケーションから意図せず悪意を持ったヘルパーツールを起動しないため、一方ヘルパツールから
すれば本来起動するアプリケーションではない別のアプリから起動されてしまうと、セキュリティホール
となってしまいます。そこで、アプリケーションはヘルパツールのコード署名を、一方ヘルパツールは
自分を呼び出すアプリケーションのコード署名をもって、意図しないものを起動したりされたりするのを
防ぎます。このような事情により、SMJobBless を使うアプリケーションへのコード署名は必須になっています。
コード署名をするには、 developerCenter でMac Developer
Programに加入します。個人会員で年間1万円程度
かかります。
SMJobBlessサンプルを解凍すると、2つのターゲットSMJobBlessAppとSMJobBlessHelperに加えて、
SMJobBlessUtil.pyと Uninstall.shが現れます。
まず1回目のビルドをすると2つの実行ファイルができます。署名ができなければビルドはエラーで終了します。
成功したら、 アプリケーション側のSMJobBlessAppとヘルパツールの SMJobBlessそれぞれに、コード署名が
含まれています。
次に SMJobBlessUtil.pyを使って、お互いのコード署名を交換して plistに書き込みます。そして2回目のビルドを
実施すると、 plistに書かれた相手のコード署名が実行ファイルに含まれるようになります。これにより、自分に
含まれるコード署名を持つ相手だけが起動する(される)ことができるようになります。
SMJobBlessサンプルのビルド作業
ビルドはXcodeで行います。署名も有効なIDを使って自動的に付加されます。
SMJobBlessUtil.pyをコード署名交換のために第一引数を setreqで使う場合には、
そのあとに実行パッケージのパス、 アプリケーション側の plist、ヘルパツールの
plist という3つの起動引数が必要になります。
たいていの場合Xcode でビルドしたときの実行パッケージは、
~/Library/Developer/Xcode/DerivedData/SMJobBless-*/Build/Products/Debug/SMJobBlessApp.app
にあります。ただし上記*はその時々で異なる文字列が入ります。
plistはそれぞれ
SMJobBlessUtil.pyの場所から、SMJobBlessApp/SMJobBlessApp-Info.plist と
SMJobBlessHelper/SMJobBlessHelper-Info.plist
にありますので、SMJobBlessUtil.pyは以下のように
起動します。緑文字はコマンドプロンプト、黒文字は入力コマンド、青文字は出力メッセージです。
Hiroaki-no-MacBook-Pro:SMJobBless
hata$ ./SMJobBlessUtil.py
setreq
~/Library/Developer/Xcode/DerivedData/SMJobBless-cjpgozzamebzngbquuhhrinuzuds/Build/Products/Debug/SMJobBlessApp.app
SMJobBlessApp/SMJobBlessApp-Info.plist
SMJobBlessHelper/SMJobBlessHelper-Info.plist
SMJobBlessApp/SMJobBlessApp-Info.plist:
updated
SMJobBlessHelper/SMJobBlessHelper-Info.plist:
updated
SMJobBlessUtil.pyは何を行っているかといえば、まずMJobBlessApp実行ファイルから
DesignatedRequestを取り出し、
それをSMJobBlessHelper-Info.plistに設定して、さらにSMJobBlessHelper実行ファイルから 取り出したDesignatedRequest
をSMJobBlessApp-Info.plistに設定するという情報のたすきがけのようなことをやっています。
DesignatedRequestは codesignコマンドの -d -r- オプションで表示される
designated => プロンプト以下のもので、
プログラマ側の観点から利用者にコード認証してもらうときに確認してほしい要件を記載したものです。
コード署名すると一緒に設定されます。もしコード署名がされていないと
designated => プロンプロではなく
#designated =>のように#マークが行頭に付加されますので、SMJobBlessUtil.py コマンドは失敗します。
Hiroaki-no-MacBook-Pro:Debug hata$
codesign -d -r - SMJobBlessApp.app 2>/dev/null
designated => identifier "com.apple.bsd.SMJobBlessApp" and anchor
apple generic and certificate leaf[subject.CN] = "Mac Developer:
Hiroaki Hata (7GC5NDTSBE)" and certificate
1[field.1.2.840.113635.100.6.2.1] /* exists */
SMJobBlessUtil.py コマンドが成功すると、たとえばアプリケーション側のDesignatedRequestが上記のようなであれば、
SMJobBlessHelper-Info.plist
にSMAuthorizedClientsが以下のように追加されます。
<key>SMAuthorizedClients</key>
<array>
<string>identifier
"com.apple.bsd.SMJobBlessApp" and anchor apple generic and certificate
leaf[subject.CN] = "Mac Developer: Hiroaki Hata (7GC5NDTSBE)" and
certificate 1[field.1.2.840.113635.100.6.2.1] /* exists
*/</string>
</array>
SMJobBlessUtil.py が成功すると、もう一度ビルドしなおすことでplist の内容が正しく反映されますので
SMJobBlessApp が実行可能になります。
SMJobBlessUtil.py は、ヘルパーツールを起動するサンプルEvenBetterAuthorizationSampleをビルドするときにも
使えますが、そちらのサンプルzip には含まれていません。SMJobBlessサンプル以外でも使用できる便利な
ツールです。
SMJobBlessApp の実行
SMJobBlessAppを実行するとヘルパツールが以下のところにコピーされていることが確認できます。
/Library/LaunchDaemons/com.apple.bsd.SMJobBlessHelper.plist
/Library/PrivilegedHelperTools/com.apple.bsd.SMJobBlessHelper
一般ユーザ権限でSMJobBlessAppを起動すると、パスワードが聞かれます。パスワードが正しく
入力されると、SMJobBlessHelperは所有者が rootで上記の位置にコピーされているため
ヘルパツールは起動されると特権をもって実行されることになります。
SMJobBlessでインストールされたヘルパツールは同梱の Uninstall.shを sudoで起動するとアンインストール
されます。
戻る