~ubuntu-branches/ubuntu/maverick/ubuntu-system-service/maverick

« back to all changes in this revision

Viewing changes to backend/system-service-d

  • Committer: Bazaar Package Importer
  • Author(s): Michael Vogt
  • Date: 2008-08-19 14:18:18 UTC
  • Revision ID: james.westby@ubuntu.com-20080819141818-6gs3fa82dxidv52p
Tags: 0.1.6
* debian/control:
  - add missing depends on policykit and python-dbus
* add socks support
* support no_proxy environment

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
 
 
3
# (c) 2008 Canonical Ltd.
 
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 along
 
16
# with this program; if not, write to the Free Software Foundation, Inc.,
 
17
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
18
 
 
19
import sys
 
20
import gobject
 
21
import dbus
 
22
import dbus.service
 
23
import dbus.mainloop.glib 
 
24
import os
 
25
import apt_pkg
 
26
from UbuntuSystemService.utils import *
 
27
 
 
28
class UnknownProxyTypeError(dbus.DBusException):
 
29
    " a unknown proxy type was passed "
 
30
    pass
 
31
class PermissionDeniedError(dbus.DBusException):
 
32
    " permission denied by policy "
 
33
    pass
 
34
 
 
35
 
 
36
class ProxyBackend(dbus.service.Object): 
 
37
    DBUS_INTERFACE_NAME = "com.ubuntu.SystemService"
 
38
 
 
39
    SUPPORTED_PROXIES = ("http","ftp", "https", "socks")
 
40
 
 
41
    def __init__(self):
 
42
        bus_name = dbus.service.BusName(self.DBUS_INTERFACE_NAME,
 
43
                                        bus=dbus.SystemBus())
 
44
        dbus.service.Object.__init__(self, bus_name, '/')
 
45
        apt_pkg.InitConfig()
 
46
 
 
47
    def _authWithPolicyKit(self, sender, connection, priv):
 
48
        #print "_authWithPolicyKit()"
 
49
        system_bus = dbus.SystemBus()
 
50
        obj = system_bus.get_object("org.freedesktop.PolicyKit", 
 
51
                                    "/", 
 
52
                                    "org.freedesktop.PolicyKit")
 
53
        policykit = dbus.Interface(obj, "org.freedesktop.PolicyKit")
 
54
        info = dbus.Interface(connection.get_object('org.freedesktop.DBus',
 
55
                                              '/org/freedesktop/DBus/Bus', 
 
56
                                              False), 
 
57
                              'org.freedesktop.DBus')
 
58
        pid = info.GetConnectionUnixProcessID(sender) 
 
59
        #print "pid is:",pid
 
60
        #print "priv: ", priv
 
61
        # FIXME: not sure what revoke_if_one_shot (last arg) does
 
62
        ok = policykit.IsProcessAuthorized(priv, dbus.UInt32(pid), True)
 
63
        #print "ok: ", ok
 
64
        if ok == 'yes':
 
65
            return True
 
66
        return False
 
67
 
 
68
    def _etc_environment_proxy(self, proxy_type):
 
69
        " internal that returns the /etc/environment proxy "
 
70
        if not os.path.exists("/etc/environment"):
 
71
            return ""
 
72
        for line in open("/etc/environment"):
 
73
            if line.startswith("%s_proxy=" % proxy_type):
 
74
                (key, value) = line.strip().split("=")
 
75
                value = value.strip('"')
 
76
                return value
 
77
        return ""
 
78
 
 
79
    def _http_proxy(self):
 
80
        " internal helper that returns the current http proxy "
 
81
        apt_proxy = self._apt_proxy("http")
 
82
        env_proxy = self._etc_environment_proxy("http")
 
83
        # FIXME: what to do if both proxies are differnet?
 
84
        return env_proxy
 
85
 
 
86
    def _apt_proxy(self, proxy_type):
 
87
        " internal helper that returns the configured apt proxy"
 
88
        apt_pkg.InitConfig()
 
89
        proxy = apt_pkg.Config.Find("Acquire::%s::proxy" % proxy_type)
 
90
        return proxy
 
91
 
 
92
    def _ftp_proxy(self):
 
93
        apt_proxy = self._apt_proxy("ftp")
 
94
        env_proxy = self._etc_environment_proxy("ftp")
 
95
        # FIXME: what to do if both proxies are differnet?
 
96
        return env_proxy
 
97
 
 
98
    def _socks_proxy(self):
 
99
        env_proxy = self._etc_environment_proxy("socks")
 
100
        return env_proxy
 
101
 
 
102
    def _ftp_apt_proxy(self):
 
103
        " internal helper that returns the configured apt proxy"
 
104
        apt_pkg.InitConfig()
 
105
        http_proxy = apt_pkg.Config.Find("Acquire::ftp::proxy")
 
106
        return http_proxy
 
107
 
 
108
    def _https_proxy(self):
 
109
        " internal helper that returns the current https proxy "
 
110
        env_proxy = self._etc_environment_proxy("https")
 
111
        return env_proxy
 
112
 
 
113
    def _verify_proxy(self, proxy_type, proxy):
 
114
        " internal helper, verify that the proxy string is valid "
 
115
        return verify_proxy(proxy_type, proxy)
 
116
 
 
117
    def _verify_no_proxy(self, proxy):
 
118
        " internal helper, verify that the no_proxy string is valid "
 
119
        return verify_no_proxy(proxy)
 
120
 
 
121
    @dbus.service.method(DBUS_INTERFACE_NAME,
 
122
                         in_signature='s', 
 
123
                         out_signature='s',
 
124
                         sender_keyword='sender',
 
125
                         connection_keyword='conn')
 
126
    def get_proxy(self, proxy_type, sender=None, conn=None):
 
127
        """ 
 
128
        Get the current system-wide proxy  for type "proxy_type"
 
129
 
 
130
        This function will look in the apt configuration to 
 
131
        find the current http proxy.
 
132
        """
 
133
        if proxy_type == "http":
 
134
            return self._http_proxy()
 
135
        if proxy_type == "https":
 
136
            return self._https_proxy()
 
137
        elif proxy_type == "ftp": 
 
138
            return self._ftp_proxy()
 
139
        elif proxy_type == "socks": 
 
140
            return self._socks_proxy()
 
141
        raise UnknownProxyTypeError, "proxy_type '%s' is unknown in get_proxy" % proxy_type
 
142
 
 
143
 
 
144
    def _write_apt_proxy(self, proxy_type, new_proxy):
 
145
        " helper that writes the new apt proxy "
 
146
        confdir = apt_pkg.Config.FindDir("Dir::Etc") 
 
147
        if not self._verify_proxy(proxy_type, new_proxy):
 
148
            return False
 
149
        # check for the easy case (no proxy setting in the config)
 
150
        old_proxy = self._apt_proxy(proxy_type)
 
151
        if old_proxy == "":
 
152
            f=open(os.path.join(confdir, "apt.conf"),"a")
 
153
            f.write("Acquire::%s::proxy \"%s\";\n" % (proxy_type, new_proxy))
 
154
            f.close()
 
155
            return True
 
156
        # now the difficult case (search the apt configuration files)
 
157
        # build the list of apt configuration files first
 
158
        apt_conffiles = [os.path.join(confdir,"apt.conf.d",n) for n in 
 
159
                         os.listdir(os.path.join(confdir,"apt.conf.d"))]
 
160
        apt_conffiles.insert(0, os.path.join(confdir,"apt.conf"))
 
161
        # then scan them for the content
 
162
        for f in apt_conffiles:
 
163
            new_content = []
 
164
            found = False
 
165
            for line in open(f):
 
166
                if line.lower().startswith("acquire::%s::proxy" % proxy_type):
 
167
                    found = True
 
168
                    line = "Acquire::%s::proxy \"%s\";\n" % (proxy_type, new_proxy)
 
169
                # FIXME: scan for more complicated forms of the proxy
 
170
                # settings and/or scan for the proxy string and just
 
171
                # replace this
 
172
                new_content.append(line)
 
173
            # if we found/replaced the proxy, write it out now
 
174
            if found:
 
175
                open(f,"w").write("".join(new_content))
 
176
                return True
 
177
        return False
 
178
 
 
179
    def _write_etc_environment_proxy(self, proxy_type, new_proxy):
 
180
        if not self._verify_proxy(proxy_type, new_proxy):
 
181
            return False
 
182
        found=False
 
183
        new_content=[]
 
184
        new_proxy_line = '%s_proxy="%s"\n' % (proxy_type, new_proxy)
 
185
        for line in open("/etc/environment"):
 
186
            if line.startswith("%s_proxy=" % proxy_type):
 
187
                line=new_proxy_line
 
188
                found = True
 
189
            new_content.append(line)
 
190
        if found:
 
191
            open("/etc/environment","w").write("".join(new_content))
 
192
        else:
 
193
            open("/etc/environment","a").write(new_proxy_line)
 
194
        return True
 
195
 
 
196
    def _clear_etc_environment_proxy(self, proxy_type):
 
197
        found=False
 
198
        new_content=[]
 
199
        for line in open("/etc/environment"):
 
200
            if line.startswith("%s_proxy=" % proxy_type):
 
201
                found = True
 
202
            else:
 
203
                new_content.append(line)
 
204
        if found:
 
205
            open("/etc/environment","w").write("".join(new_content))
 
206
        return True
 
207
    
 
208
    def _clear_apt_proxy(self, proxy_type):
 
209
        " helper that clears the apt proxy "
 
210
        confdir = apt_pkg.Config.FindDir("Dir::Etc") 
 
211
        apt_conffiles = [os.path.join(confdir,"apt.conf.d",n) for n in 
 
212
                         os.listdir(os.path.join(confdir,"apt.conf.d"))]
 
213
        apt_conffiles.insert(0, os.path.join(confdir,"apt.conf"))
 
214
        for f in apt_conffiles:
 
215
            new_content = []
 
216
            found = False
 
217
            for line in open(f):
 
218
                if line.lower().startswith("acquire::%s::proxy" % proxy_type):
 
219
                    found = True
 
220
                else:
 
221
                    new_content.append(line)
 
222
            # if we found/replaced the proxy, write it out now
 
223
            if found:
 
224
                open(f,"w").write("".join(new_content))
 
225
        return True
 
226
    
 
227
    @dbus.service.method(DBUS_INTERFACE_NAME,
 
228
                         in_signature='ss', 
 
229
                         out_signature='b',
 
230
                         sender_keyword='sender',
 
231
                         connection_keyword='conn')
 
232
    def set_proxy(self, proxy_type, new_proxy, sender=None, conn=None):
 
233
        """
 
234
        Set a new system-wide proxy that looks like e.g.:
 
235
        http://proxy.host.net:port/
 
236
 
 
237
        This function will set a new apt configuration and
 
238
        modify /etc/environment
 
239
        
 
240
        """
 
241
        if not self._authWithPolicyKit(sender, conn, 
 
242
                                       "com.ubuntu.systemservice.setproxy"):
 
243
            raise PermissionDeniedError, "Permission denied by policy"
 
244
        
 
245
        # check if something supported is set
 
246
        if not proxy_type in self.SUPPORTED_PROXIES:
 
247
            raise UnknownProxyTypeError, "proxy_type '%s' is unknown in set_proxy" % proxy_type
 
248
        
 
249
        # set (or reset)
 
250
        if new_proxy == "" or new_proxy is None:
 
251
            res = self._clear_apt_proxy(proxy_type)
 
252
            res &= self._clear_etc_environment_proxy(proxy_type)
 
253
        else:
 
254
            res = self._write_apt_proxy(proxy_type, new_proxy)
 
255
            res &= self._write_etc_environment_proxy(proxy_type, new_proxy)
 
256
        return res
 
257
 
 
258
 
 
259
    def _clear_etc_environment_no_proxy(self):
 
260
        found=False
 
261
        new_content=[]
 
262
        for line in open("/etc/environment"):
 
263
            if line.startswith("no_proxy="):
 
264
                found = True
 
265
            else:
 
266
                new_content.append(line)
 
267
        if found:
 
268
            open("/etc/environment","w").write("".join(new_content))
 
269
        return True
 
270
 
 
271
    def _write_etc_environment_no_proxy(self, new_proxy):
 
272
        if not self._verify_no_proxy(new_proxy):
 
273
            return False
 
274
        found=False
 
275
        new_content=[]
 
276
        new_proxy_line = 'no_proxy="%s"\n' % new_proxy
 
277
        for line in open("/etc/environment"):
 
278
            if line.startswith("no_proxy="):
 
279
                line=new_proxy_line
 
280
                found = True
 
281
            new_content.append(line)
 
282
        if found:
 
283
            open("/etc/environment","w").write("".join(new_content))
 
284
        else:
 
285
            open("/etc/environment","a").write(new_proxy_line)
 
286
        return True
 
287
 
 
288
    
 
289
 
 
290
    @dbus.service.method(DBUS_INTERFACE_NAME,
 
291
                         in_signature='s', 
 
292
                         out_signature='b',
 
293
                         sender_keyword='sender',
 
294
                         connection_keyword='conn')
 
295
    def set_no_proxy(self, new_no_proxy, sender=None, conn=None):
 
296
        """
 
297
        Set a new system-wide no_proxy list that looks like e.g.:
 
298
        localhost,foo.com
 
299
 
 
300
        This function will modify /etc/environment
 
301
        
 
302
        """
 
303
        if not self._authWithPolicyKit(sender, conn, 
 
304
                                       "com.ubuntu.systemservice.setnoproxy"):
 
305
            raise PermissionDeniedError, "Permission denied by policy"
 
306
        
 
307
        # set (or reset)
 
308
        if new_no_proxy == "" or new_no_proxy is None:
 
309
            res = self._clear_no_proxy()
 
310
        else:
 
311
            res = self._write_etc_environment_no_proxy(new_no_proxy)
 
312
        return res
 
313
 
 
314
if __name__ == "__main__":
 
315
    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) 
 
316
    server = ProxyBackend()
 
317
    gobject.MainLoop().run()
 
318