1# -*- coding: utf-8 -*- 2# 3# (c) Copyright 2003-2015 HP Development Company, L.P. 4# 5# This program is free software; you can redistribute it and/or modify 6# it under the terms of the GNU General Public License as published by 7# the Free Software Foundation; either version 2 of the License, or 8# (at your option) any later version. 9# 10# This program is distributed in the hope that it will be useful, 11# but WITHOUT ANY WARRANTY; without even the implied warranty of 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13# GNU General Public License for more details. 14# 15# You should have received a copy of the GNU General Public License 16# along with this program; if not, write to the Free Software 17# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18# 19# Author: Stan Dolson , Goutam Kodu 20# 21 22# Std Lib 23import os 24import os.path 25import sys 26 27# Local 28from .g import * 29from .codes import * 30from . import utils, password 31from installer import pluginhandler 32 33# DBus 34import dbus 35import dbus.service 36 37if PY3: 38 from gi import _gobject as gobject 39else: 40 import gobject 41 42import warnings 43# Ignore: .../dbus/connection.py:242: DeprecationWarning: object.__init__() takes no parameters 44# (occurring on Python 2.6/dBus 0.83/Ubuntu 9.04) 45warnings.simplefilter("ignore", DeprecationWarning) 46 47 48class AccessDeniedException(dbus.DBusException): 49 _dbus_error_name = 'com.hp.hplip.AccessDeniedException' 50 51class UnsupportedException(dbus.DBusException): 52 _dbus_error_name = 'com.hp.hplip.UnsupportedException' 53 54class UsageError(dbus.DBusException): 55 _dbus_error_name = 'com.hp.hplip.UsageError' 56 57 58POLICY_KIT_ACTION = "com.hp.hplip" 59INSTALL_PLUGIN_ACTION = "com.hp.hplip.installplugin" 60 61 62def get_service_bus(): 63 return dbus.SystemBus() 64 65 66def get_service(bus=None): 67 if not bus: 68 bus = get_service_bus() 69 70 service = bus.get_object(BackendService.SERVICE_NAME, '/') 71 service = dbus.Interface(service, BackendService.INTERFACE_NAME) 72 return service 73 74 75class PolicyKitAuthentication(object): 76 def __init__(self): 77 super(PolicyKitAuthentication, self).__init__() 78 self.pkit = None 79 self.auth = None 80 81 82 def is_authorized(self, action_id, pid=None): 83 if pid == None: 84 pid = os.getpid() 85 86 pid = dbus.UInt32(pid) 87 88 authorized = self.policy_kit.IsProcessAuthorized(action_id, pid, False) 89 log.debug("is_authorized(%s) = %r" % (action_id, authorized)) 90 91 return (authorized == 'yes') 92 93 94 def obtain_authorization(self, action_id, widget=None): 95 if self.is_authorized(action_id): 96 return True 97 98 xid = (widget and widget.get_toplevel().window.xid or 0) 99 xid, pid = dbus.UInt32(xid), dbus.UInt32(os.getpid()) 100 101 granted = self.auth_agent.ObtainAuthorization(action_id, xid, pid) 102 log.debug("obtain_authorization(%s) = %r" % (action_id, granted)) 103 104 return bool(granted) 105 106 107 def get_policy_kit(self): 108 if self.pkit: 109 return self.pkit 110 111 service = dbus.SystemBus().get_object('org.freedesktop.PolicyKit', '/') 112 self.pkit = dbus.Interface(service, 'org.freedesktop.PolicyKit') 113 return self.pkit 114 115 policy_kit = property(get_policy_kit) 116 117 118 def get_auth_agent(self): 119 if self.auth: 120 return self.auth 121 122 self.auth = dbus.SessionBus().get_object( 123 'org.freedesktop.PolicyKit.AuthenticationAgent', '/') 124 return self.auth 125 126 auth_agent = property(get_auth_agent) 127 128 129 130class PolicyKitService(dbus.service.Object): 131 def check_permission_v0(self, sender, action=POLICY_KIT_ACTION): 132 if not sender: 133 log.error("Session not authorized by PolicyKit") 134 raise AccessDeniedException('Session not authorized by PolicyKit') 135 136 try: 137 policy_auth = PolicyKitAuthentication() 138 bus = dbus.SystemBus() 139 140 dbus_object = bus.get_object('org.freedesktop.DBus', '/') 141 dbus_object = dbus.Interface(dbus_object, 'org.freedesktop.DBus') 142 143 pid = dbus.UInt32(dbus_object.GetConnectionUnixProcessID(sender)) 144 145 granted = policy_auth.is_authorized(action, pid) 146 if not granted: 147 log.error("Process not authorized by PolicyKit") 148 raise AccessDeniedException('Process not authorized by PolicyKit') 149 150 granted = policy_auth.policy_kit.IsSystemBusNameAuthorized(action, 151 sender, 152 False) 153 if granted != 'yes': 154 log.error("Session not authorized by PolicyKit version 0") 155 raise AccessDeniedException('Session not authorized by PolicyKit') 156 157 except AccessDeniedException: 158 log.warning("AccessDeniedException") 159 raise 160 161 except dbus.DBusException as ex: 162 log.warning("AccessDeniedException %r", ex) 163 raise AccessDeniedException(ex.message) 164 165 166 def check_permission_v1(self, sender, connection, action=POLICY_KIT_ACTION): 167 if not sender or not connection: 168 log.error("Session not authorized by PolicyKit") 169 raise AccessDeniedException('Session not authorized by PolicyKit') 170 171 system_bus = dbus.SystemBus() 172 obj = system_bus.get_object("org.freedesktop.PolicyKit1", 173 "/org/freedesktop/PolicyKit1/Authority", 174 "org.freedesktop.PolicyKit1.Authority") 175 policy_kit = dbus.Interface(obj, "org.freedesktop.PolicyKit1.Authority") 176 177 subject = ( 178 'system-bus-name', 179 { 'name' : dbus.String(sender, variant_level = 1) } 180 ) 181 details = { '' : '' } 182 flags = dbus.UInt32(1) # AllowUserInteraction = 0x00000001 183 cancel_id = '' 184 185 (ok, notused, details) = \ 186 policy_kit.CheckAuthorization(subject, 187 action, 188 details, 189 flags, 190 cancel_id) 191 if not ok: 192 log.error("Session not authorized by PolicyKit version 1") 193 raise AccessDeniedException("Session not authorized by PolicyKit") 194 195 return ok 196 197 198if utils.to_bool(sys_conf.get('configure', 'policy-kit')): 199 class BackendService(PolicyKitService): 200 INTERFACE_NAME = 'com.hp.hplip' 201 SERVICE_NAME = 'com.hp.hplip' 202 203 def __init__(self, connection=None, path='/'): 204 if connection is None: 205 connection = get_service_bus() 206 207 super(BackendService, self).__init__(connection, path) 208 209 self.name = dbus.service.BusName(self.SERVICE_NAME, connection) 210 self.loop = gobject.MainLoop() 211 self.version = 0 212 log.set_level("debug") 213 214 def run(self, version=None): 215 if version is None: 216 version = policykit_version() 217 if version is None: 218 log.error("Unable to determine installed PolicyKit version") 219 return 220 221 self.version = version 222 log.debug("Starting back-end service loop (version %d)" % version) 223 224 self.loop.run() 225 226 227 @dbus.service.method(dbus_interface=INTERFACE_NAME, 228 in_signature='s', out_signature='b', 229 sender_keyword='sender', 230 connection_keyword='connection') 231 def installPlugin(self, src_dir, sender=None, connection=None): 232 if self.version == 0: 233 try: 234 self.check_permission_v0(sender, INSTALL_PLUGIN_ACTION) 235 except AccessDeniedException as e: 236 log.error("installPlugin: Failed due to permission error [%s]" %e) 237 return False 238 239 elif self.version == 1: 240 if not self.check_permission_v1(sender, 241 connection, 242 INSTALL_PLUGIN_ACTION): 243 return False 244 245 else: 246 log.error("installPlugin: invalid PolicyKit version %d" % self.version) 247 return False 248 249 log.debug("installPlugin: installing from '%s'" % src_dir) 250 try: 251 from installer import pluginhandler 252 except ImportError as e: 253 log.error("Failed to Import pluginhandler") 254 return False 255 256 pluginObj = pluginhandler.PluginHandle() 257 if not pluginObj.copyFiles(src_dir): 258 log.error("Plugin installation failed") 259 return False 260 261 return True 262 263 264 @dbus.service.method(dbus_interface=INTERFACE_NAME, 265 in_signature='s', out_signature='b', 266 sender_keyword='sender', 267 connection_keyword='connection') 268 def shutdown(self, arg, sender=None, connection=None): 269 log.debug("Stopping backend service") 270 self.loop.quit() 271 272 return True 273 274 275 276class PolicyKit(object): 277 def __init__(self, version=None): 278 if version is None: 279 version = policykit_version() 280 if version is None: 281 log.debug("Unable to determine installed PolicyKit version") 282 return 283 284 self.bus = dbus.SystemBus() 285 self.obj = self.bus.get_object(POLICY_KIT_ACTION, "/") 286 self.iface = dbus.Interface(self.obj, dbus_interface=POLICY_KIT_ACTION) 287 self.version = version 288 289 def installPlugin(self, src_dir): 290 if self.version == 0: 291 auth = PolicyKitAuthentication() 292 if not auth.is_authorized(INSTALL_PLUGIN_ACTION): 293 if not auth.obtain_authorization(INSTALL_PLUGIN_ACTION): 294 return None 295 296 try: 297 ok = self.iface.installPlugin(src_dir) 298 return ok 299 except dbus.DBusException as e: 300 log.debug("installPlugin: %s" % str(e)) 301 return False 302 303 304 def shutdown(self): 305 if self.version == 0: 306 auth = PolicyKitAuthentication() 307 if not auth.is_authorized(INSTALL_PLUGIN_ACTION): 308 if not auth.obtain_authorization(INSTALL_PLUGIN_ACTION): 309 return None 310 311 try: 312 ok = self.iface.shutdown("") 313 return ok 314 except dbus.DBusException as e: 315 log.debug("shutdown: %s" % str(e)) 316 return False 317 318 319 320 321 322def run_plugin_command(required=True, plugin_reason=PLUGIN_REASON_NONE, Mode = GUI_MODE): 323 324 if utils.to_bool(sys_conf.get('configure', 'policy-kit')): 325 try: 326 obj = PolicyKit() 327 su_sudo = "%s" 328 need_sudo = False 329 log.debug("Using PolicyKit for authentication") 330 except dbus.DBusException as ex: 331 log.error("PolicyKit NOT installed when configured for use. [%s]"%ex) 332 333 req = '--required' 334 if not required: 335 req = '--optional' 336 337 if utils.which("hp-plugin"): 338 p_path="hp-plugin" 339 else: 340 p_path="python ./plugin.py" 341 342 cmd = "%s -u %s --reason %s" %(p_path, req, plugin_reason) 343 log.debug("%s" % cmd) 344 status = os_utils.execute(cmd) 345 346 return (status == 0, True) 347 348 349def policykit_version(): 350 if os.path.isdir("/usr/local/share/polkit-1"): 351 return 1 352 elif os.path.isdir("/usr/local/share/PolicyKit"): 353 return 0 354 else: 355 return None 356