The program that uses PolicyKit usually has a Dbus daemon program to complete the related operation, this Dbus daemon will register a system bus service name, in response to request root privileged operation, When the Dbus request arrives, it verifies that the requestor has the appropriate permissions to invoke the operation (method), which is defined in the. conf file (described later).
First define the system Dbus daemon, write a. service file to launch our daemon
Org.example.foo.service
File Placement Directory:/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
Where name is the registered Systembus service name
Exec is the path where the daemon program is located
We're starting with root privileges.
When a program requests the Org.example.foo service, the system will automatically start our daemon with root.
For information see here D-bus system Bus activation
Note: Sessionbus's ' org.freedesktop.PolicyKit.AuthenticationAgent ' service is automatically activated only when the authentication is requested, and is automatically turned off after a period of time.
And look at our daemon program.
policykit_dbus_foo_daemon.py
File Placement Directory:/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
Ten Import Dbus.service
Import Dbus.mainloop.glib
12
Class Notprivilegedexception (Dbus. Dbusexception):
_dbus_error_name = "Org.example.foo.dbus.service.PolKit.NotPrivilegedException"
def __init__ (self, action_id, *p, **k):
Self._dbus_error_name = Self.__class__._dbus_error_name + "." + action_id
+ Super (notprivilegedexception, self). __init__ (*p, **k)
18
def require_auth (action_id):
def require_auth_decorator (func):
def _func (*args,**kwds):
Revoke_if_one_shot = True
System_bus = Dbus. Systembus ()
Auth_obj = System_bus.get_object (' org.freedesktop.PolicyKit ', '/')
Auth_interface = Dbus. Interface (auth_obj, ' org.freedesktop.PolicyKit ')
-Try:
Dbus_name = kwds[' Sender_keyword ']
Except:
Raise Notprivilegedexception (ACTION_ID)
granted = Auth_interface. Issystembusnameauthorized (Action_id,dbus_name,revoke_if_one_shot)
If granted! = ' Yes ':
Raise Notprivilegedexception (ACTION_ID)
33
return func (*args,**kwds)
35
_func.func_name = Func.func_name
PNS _func.__name__ = func.__name__
_func.__doc__ = func.__doc__
_func return
Require_auth_decorator return
41
42 ""
A D-bus Service that PolicyKit Controls access to.
44 ""
Class Policykitfoomechanism (Dbus.service.Object):
service_name = ' Org.example.foo '
Service_path = '/org/example/foo '
interface_name = ' Org.example.foo '
49
def __init__ (self, conn, Object_path=service_path):
Wuyi dbus.service.object.__init__ (SELF, conn, Object_path)
52
@dbus. Service.method (Dbus_interface=interface_name, in_signature= ' ss ', out_signature= ' s ', sender_keyword= ' Sender ')
WriteFile def (self, filepath, Contents,sender=none):
55 ""
The contents to a file, requires Sudo/root access to doing so.
PolicyKit won't allow this function to be called without sudo/root
Authenticate access, and would ask the user to the if necessary, when
The application calls PolicyKit ' s obtainauthentication ().
60 ""
@require_auth (' org.example.foo.modify ')
+ def _write_file (Filepath,contents,sender_keyword = None):
+ F = open (filepath, ' W ')
F.write (contents)
F.close ()
The return ' done '
_write_file return (Filepath,contents,sender_keyword = sender)
68
@dbus. Service.method (Dbus_interface=interface_name, in_signature= ' s ', out_signature= ' as ', sender_keyword= ' Sender ')
Runcmd def (self, Cmdstr, Sender=none):
@require_auth (' Org.example.foo.sys ')
_run_cmd def (Cmdstr,sender_keyword = None):
Os.popen f = (CMDSTR)
A. Output = F.readlines ()
F.close ()
Return output
_run_cmd return (Cmdstr,sender_keyword = sender)
78
@dbus. Service.method (dbus_interface=interface_name,in_signature= ", out_signature=", sender_keyword= ' sender ')
def Exit (self, Sender=none):
Bayi @require_auth (' Org.example.foo.sys ')
_exit def (Sender_keyword = None):
Loop.quit ()
_exit return (Sender_keyword = sender)
85
@dbus. Service.method (dbus_interface=interface_name,in_signature= ", out_signature= ' s ')
def hello (self):
The return ' Hello '
89
if __name__ = = ' __main__ ':
Dbus.mainloop.glib.DBusGMainLoop (Set_as_default=true)
The Dbus bus =. Systembus ()
Name = Dbus.service.BusName (policykitfoomechanism.service_name, bus)
94 The_object = Policykitfoomechanism (BUS)
The loop = GObject. Mainloop ()
Loop.run ()
97
98
Three operations are defined in the daemon program that require permissions, an operation that does not require permissions, and an action ID that defines how the operation (method) requires validation. The program asks the org.freedesktop.PolicyKit.AuthenticationAgent to request the corresponding Action ID permission before it can be called.
Otherwise you will be prompted not to have permission, the Hello operation does not require permission to operate, the difference is whether to request the first to Org.freedesktop.Policykit detect this dbus please ask if there is previleged.
Call the Issystembusnameauthorized method to verify that the pass returns ' Yes ', otherwise the other string is returned
Use the command below to view the issystembusnameauthorized details of the method Introspec
Dbus-send--system--print-reply--dest=org.freedesktop.policykit/org.freedesktop.dbus.introspectable.introspect
It is worth noting here that if you define a series of system-level invoke operations (starting with the previous program as root, but removing the previous @require_auth section), you must ensure that each operation is authenticated with permission, that is, add this thing @require_auth (' Org.example.foo.sys ')
If you define the Dbus operation of the write file, but do not perform permission validation, an ordinary user's Dbus call will also be called through, that is, ordinary users can arbitrarily overwrite any file, which is very dangerous
You can also try to remove the previous @require_auth section, and then start the service, and use D-feet to invoke the WriteFile method to write the file at random on the root directory
--Off-topic-
I wanted to write the procedure in this form.
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 ()
This writing, with D-feet looked under, service does not come, adjusted for a long time also can not find out the reason, but write this kind of redundant way--!, see can have expert guidance under, not grateful!!
Then define who can invoke these operations (methods) in the. conf file definition
Org.example.foo.conf
File Placement Directory:/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" >
Ten <allow own= "Org.example.foo"/>
One <allow send_interface= "Org.example.foo"/>
</policy>
13
<!--allow introspectable-->< can be called by anyone, using. Policy in the later.
<policy context= "Default" >
<allow send_interface= "Org.example.foo"/>
<allow send_interface= "Org.freedesktop.DBus.Introspectable"/>
</policy>
19
</busconfig>
21st
followed by the definition of the associated action ID, defined in the. policy file
which defines the way and time of authorization authentication can have the following several
No
auth_self$$
auth_admin$$
Yes
Where add $$ can append suffix _one_shot,_keep_session,_keep_always
Its meaning is literally clear.
You can also see man policykit.conf
Can't write? Refer to the/usr/share/policykit/policy directory for a heap of. policy files.
After writing, you can use the tool polkit-policy-file-validate to verify that it is valid.
Org.example.foo.policy
File Placement Directory:/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
Ten <action id= "Org.example.foo.modify" >
<description>example Write access</description>
<message>system policy prevents write access to the Example service</message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
</action>
18
<action id= "Org.example.foo.sys" >
<description>example system action</description>
<message>system policy prevents do System action to the Example service</message>
<defaults>
<allow_inactive>no</allow_inactive>
<allow_active>auth_admin</allow_active>
</defaults>
</action>
27
28
</policyconfig>
Do the above work, we can write our call-end program
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
def auth_proxy (func):
Dbusname = ' org.freedesktop.PolicyKit.AuthenticationAgent '
Dbuspath = '/'
Dbusinterface = ' org.freedesktop.PolicyKit.AuthenticationAgent '
Exc_name = "Org.example.foo.dbus.service.PolKit.NotPrivilegedException"
def auth_proxy_wrapper (*args, **kwds):
Try:
return func (*args, **kwds)
Except Dbus. Dbusexception, E:
Exc_name = E.get_dbus_name ()
If Exc_name.startswith (Exc_name + "."):
Session_bus = Dbus. Sessionbus ()
Auth_obj = Session_bus.get_object (Dbusname, Dbuspath)
Auth_interface = Dbus. Interface (Auth_obj,dbusinterface)
action_id = Exc_name[len (exc_name) + 1:]
granted = Auth_interface. Obtainauthorization (action_id, Dbus. UInt32 (0), Dbus. UInt32 (Os.getpid ()))
If not granted:
Raise
else:
Raise
31
return func (*args, **kwds)
Return Auth_proxy_wrapper
34
Class Dbustestproxy:
service_name = ' Org.example.foo '
PNS Service_path = '/org/example/foo '
interface_name = ' Org.example.foo '
__init__ def (self):
Self.bus = Dbus. Systembus ()
SELF.O = Self.bus.get_object (self. Service_name,self. Service_path)
SELF.I = Dbus. Interface (self.o,self. Interface_name)
43
@auth_proxy
def writefilewithauth (self,filepath,contents):
Self.i.writefile return (filepath,contents)
47
def writefilewithoutauth (self,filepath,contents):
Self.i.writefile return (filepath,contents)
50
Wuyi @auth_proxy
Runcmd def (SELF,CMDSTR):
Self.i.runcmd return (CMDSTR)
54
@auth_proxy
+ def Exit (self):
Self.i.exit return ()
58
#do need to Auth
def hello (self):
Self.i.hello return ()
62
63
if __name__ = = "__main__":
p = dbustestproxy ()
#print p.runcmd (' Ls-al ')
P.writefilewithauth print ('/text ', ' test\n ')
#print P.writefilewithoutauth ('/text ', ' test\n ')
#p. Exit ()
Print P.hello ()
Run the above program to try the Writefilewithauth method will pop up the verification dialog box, the password is correct in the root directory will be written to the file, call Writefilewithoutauth because there is no call permission validation
Instead, returns an exception with no privileged, because the WriteFile operation requires permission.
The above procedure is quite simple, because I am also a novice python, I believe you can see clearly.
Finally, make a package, click Download policykit_dbus_foo.7z
#install
sudo./install.sh Install
#remove
sudo./install.sh Uninstall
#test
./policykit_dbus_foo_client.py
The above system environment is 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
Finally found an open source project Python-slip
The slip.dbus.polkit section, which encapsulates the policykit, makes it easier to use PolicyKit in your project. I think Python is simple enough. Orz)
NOTE: Reprint Annotated source
Http://www.cnblogs.com/joe2k8/archive/2009/05/24/1488074.html
Dbus and PolicyKit instance (Python) () goto