dbus 和 policykit 實例篇(python)

dbus 和 policykit 實例篇(python)

使用policykit 的程序一般都有一個dbus daemon程序來完成相關操作,這個dbus daemon 會在系統注冊一個system bus 服務名,用于響應要求root privileged的操作,當dbus請求到達時會先驗證請求程序是否有相應的權限來調用這個操作(方法),而這是在.conf文件中定義的(后面說明)。

首先定義個System Dbus daemon,寫一個.service文件來啟動我們的daemon

?org.example.foo.service

文件放置目錄:/usr/share/dbus-1/system-services

1?[D-BUS?Service]
2?Name=org.example.foo
3?Exec=/usr/local/libexec/policykit_dbus_foo_daemon.py
4?User=root

?

其中Name是注冊的SystemBus 服務名

Exec 是daemon 程序所在路徑

我們以root權限啟動

當有程序請求org.example.foo服務時,系統會自動以root啟動我們的daemon。

相關信息看這里D-Bus system bus activation

?注: SessionBus 的 'org.freedesktop.PolicyKit.AuthenticationAgent' 的服務,只有在請求認證的時候才自動啟動,打開過一段時間會自動關閉。

再看我們的daemon程序

policykit_dbus_foo_daemon.py

文件放置目錄:/usr/local/libexec

復制代碼
?1?#!/usr/bin/python
?2?#?-*-?coding:?UTF-8?-*-
?3?"""
?4?Author:?joe.zhou
?5?"""
?6?import?os
?7?import?sys
?8?import?gobject
?9?import?dbus
10?import?dbus.service
11?import?dbus.mainloop.glib
12?
13?class?NotPrivilegedException?(dbus.DBusException):
14?????_dbus_error_name?=?"org.example.foo.dbus.service.PolKit.NotPrivilegedException"
15?????def?__init__?(self,?action_id,?*p,?**k):
16?????????self._dbus_error_name?=?self.__class__._dbus_error_name?+?"."?+?action_id
17?????????super?(NotPrivilegedException,?self).__init__?(*p,?**k)
18?????????
19?def?require_auth?(action_id):
20?????def?require_auth_decorator(func):????????
21?????????def?_func(*args,**kwds):
22?????????????revoke_if_one_shot?=?True
23?????????????system_bus?=?dbus.SystemBus()
24?????????????auth_obj?=?system_bus.get_object('org.freedesktop.PolicyKit','/')
25?????????????auth_interface?=?dbus.Interface(auth_obj,'org.freedesktop.PolicyKit')
26?????????????try:
27?????????????????dbus_name?=?kwds['sender_keyword']????????????????
28?????????????except:
29?????????????????raise?NotPrivilegedException?(action_id)
30?????????????granted?=?auth_interface.IsSystemBusNameAuthorized(action_id,dbus_name,revoke_if_one_shot)
31?????????????if?granted?!=?'yes':
32?????????????????raise?NotPrivilegedException?(action_id)
33?
34?????????????return?func(*args,**kwds)
35?????????????
36?????????_func.func_name?=?func.func_name
37?????????_func.__name__?=?func.__name__
38?????????_func.__doc__?=?func.__doc__????????
39?????????return?_func????
40?????return?require_auth_decorator
41?
42?'''
43?A?D-Bus?service?that?PolicyKit?controls?access?to.
44?'''
45?class?PolicyKitFooMechanism(dbus.service.Object):??????
46?????SERVICE_NAME?=?'org.example.foo'
47?????SERVICE_PATH?=?'/org/example/foo'
48?????INTERFACE_NAME?=?'org.example.foo'
49?
50?????def?__init__(self,?conn,?object_path=SERVICE_PATH):
51?????????dbus.service.Object.__init__(self,?conn,?object_path)
52?
53?????@dbus.service.method(dbus_interface=INTERFACE_NAME,?in_signature='ss',out_signature='s',sender_keyword='sender')
54?????def?WriteFile(self,?filepath,?contents,sender=None):
55?????????'''
56?????????Write?the?contents?to?a?file?that?requires?sudo/root?access?to?do?so.
57?????????PolicyKit?will?not?allow?this?function?to?be?called?without?sudo/root?
58?????????access,?and?will?ask?the?user?to?authenticate?if?necessary,?when?
59?????????the?application?calls?PolicyKit's?ObtainAuthentication().
60?????????'''
61?????????@require_auth('org.example.foo.modify')
62?????????def?_write_file(filepath,contents,sender_keyword?=?None):
63?????????????f?=?open(filepath,?'w')
64?????????????f.write(contents)
65?????????????f.close()
66?????????????return?'done'
67?????????return?_write_file(filepath,contents,sender_keyword?=?sender)?????
68?????
69?????@dbus.service.method(dbus_interface=INTERFACE_NAME,?in_signature='s',out_signature='as',sender_keyword='sender')
70?????def?RunCmd(self,?cmdStr,?sender=None):
71?????????@require_auth('org.example.foo.sys')
72?????????def?_run_cmd(cmdStr,sender_keyword?=?None):
73?????????????f?=?os.popen(cmdStr)
74?????????????output?=?f.readlines()
75?????????????f.close()
76?????????????return?output????????
77?????????return?_run_cmd(cmdStr,sender_keyword?=?sender)
78?
79?????@dbus.service.method(dbus_interface=INTERFACE_NAME,in_signature='',?out_signature='',sender_keyword='sender')
80?????def?Exit(self,?sender=None):
81?????????@require_auth('org.example.foo.sys')
82?????????def?_exit(sender_keyword?=?None):
83?????????????loop.quit()
84?????????return?_exit(sender_keyword?=?sender)
85?????????
86?????@dbus.service.method(dbus_interface=INTERFACE_NAME,in_signature='',?out_signature='s')????
87?????def?hello(self):
88?????????return?'hello'
89?
90?if?__name__?==?'__main__':
91?????dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
92?????bus?=?dbus.SystemBus()
93?????name?=?dbus.service.BusName(PolicyKitFooMechanism.SERVICE_NAME,?bus)
94?????the_object?=?PolicyKitFooMechanism(bus)
95?????loop?=?gobject.MainLoop()
96?????loop.run()
97?
98?
復制代碼

?

在daemon程序中定義了三個需要權限的操作,一個不需要權限的操作,也定義了操作(方法)要求驗證的action id,程序請求寫文件操作時需先向org.freedesktop.PolicyKit.AuthenticationAgent 請求對應的 action id權限才能再進行調用,

否則會提示沒有權限,hello操作不需要操作權限,兩者區別在于來請求時是否先向 org.freedesktop.Policykit 檢測這個 dbus 請求是否有 previleged。

具體是調用? IsSystemBusNameAuthorized 方法來驗證,通過則返回'yes',否則 返回其它字符串

使用命令以下命令查看方法的 IsSystemBusNameAuthorized 詳細 introspec

dbus-send?--system?--print-reply?--dest=org.freedesktop.PolicyKit?/?org.freedesktop.DBus.Introspectable.Introspect

?

在這里值得注意的是如果你定義了一系列的系統級調用操作(以root方式啟動前面的程序,但去除了前面的@require_auth 部分),你必須保證每個操作要進行權限驗證,即加上這個東西@require_auth('org.example.foo.sys')

如果你定義了寫文件的dbus操作,但是沒有進行權限驗證的話,一個普通用戶的dbus 調用請求也會調用通過,即普通用戶可以隨意改寫任何文件,這是很危險的

你也可以嘗試把前面的@require_auth部分去掉,再啟動服務,用 d-feet? 就可以調用WriteFile方法隨意地在根目錄上寫入文件

?

?

--題外話——

本想將程序寫成這種形式的

1?@require_auth('org.example.foo.sys')
2?@dbus.service.method(dbus_interface=INTERFACE_NAME,in_signature='',?out_signature='',sender_keyword='sender')
3?def?Exit(self,?sender=None):
4?????loop.quit()

?這樣寫,用d-feet 看了下,服務起不來,調了很久也找不出原因,無奈寫成這種冗余的方式 --!,看能否有高手指點下,不盡感激!!

?

接著定義誰可以調用這些操作(方法),在.conf 文件定義

org.example.foo.conf

文件放置目錄:/etc/dbus-1/system.d

復制代碼
?1?<?xml?version="1.0"?encoding="UTF-8"?>?<!--?-*-?XML?-*-?-->
?2?
?3?<!DOCTYPE?busconfig?PUBLIC
?4??"-//freedesktop//DTD?D-BUS?Bus?Configuration?1.0//EN"
?5??"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
?6?<busconfig>
?7?
?8???<!--?Only?root?can?own?the?service?-->
?9???<policy?user="root">
10?????<allow?own="org.example.foo"/>
11?????<allow?send_interface="org.example.foo"/>
12???</policy>
13?
14???<!--?allow?Introspectable?--><!-- 任何人都可以調用,在后面使用.policy進行約束-->
15???<policy?context="default">
16?????<allow?send_interface="org.example.foo"/>
17?????<allow?send_interface="org.freedesktop.DBus.Introspectable"/>
18???</policy>
19?
20?</busconfig>
21?
復制代碼

?

?

再跟著是定義相關的 action id了,在.policy 文件定義

其中定義授權認證的方式和時效可以有以下幾種

復制代碼
no?
auth_self$$
auth_admin$$
yes

其中加$$的可以附加后綴?_one_shot,_keep_session,_keep_always
其意義字面已經很清楚了
復制代碼

?另外也可以看看 man policykit.conf

不會寫?參照/usr/share/PolicyKit/policy 目錄下一堆 .policy文件總會了吧

寫好后可以用工具 polkit-policy-file-validate 驗證下是否有效

org.example.foo.policy

文件放置目錄:/usr/share/PolicyKit/policy

復制代碼
?1?<?xml?version="1.0"?encoding="UTF-8"?>
?2?<!DOCTYPE?policyconfig?PUBLIC
?3??"-//freedesktop//DTD?PolicyKit?Policy?Configuration?1.0//EN"
?4??"http://www.freedesktop.org/standards/PolicyKit/1.0/policyconfig.dtd">
?5?<policyconfig>
?6?
?7???<vendor>Example?Application</vendor>
?8???<vendor_url>http://fedoraproject.org/example</vendor_url>
?9?
10????<action?id="org.example.foo.modify">
11?????<description>Example?Write?Access</description>
12?????<message>System?policy?prevents?write?access?to?the?Example?service</message>
13?????<defaults>
14???????<allow_inactive>no</allow_inactive>
15???????<allow_active>auth_admin</allow_active>
16?????</defaults>
17???</action>
18?
19???<action?id="org.example.foo.sys">
20?????<description>Example?system?action</description>
21?????<message>System?policy?prevents?do?system?action?to?the?Example?service</message>
22?????<defaults>
23???????<allow_inactive>no</allow_inactive>
24???????<allow_active>auth_admin</allow_active>
25?????</defaults>
26???</action>
27?
28??
29?</policyconfig>
復制代碼

?

做好以上工作,我們可以寫我們的調用端程序了

?

復制代碼
?1?#!/usr/bin/python
?2?#?-*-?coding:?UTF-8?-*-
?3?import?os
?4?import?sys
?5?import?gobject
?6?import?dbus
?7?import?dbus.service
?8?import?dbus.mainloop.glib
?9?import?traceback
10?
11?def?auth_proxy?(func):
12?????DBUSNAME?=?'org.freedesktop.PolicyKit.AuthenticationAgent'
13?????DBUSPATH?=?'/'?
14?????DBUSINTERFACE?=?'org.freedesktop.PolicyKit.AuthenticationAgent'
15?????EXC_NAME?=??"org.example.foo.dbus.service.PolKit.NotPrivilegedException"??
16?????def?auth_proxy_wrapper?(*args,?**kwds):
17?????????try:
18?????????????return?func?(*args,?**kwds)
19?????????except?dbus.DBusException,?e:
20?????????????exc_name?=?e.get_dbus_name?()
21?????????????if?exc_name.startswith?(EXC_NAME?+?"."):
22?????????????????session_bus?=?dbus.SessionBus?()
23?????????????????auth_obj?=?session_bus.get_object?(DBUSNAME,?DBUSPATH)
24?????????????????auth_interface?=?dbus.Interface(auth_obj,DBUSINTERFACE)
25?????????????????action_id?=?exc_name[len?(EXC_NAME)+1:]
26?????????????????granted?=?auth_interface.ObtainAuthorization?(action_id,?dbus.UInt32?(0),dbus.UInt32?(os.getpid?()))
27?????????????????if?not?granted:
28?????????????????????raise
29?????????????else:
30?????????????????raise
31?
32?????????return?func(*args,?**kwds)
33?????return?auth_proxy_wrapper
34?
35?class?DbusTestProxy:
36?????SERVICE_NAME?=?'org.example.foo'
37?????SERVICE_PATH?=?'/org/example/foo'
38?????INTERFACE_NAME?=?'org.example.foo'
39?????def?__init__(self):
40?????????self.bus?=?dbus.SystemBus()
41?????????self.o?=?self.bus.get_object(self.SERVICE_NAME,self.SERVICE_PATH)
42?????????self.i?=?dbus.Interface(self.o,self.INTERFACE_NAME)
43?????
44?????@auth_proxy
45?????def?WriteFileWithAuth(self,filePath,contents):
46?????????return?self.i.WriteFile(filePath,contents)
47?
48?????def?WriteFileWithoutAuth(self,filePath,contents):
49?????????return?self.i.WriteFile(filePath,contents)
50????
51?????@auth_proxy
52?????def?RunCmd(self,cmdStr):
53?????????return?self.i.RunCmd(cmdStr)
54?????
55?????@auth_proxy
56?????def?Exit(self):
57?????????return?self.i.Exit()
58?????
59?????#do?not?need?to?auth
60?????def?hello(self):
61?????????return?self.i.hello()
62?????
63?????
64?if?__name__?==?"__main__":
65?????p?=?DbusTestProxy()
66?????#print?p.RunCmd('ls?-al')
67?????print?p.WriteFileWithAuth('/text','test\n')
68?????#print?p.WriteFileWithoutAuth('/text','test\n')
69?????#p.Exit()
70?????print?p.hello()
復制代碼

?

運行上面的程序嘗試WriteFileWithAuth 方法會彈出驗證的對話框,口令正確的話會在根目錄寫入文件,調用WriteFileWithoutAuth會因為沒有調用權限驗證

而返回沒有privileged的 異常,因為WriteFile操作是需要權限的。

?以上程序相當的簡單,因為我也是python新手,相信你也看得明白。

最后打個包,點擊下載 policykit_dbus_foo.7z

?

復制代碼
#install
sudo?./install.sh?install

#remove
sudo?./install.sh?uninstall

#test
./policykit_dbus_foo_client.py
復制代碼


以上系統環境為ubuntu 8.04

Reference


?

http://hal.freedesktop.org/docs/PolicyKit?

Policy, Mechanism and Time zones

http://dbus.freedesktop.org/doc/dbus-specification.html

http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html

python Decorator for functions and methods

?最后發現了個開源項目 python-slip

其中 slip.dbus.polkit 部分,封裝了policykit,?能使你在項目中使用policykit 更容易些.(我覺得python已經夠簡單的了Orz)

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274086.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274086.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274086.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

一個實際的sonar代碼檢查的配置文件

國內私募機構九鼎控股打造APP&#xff0c;來就送 20元現金領取地址&#xff1a;http://jdb.jiudingcapital.com/phone.html內部邀請碼&#xff1a;C8E245J &#xff08;不寫邀請碼&#xff0c;沒有現金送&#xff09;國內私募機構九鼎控股打造&#xff0c;九鼎投資是在全國股份…

JavaScript 第二課 JavaScript語法

本章內容&#xff1a;語句變量和數組操作符條件語句和循環語句函數與對象 ------------------------------------------------------------- 準備&#xff1a; 編寫JavaScript腳本只需要一個普通地文本編輯器和一個Web瀏覽器就足啦。 用JavaScript編寫的代碼必須通過HTML/XHTML…

和菜鳥一起學linux之DBUS基礎學習記錄

轉自&#xff1a;http://blog.csdn.net/eastmoon502136/article/details/10044993 D-Bus三層架構 D-Bus是一個為應用程序間通信的消息總線系統, 用于進程之間的通信。它是個3層架構的IPC 系統&#xff0c;包括&#xff1a; 1、函數庫libdbus &#xff0c;用于兩個應用程序互…

Android 第二十課 廣播機制(大喇叭)----發送自定義廣播(包括發送標準廣播和發送有序廣播)

廣播分為兩種類型&#xff1a;標準廣播和有序廣播 我們來看一下具體這兩者的具體區別&#xff1a; 1、發送標準廣播 我們需要先定義一個廣播接收器來準備接收此廣播才行&#xff0c;否則也是白發。 新建一個MyBroadcastReceiver,代碼如下&#xff1a; package com.example.broa…

八大排序算法

概述 排序有內部排序和外部排序&#xff0c;內部排序是數據記錄在內存中進行排序&#xff0c;而外部排序是因排序的數據很大&#xff0c;一次不能容納全部的排序記錄&#xff0c;在排序過程中需要訪問外存。 我們這里說說八大排序就是內部排序。 當n較大&#xff0c;則應采用…

需求?

1 需求怎樣描述清楚&#xff1f; 利用用例技術&#xff0c;一般這里指的是系統用例&#xff1b;包括以下幾個內容&#xff1a; 用例視圖 系統的功能描述&#xff1b; 用例規約 規定了用戶和系統的交互過程&#xff1b;用戶如何使用系統&#xff1b;用戶如何交互&#xff0c;以及…

Android 第二十一課 RecyclerView簡單的應用之編寫“精美”的聊天頁面

1、由于我們會使用到RecyclerView&#xff0c;因此首先需要在app/build.gradle當中添加依賴庫。如下&#xff1a; apply plugin: com.android.application .... dependencies {....compile com.android.support:recyclerview-v7:26.1.0 } 2、然后開始編寫主頁面&#xff0c;修該…

VS 2008 生成操作中各個選項的差別

近日&#xff0c;在編譯C#項目時經常發現有些時候明明代碼沒錯&#xff0c;但就是編譯不過&#xff0c;只有選擇重新編譯或者清理再編譯才會不出錯&#xff0c;本著求學的態度&#xff0c;搜羅了下VS2008IDE中生成操作的種類以及差別&#xff0c;整理如下&#xff1a;內容(Cont…

dbus-python指南

菜鳥學dbus-python&#xff0c;翻譯dbus-python指南&#xff0c;錯誤之處請在所難免&#xff0c;請諸位不吝賜教&#xff0c;多多指正&#xff01;查看英文原版請點這里。 連接總線Connecting to the Bus方法調用Making method calls代理對象proxy objects接口和方法Interfaces…

JavaScript 第三課 DOM

主要內容&#xff1a; 節點5個常用的DOM方法&#xff1a;getElementById、getElementByTagname、getElementByClassName、getAttribute和setAttribute詳細內容: 1、文檔&#xff1a;DOM中的“D”如果沒有document(文檔),DOM也就無從談起。當創建了一個網頁并把它加載到Web瀏覽器…

源碼編譯安裝Nginx

1.源碼下載 Nginx在github上有一個只讀源碼庫&#xff0c;我獲取的源碼方式為&#xff1a; git clone https://github.com/nginx/nginx.git 2.configure 我下載源碼的時候&#xff0c;github上的源碼的目錄結構為: auto, conf, contrib, docs, misc, src共6個目錄。src目錄是…

SOAP協議初級指南(2)

目前的技術存在的問題&#xff1f;   盡管DCOM和IIOP都是固定的協議&#xff0c;業界還沒有完全轉向其中任何一個協議。沒有融合的部分原因是文化的問題所致。而且在當一些組織試圖標準化一個或另一個協議的時候&#xff0c;兩個協議的技術適用性就被提出質疑。傳統上認為DC…

JavaScript 第四課 案例研究:JavaScript圖片庫

主要內容&#xff1a;編寫一個優秀的標記文件編寫一個JavaScript函數以顯示用戶想要查看的內容由標記出發函數調用使用幾個新方法擴展這個JavaScript函數 學習過DOM&#xff0c;我們用JavaScript和DOM去建立一個圖片庫。最好的辦法是什么呢&#xff1f; 利用JavaScript來建立圖…

windows下mongodb安裝與使用整理

一、首先安裝mongodb 1.下載地址&#xff1a;http://www.mongodb.org/downloads 2.解壓縮到自己想要安裝的目錄&#xff0c;比如d:\mongodb 3.創建文件夾d:\mongodb\data\db、d:\mongodb\data\log&#xff0c;分別用來安裝db和日志文件&#xff0c;在log文件夾下創建一個日志文…

可變參數列表(va_list,va_arg,va_copy,va_start,va_end)

本文轉自:http://blog.csdn.net/costa100/article/details/5787068 va_list arg_ptr&#xff1a;定義一個指向個數可變的參數列表指針&#xff1b;      va_start(arg_ptr, argN)&#xff1a;使參數列表指針arg_ptr指向函數參數列表中的第一個可選參數&#xff0c;說明&…

src與href屬性的區別

src和href之間存在區別&#xff0c;能混淆使用。src用于替換當前元素&#xff0c;href用于在當前文檔和引用資源之間確立聯系。 src是source的縮寫&#xff0c;指向外部資源的位置&#xff0c;指向的內容將會嵌入到文檔中當前標簽所在位置&#xff1b;在請求src資源時會將其指向…

USACO4.12Beef McNuggets(背包+數論)

昨天晚上寫的一題 結果USACO一直掛中 今天交了下 有一點點的數論知識 背包很好想 就是不好確定上界 官方題解&#xff1a; 這是一個背包問題。一般使用動態規劃求解。 一種具體的實現是&#xff1a;用一個線性表儲存所有的節點是否可以相加得到的狀態&#xff0c;然后每次可以…

Java 循環語句中 break,continue,return有什么區別?

break 結束循環&#xff0c;跳出循環體,進行后面的程序;continue 結束本次循環&#xff0c;進行下次循環;return 跳出循環體所在的方法&#xff0c;相當于結束該方法; 例子&#xff1a; public class whiletrueTest{public static void main(String[] args) {heihei();haha();…

Epoll模型詳解

轉自http://blog.163.com/huchengsz126/blog/static/73483745201181824629285/ Linux 2.6內核中提高網絡I/O性能的新方法-epoll I/O多路復用技術在比較多的TCP網絡服務器中有使用&#xff0c;即比較多的用到select函數。 1、為什么select落后 首先&#xff0c;在Linux內核中…

運算放大器單電源應用中的使用齊納二極管偏置方法

運算放大器單電源應用中的偏置方法除了使用大電阻使運放輸出達到電源電壓的一半外&#xff0c;還有使用齊納二極管&#xff08;穩壓管&#xff09;方法也能得到達到應用目的。 下面就推薦幾個齊納二極管&#xff08;分別對應著電源電壓是15V,12V&#xff0c;9V;5V&#xff09; …