/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to mandos

  • Committer: Teddy Hogeborn
  • Date: 2014-08-06 21:45:09 UTC
  • mfrom: (237.4.53 release)
  • Revision ID: teddy@recompile.se-20140806214509-d6sprf3gnmahcfax
Merge from release branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
88
88
    except ImportError:
89
89
        SO_BINDTODEVICE = None
90
90
 
91
 
if sys.version_info.major == 2:
92
 
    str = unicode
93
 
 
94
 
version = "1.6.9"
 
91
version = "1.6.8"
95
92
stored_state_file = "clients.pickle"
96
93
 
97
94
logger = logging.getLogger()
107
104
        SIOCGIFINDEX = 0x8933  # From /usr/include/linux/sockios.h
108
105
        with contextlib.closing(socket.socket()) as s:
109
106
            ifreq = fcntl.ioctl(s, SIOCGIFINDEX,
110
 
                                struct.pack(b"16s16x", interface))
111
 
        interface_index = struct.unpack("I", ifreq[16:20])[0]
 
107
                                struct.pack(str("16s16x"),
 
108
                                            interface))
 
109
        interface_index = struct.unpack(str("I"),
 
110
                                        ifreq[16:20])[0]
112
111
        return interface_index
113
112
 
114
113
 
119
118
    syslogger = (logging.handlers.SysLogHandler
120
119
                 (facility =
121
120
                  logging.handlers.SysLogHandler.LOG_DAEMON,
122
 
                  address = "/dev/log"))
 
121
                  address = str("/dev/log")))
123
122
    syslogger.setFormatter(logging.Formatter
124
123
                           ('Mandos [%(process)d]: %(levelname)s:'
125
124
                            ' %(message)s'))
225
224
class AvahiError(Exception):
226
225
    def __init__(self, value, *args, **kwargs):
227
226
        self.value = value
228
 
        return super(AvahiError, self).__init__(value, *args,
229
 
                                                **kwargs)
 
227
        super(AvahiError, self).__init__(value, *args, **kwargs)
 
228
    def __unicode__(self):
 
229
        return unicode(repr(self.value))
230
230
 
231
231
class AvahiServiceError(AvahiError):
232
232
    pass
275
275
        self.bus = bus
276
276
        self.entry_group_state_changed_match = None
277
277
    
278
 
    def rename(self, remove=True):
 
278
    def rename(self):
279
279
        """Derived from the Avahi example code"""
280
280
        if self.rename_count >= self.max_renames:
281
281
            logger.critical("No suitable Zeroconf service name found"
282
282
                            " after %i retries, exiting.",
283
283
                            self.rename_count)
284
284
            raise AvahiServiceError("Too many renames")
285
 
        self.name = str(self.server
286
 
                        .GetAlternativeServiceName(self.name))
287
 
        self.rename_count += 1
 
285
        self.name = unicode(self.server
 
286
                            .GetAlternativeServiceName(self.name))
288
287
        logger.info("Changing Zeroconf service name to %r ...",
289
288
                    self.name)
290
 
        if remove:
291
 
            self.remove()
 
289
        self.remove()
292
290
        try:
293
291
            self.add()
294
292
        except dbus.exceptions.DBusException as error:
295
 
            if (error.get_dbus_name()
296
 
                == "org.freedesktop.Avahi.CollisionError"):
297
 
                logger.info("Local Zeroconf service name collision.")
298
 
                return self.rename(remove=False)
299
 
            else:
300
 
                logger.critical("D-Bus Exception", exc_info=error)
301
 
                self.cleanup()
302
 
                os._exit(1)
 
293
            logger.critical("D-Bus Exception", exc_info=error)
 
294
            self.cleanup()
 
295
            os._exit(1)
 
296
        self.rename_count += 1
303
297
    
304
298
    def remove(self):
305
299
        """Derived from the Avahi example code"""
343
337
            self.rename()
344
338
        elif state == avahi.ENTRY_GROUP_FAILURE:
345
339
            logger.critical("Avahi: Error in group state changed %s",
346
 
                            str(error))
 
340
                            unicode(error))
347
341
            raise AvahiGroupError("State changed: {!s}"
348
342
                                  .format(error))
349
343
    
397
391
 
398
392
 
399
393
class AvahiServiceToSyslog(AvahiService):
400
 
    def rename(self, *args, **kwargs):
 
394
    def rename(self):
401
395
        """Add the new name to the syslog messages"""
402
 
        ret = AvahiService.rename(self, *args, **kwargs)
 
396
        ret = AvahiService.rename(self)
403
397
        syslogger.setFormatter(logging.Formatter
404
398
                               ('Mandos ({}) [%(process)d]:'
405
399
                                ' %(levelname)s: %(message)s'
694
688
        if self.checker is None:
695
689
            # Escape attributes for the shell
696
690
            escaped_attrs = { attr:
697
 
                                  re.escape(str(getattr(self, attr)))
 
691
                                  re.escape(unicode(getattr(self,
 
692
                                                            attr)))
698
693
                              for attr in self.runtime_expansions }
699
694
            try:
700
695
                command = self.checker_command % escaped_attrs
819
814
    """Decorator to annotate D-Bus methods, signals or properties
820
815
    Usage:
821
816
    
822
 
    @dbus_annotations({"org.freedesktop.DBus.Deprecated": "true",
823
 
                       "org.freedesktop.DBus.Property."
824
 
                       "EmitsChangedSignal": "false"})
825
817
    @dbus_service_property("org.example.Interface", signature="b",
826
818
                           access="r")
 
819
    @dbus_annotations({{"org.freedesktop.DBus.Deprecated": "true",
 
820
                        "org.freedesktop.DBus.Property."
 
821
                        "EmitsChangedSignal": "false"})
827
822
    def Property_dbus_property(self):
828
823
        return dbus.Boolean(False)
829
824
    """
836
831
class DBusPropertyException(dbus.exceptions.DBusException):
837
832
    """A base class for D-Bus property-related exceptions
838
833
    """
839
 
    pass
 
834
    def __unicode__(self):
 
835
        return unicode(str(self))
 
836
 
840
837
 
841
838
class DBusPropertyAccessException(DBusPropertyException):
842
839
    """A property's access permissions disallows an operation.
952
949
                                           value.variant_level+1)
953
950
        return dbus.Dictionary(properties, signature="sv")
954
951
    
955
 
    @dbus.service.signal(dbus.PROPERTIES_IFACE, signature="sa{sv}as")
956
 
    def PropertiesChanged(self, interface_name, changed_properties,
957
 
                          invalidated_properties):
958
 
        """Standard D-Bus PropertiesChanged() signal, see D-Bus
959
 
        standard.
960
 
        """
961
 
        pass
962
 
    
963
952
    @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
964
953
                         out_signature="s",
965
954
                         path_keyword='object_path',
1232
1221
    runtime_expansions = (Client.runtime_expansions
1233
1222
                          + ("dbus_object_path",))
1234
1223
    
1235
 
    _interface = "se.recompile.Mandos.Client"
1236
 
    
1237
1224
    # dbus.service.Object doesn't use super(), so we can't either.
1238
1225
    
1239
1226
    def __init__(self, bus = None, *args, **kwargs):
1241
1228
        Client.__init__(self, *args, **kwargs)
1242
1229
        # Only now, when this client is initialized, can it show up on
1243
1230
        # the D-Bus
1244
 
        client_object_name = str(self.name).translate(
 
1231
        client_object_name = unicode(self.name).translate(
1245
1232
            {ord("."): ord("_"),
1246
1233
             ord("-"): ord("_")})
1247
1234
        self.dbus_object_path = (dbus.ObjectPath
1251
1238
    
1252
1239
    def notifychangeproperty(transform_func,
1253
1240
                             dbus_name, type_func=lambda x: x,
1254
 
                             variant_level=1, invalidate_only=False,
1255
 
                             _interface=_interface):
 
1241
                             variant_level=1):
1256
1242
        """ Modify a variable so that it's a property which announces
1257
1243
        its changes to DBus.
1258
1244
        
1269
1255
                if (not hasattr(self, attrname) or
1270
1256
                    type_func(getattr(self, attrname, None))
1271
1257
                    != type_func(value)):
1272
 
                    if invalidate_only:
1273
 
                        self.PropertiesChanged(_interface,
1274
 
                                               dbus.Dictionary(),
1275
 
                                               dbus.Array
1276
 
                                               ((dbus_name,)))
1277
 
                    else:
1278
 
                        dbus_value = transform_func(type_func(value),
1279
 
                                                    variant_level
1280
 
                                                    =variant_level)
1281
 
                        self.PropertyChanged(dbus.String(dbus_name),
1282
 
                                             dbus_value)
1283
 
                        self.PropertiesChanged(_interface,
1284
 
                                               dbus.Dictionary({
1285
 
                                    dbus.String(dbus_name):
1286
 
                                        dbus_value }), dbus.Array())
 
1258
                    dbus_value = transform_func(type_func(value),
 
1259
                                                variant_level
 
1260
                                                =variant_level)
 
1261
                    self.PropertyChanged(dbus.String(dbus_name),
 
1262
                                         dbus_value)
1287
1263
            setattr(self, attrname, value)
1288
1264
        
1289
1265
        return property(lambda self: getattr(self, attrname), setter)
1327
1303
                                    lambda td: td.total_seconds()
1328
1304
                                    * 1000)
1329
1305
    checker_command = notifychangeproperty(dbus.String, "Checker")
1330
 
    secret = notifychangeproperty(dbus.ByteArray, "Secret",
1331
 
                                  invalidate_only=True)
1332
1306
    
1333
1307
    del notifychangeproperty
1334
1308
    
1381
1355
        self.send_changedstate()
1382
1356
    
1383
1357
    ## D-Bus methods, signals & properties
 
1358
    _interface = "se.recompile.Mandos.Client"
1384
1359
    
1385
1360
    ## Interfaces
1386
1361
    
 
1362
    @dbus_interface_annotations(_interface)
 
1363
    def _foo(self):
 
1364
        return { "org.freedesktop.DBus.Property.EmitsChangedSignal":
 
1365
                     "false"}
 
1366
    
1387
1367
    ## Signals
1388
1368
    
1389
1369
    # CheckerCompleted - signal
1399
1379
        pass
1400
1380
    
1401
1381
    # PropertyChanged - signal
1402
 
    @dbus_annotations({"org.freedesktop.DBus.Deprecated": "true"})
1403
1382
    @dbus.service.signal(_interface, signature="sv")
1404
1383
    def PropertyChanged(self, property, value):
1405
1384
        "D-Bus signal"
1510
1489
    def Host_dbus_property(self, value=None):
1511
1490
        if value is None:       # get
1512
1491
            return dbus.String(self.host)
1513
 
        self.host = str(value)
 
1492
        self.host = unicode(value)
1514
1493
    
1515
1494
    # Created - property
1516
1495
    @dbus_service_property(_interface, signature="s", access="read")
1614
1593
    def Checker_dbus_property(self, value=None):
1615
1594
        if value is None:       # get
1616
1595
            return dbus.String(self.checker_command)
1617
 
        self.checker_command = str(value)
 
1596
        self.checker_command = unicode(value)
1618
1597
    
1619
1598
    # CheckerRunning - property
1620
1599
    @dbus_service_property(_interface, signature="b",
1636
1615
    @dbus_service_property(_interface, signature="ay",
1637
1616
                           access="write", byte_arrays=True)
1638
1617
    def Secret_dbus_property(self, value):
1639
 
        self.secret = bytes(value)
 
1618
        self.secret = str(value)
1640
1619
    
1641
1620
    del _interface
1642
1621
 
1676
1655
    def handle(self):
1677
1656
        with contextlib.closing(self.server.child_pipe) as child_pipe:
1678
1657
            logger.info("TCP connection from: %s",
1679
 
                        str(self.client_address))
 
1658
                        unicode(self.client_address))
1680
1659
            logger.debug("Pipe FD: %d",
1681
1660
                         self.server.child_pipe.fileno())
1682
1661
            
1981
1960
                try:
1982
1961
                    self.socket.setsockopt(socket.SOL_SOCKET,
1983
1962
                                           SO_BINDTODEVICE,
1984
 
                                           (self.interface + "\0")
1985
 
                                           .encode("utf-8"))
 
1963
                                           str(self.interface + '\0'))
1986
1964
                except socket.error as error:
1987
1965
                    if error.errno == errno.EPERM:
1988
1966
                        logger.error("No permission to bind to"
2248
2226
    timevalue = datetime.timedelta(0)
2249
2227
    for s in interval.split():
2250
2228
        try:
2251
 
            suffix = s[-1]
 
2229
            suffix = unicode(s[-1])
2252
2230
            value = int(s[:-1])
2253
2231
            if suffix == "d":
2254
2232
                delta = datetime.timedelta(value)
2405
2383
    del options
2406
2384
    # Force all strings to be unicode
2407
2385
    for option in server_settings.keys():
2408
 
        if isinstance(server_settings[option], bytes):
2409
 
            server_settings[option] = (server_settings[option]
2410
 
                                       .decode("utf-8"))
 
2386
        if type(server_settings[option]) is str:
 
2387
            server_settings[option] = unicode(server_settings[option])
2411
2388
    # Force all boolean options to be boolean
2412
2389
    for option in ("debug", "use_dbus", "use_ipv6", "restore",
2413
2390
                   "foreground", "zeroconf"):
2556
2533
                                       protocol = protocol, bus = bus)
2557
2534
        if server_settings["interface"]:
2558
2535
            service.interface = (if_nametoindex
2559
 
                                 (server_settings["interface"]
2560
 
                                  .encode("utf-8")))
 
2536
                                 (str(server_settings["interface"])))
2561
2537
    
2562
2538
    global multiprocessing_manager
2563
2539
    multiprocessing_manager = multiprocessing.Manager()
2681
2657
            try:
2682
2658
                with pidfile:
2683
2659
                    pid = os.getpid()
2684
 
                    pidfile.write("{}\n".format(pid).encode("utf-8"))
 
2660
                    pidfile.write(str(pid) + "\n".encode("utf-8"))
2685
2661
            except IOError:
2686
2662
                logger.error("Could not write to file %r with PID %d",
2687
2663
                             pidfilename, pid)
2733
2709
            def GetAllClientsWithProperties(self):
2734
2710
                "D-Bus method"
2735
2711
                return dbus.Dictionary(
2736
 
                    { c.dbus_object_path: c.GetAll("")
2737
 
                      for c in tcp_server.clients.itervalues() },
 
2712
                    ((c.dbus_object_path, c.GetAll(""))
 
2713
                     for c in tcp_server.clients.itervalues()),
2738
2714
                    signature="oa{sv}")
2739
2715
            
2740
2716
            @dbus.service.method(_interface, in_signature="o")