/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 at recompile
  • Date: 2012-01-01 17:38:33 UTC
  • Revision ID: teddy@recompile.se-20120101173833-ai39bif1w0ftuyyh
* Makefile (install-server): Add intro(8mandos) man page.
* network-hooks.d/bridge: Add copyright info and year.
* network-hooks.d/openvpn: - '' -
* network-hooks.d/wireless: - '' -

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
# "AvahiService" class, and some lines in "main".
12
12
13
13
# Everything else is
14
 
# Copyright © 2008-2011 Teddy Hogeborn
15
 
# Copyright © 2008-2011 Björn Påhlsson
 
14
# Copyright © 2008-2012 Teddy Hogeborn
 
15
# Copyright © 2008-2012 Björn Påhlsson
16
16
17
17
# This program is free software: you can redistribute it and/or modify
18
18
# it under the terms of the GNU General Public License as published by
85
85
    except ImportError:
86
86
        SO_BINDTODEVICE = None
87
87
 
88
 
version = "1.4.1"
 
88
version = "1.5.0"
89
89
stored_state_file = "clients.pickle"
90
90
 
91
91
logger = logging.getLogger()
110
110
        return interface_index
111
111
 
112
112
 
113
 
def initlogger(level=logging.WARNING):
 
113
def initlogger(debug, level=logging.WARNING):
114
114
    """init logger and add loglevel"""
115
115
    
116
116
    syslogger.setFormatter(logging.Formatter
118
118
                            ' %(message)s'))
119
119
    logger.addHandler(syslogger)
120
120
    
121
 
    console = logging.StreamHandler()
122
 
    console.setFormatter(logging.Formatter('%(asctime)s %(name)s'
123
 
                                           ' [%(process)d]:'
124
 
                                           ' %(levelname)s:'
125
 
                                           ' %(message)s'))
126
 
    logger.addHandler(console)
 
121
    if debug:
 
122
        console = logging.StreamHandler()
 
123
        console.setFormatter(logging.Formatter('%(asctime)s %(name)s'
 
124
                                               ' [%(process)d]:'
 
125
                                               ' %(levelname)s:'
 
126
                                               ' %(message)s'))
 
127
        logger.addHandler(console)
127
128
    logger.setLevel(level)
128
129
 
129
130
 
141
142
        self.gnupg.options.meta_interactive = False
142
143
        self.gnupg.options.homedir = self.tempdir
143
144
        self.gnupg.options.extra_args.extend(['--force-mdc',
144
 
                                              '--quiet'])
 
145
                                              '--quiet',
 
146
                                              '--no-use-agent'])
145
147
    
146
148
    def __enter__(self):
147
149
        return self
458
460
 
459
461
    @staticmethod
460
462
    def config_parser(config):
461
 
        """ Construct a new dict of client settings of this form:
 
463
        """Construct a new dict of client settings of this form:
462
464
        { client_name: {setting_name: value, ...}, ...}
463
 
        with exceptions for any special settings as defined above"""
 
465
        with exceptions for any special settings as defined above.
 
466
        NOTE: Must be a pure function. Must return the same result
 
467
        value given the same arguments.
 
468
        """
464
469
        settings = {}
465
470
        for client_name in config.sections():
466
471
            section = dict(config.items(client_name))
470
475
            # Reformat values from string types to Python types
471
476
            client["approved_by_default"] = config.getboolean(
472
477
                client_name, "approved_by_default")
473
 
            client["enabled"] = config.getboolean(client_name, "enabled")
 
478
            client["enabled"] = config.getboolean(client_name,
 
479
                                                  "enabled")
474
480
            
475
481
            client["fingerprint"] = (section["fingerprint"].upper()
476
482
                                     .replace(" ", ""))
496
502
            client["last_approval_request"] = None
497
503
            client["last_checked_ok"] = None
498
504
            client["last_checker_status"] = None
499
 
            if client["enabled"]:
500
 
                client["last_enabled"] = datetime.datetime.utcnow()
501
 
                client["expires"] = (datetime.datetime.utcnow()
502
 
                                     + client["timeout"])
503
 
            else:
504
 
                client["last_enabled"] = None
505
 
                client["expires"] = None
506
 
 
 
505
        
507
506
        return settings
508
507
        
509
508
        
516
515
        for setting, value in settings.iteritems():
517
516
            setattr(self, setting, value)
518
517
        
 
518
        if self.enabled:
 
519
            if not hasattr(self, "last_enabled"):
 
520
                self.last_enabled = datetime.datetime.utcnow()
 
521
            if not hasattr(self, "expires"):
 
522
                self.expires = (datetime.datetime.utcnow()
 
523
                                + self.timeout)
 
524
        else:
 
525
            self.last_enabled = None
 
526
            self.expires = None
 
527
       
519
528
        logger.debug("Creating client %r", self.name)
520
529
        # Uppercase and remove spaces from fingerprint for later
521
530
        # comparison purposes with return value from the fingerprint()
522
531
        # function
523
532
        logger.debug("  Fingerprint: %s", self.fingerprint)
524
 
        self.created = settings.get("created", datetime.datetime.utcnow())
 
533
        self.created = settings.get("created",
 
534
                                    datetime.datetime.utcnow())
525
535
 
526
536
        # attributes specific for this server instance
527
537
        self.checker = None
840
850
            # signatures other than "ay".
841
851
            if prop._dbus_signature != "ay":
842
852
                raise ValueError
843
 
            value = dbus.ByteArray(''.join(unichr(byte)
844
 
                                           for byte in value))
 
853
            value = dbus.ByteArray(b''.join(chr(byte)
 
854
                                            for byte in value))
845
855
        prop(value)
846
856
    
847
857
    @dbus.service.method(dbus.PROPERTIES_IFACE, in_signature="s",
1357
1367
        if value is None:       # get
1358
1368
            return dbus.UInt64(self.timeout_milliseconds())
1359
1369
        self.timeout = datetime.timedelta(0, 0, 0, value)
1360
 
        if getattr(self, "disable_initiator_tag", None) is None:
1361
 
            return
1362
1370
        # Reschedule timeout
1363
 
        gobject.source_remove(self.disable_initiator_tag)
1364
 
        self.disable_initiator_tag = None
1365
 
        self.expires = None
1366
 
        time_to_die = timedelta_to_milliseconds((self
1367
 
                                                 .last_checked_ok
1368
 
                                                 + self.timeout)
1369
 
                                                - datetime.datetime
1370
 
                                                .utcnow())
1371
 
        if time_to_die <= 0:
1372
 
            # The timeout has passed
1373
 
            self.disable()
1374
 
        else:
1375
 
            self.expires = (datetime.datetime.utcnow()
1376
 
                            + datetime.timedelta(milliseconds =
1377
 
                                                 time_to_die))
1378
 
            self.disable_initiator_tag = (gobject.timeout_add
1379
 
                                          (time_to_die, self.disable))
 
1371
        if self.enabled:
 
1372
            now = datetime.datetime.utcnow()
 
1373
            time_to_die = timedelta_to_milliseconds(
 
1374
                (self.last_checked_ok + self.timeout) - now)
 
1375
            if time_to_die <= 0:
 
1376
                # The timeout has passed
 
1377
                self.disable()
 
1378
            else:
 
1379
                self.expires = (now +
 
1380
                                datetime.timedelta(milliseconds =
 
1381
                                                   time_to_die))
 
1382
                if (getattr(self, "disable_initiator_tag", None)
 
1383
                    is None):
 
1384
                    return
 
1385
                gobject.source_remove(self.disable_initiator_tag)
 
1386
                self.disable_initiator_tag = (gobject.timeout_add
 
1387
                                              (time_to_die,
 
1388
                                               self.disable))
1380
1389
    
1381
1390
    # ExtendedTimeout - property
1382
1391
    @dbus_service_property(_interface, signature="t",
2078
2087
                                     stored_state_file)
2079
2088
    
2080
2089
    if debug:
2081
 
        initlogger(logging.DEBUG)
 
2090
        initlogger(debug, logging.DEBUG)
2082
2091
    else:
2083
2092
        if not debuglevel:
2084
 
            initlogger()
 
2093
            initlogger(debug)
2085
2094
        else:
2086
2095
            level = getattr(logging, debuglevel.upper())
2087
 
            initlogger(level)
 
2096
            initlogger(debug, level)
2088
2097
    
2089
2098
    if server_settings["servicename"] != "Mandos":
2090
2099
        syslogger.setFormatter(logging.Formatter
2093
2102
                                % server_settings["servicename"]))
2094
2103
    
2095
2104
    # Parse config file with clients
2096
 
    client_config = configparser.SafeConfigParser(Client.client_defaults)
 
2105
    client_config = configparser.SafeConfigParser(Client
 
2106
                                                  .client_defaults)
2097
2107
    client_config.read(os.path.join(server_settings["configdir"],
2098
2108
                                    "clients.conf"))
2099
2109
    
2156
2166
        os.dup2(null, sys.stdin.fileno())
2157
2167
        if null > 2:
2158
2168
            os.close(null)
2159
 
    else:
2160
 
        # No console logging
2161
 
        logger.removeHandler(console)
2162
2169
    
2163
2170
    # Need to fork before connecting to D-Bus
2164
2171
    if not debug:
2165
2172
        # Close all input and output, do double fork, etc.
2166
2173
        daemon()
2167
2174
    
 
2175
    gobject.threads_init()
 
2176
    
2168
2177
    global main_loop
2169
2178
    # From the Avahi example code
2170
2179
    DBusGMainLoop(set_as_default=True )
2216
2225
                           .format(e))
2217
2226
            if e.errno != errno.ENOENT:
2218
2227
                raise
 
2228
        except EOFError as e:
 
2229
            logger.warning("Could not load persistent state: "
 
2230
                           "EOFError: {0}".format(e))
2219
2231
    
2220
2232
    with PGPEngine() as pgp:
2221
2233
        for client_name, client in clients_data.iteritems():
2259
2271
                        client["expires"] = (datetime.datetime
2260
2272
                                             .utcnow()
2261
2273
                                             + client["timeout"])
2262
 
                    
 
2274
                        logger.debug("Last checker succeeded,"
 
2275
                                     " keeping {0} enabled"
 
2276
                                     .format(client["name"]))
2263
2277
            try:
2264
2278
                client["secret"] = (
2265
2279
                    pgp.decrypt(client["encrypted_secret"],
2274
2288
 
2275
2289
    
2276
2290
    # Add/remove clients based on new changes made to config
2277
 
    for client_name in set(old_client_settings) - set(client_settings):
 
2291
    for client_name in (set(old_client_settings)
 
2292
                        - set(client_settings)):
2278
2293
        del clients_data[client_name]
2279
 
    for client_name in set(client_settings) - set(old_client_settings):
 
2294
    for client_name in (set(client_settings)
 
2295
                        - set(old_client_settings)):
2280
2296
        clients_data[client_name] = client_settings[client_name]
2281
2297
 
2282
2298
    # Create clients all clients
2400
2416
                del client_settings[client.name]["secret"]
2401
2417
        
2402
2418
        try:
2403
 
            with os.fdopen(os.open(stored_state_path,
2404
 
                                   os.O_CREAT|os.O_WRONLY|os.O_TRUNC,
2405
 
                                   0600), "wb") as stored_state:
 
2419
            tempfd, tempname = tempfile.mkstemp(suffix=".pickle",
 
2420
                                                prefix="clients-",
 
2421
                                                dir=os.path.dirname
 
2422
                                                (stored_state_path))
 
2423
            with os.fdopen(tempfd, "wb") as stored_state:
2406
2424
                pickle.dump((clients, client_settings), stored_state)
 
2425
            os.rename(tempname, stored_state_path)
2407
2426
        except (IOError, OSError) as e:
2408
2427
            logger.warning("Could not save persistent state: {0}"
2409
2428
                           .format(e))
2410
 
            if e.errno not in (errno.ENOENT, errno.EACCES):
2411
 
                raise
 
2429
            if not debug:
 
2430
                try:
 
2431
                    os.remove(tempname)
 
2432
                except NameError:
 
2433
                    pass
 
2434
            if e.errno not in set((errno.ENOENT, errno.EACCES,
 
2435
                                   errno.EEXIST)):
 
2436
                raise e
2412
2437
        
2413
2438
        # Delete all clients, and settings from config
2414
2439
        while tcp_server.clients: