/mandos/release

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

« back to all changes in this revision

Viewing changes to mandos

Reorder TODO entries

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
411
412
    interval:   datetime.timedelta(); How often to start a new checker
412
413
    last_approval_request: datetime.datetime(); (UTC) or None
413
414
    last_checked_ok: datetime.datetime(); (UTC) or None
414
 
 
415
415
    last_checker_status: integer between 0 and 255 reflecting exit
416
416
                         status of last checker. -1 reflects crashed
417
417
                         checker, or None.
467
467
            section = dict(config.items(client_name))
468
468
            client = settings[client_name] = {}
469
469
            
470
 
            # Default copying each value from config to new dict
471
 
            for setting, value in section.iteritems():
472
 
                client[setting] = value
473
 
            
 
470
            client["host"] = section["host"]
474
471
            # Reformat values from string types to Python types
475
472
            client["approved_by_default"] = config.getboolean(
476
473
                client_name, "approved_by_default")
496
493
                section["approval_delay"])
497
494
            client["approval_duration"] = string_to_delta(
498
495
                section["approval_duration"])
 
496
            client["checker_command"] = section["checker"]
 
497
            client["last_approval_request"] = None
 
498
            client["last_checked_ok"] = None
 
499
            client["last_checker_status"] = None
 
500
            if client["enabled"]:
 
501
                client["last_enabled"] = datetime.datetime.utcnow()
 
502
                client["expires"] = (datetime.datetime.utcnow()
 
503
                                     + client["timeout"])
 
504
            else:
 
505
                client["last_enabled"] = None
 
506
                client["expires"] = None
499
507
 
500
508
        return settings
501
509
        
502
510
        
503
 
    def __init__(self, config, name = None):
 
511
    def __init__(self, settings, name = None):
504
512
        """Note: the 'checker' key in 'config' sets the
505
513
        'checker_command' attribute and *not* the 'checker'
506
514
        attribute."""
507
515
        self.name = name
 
516
        # adding all client settings
 
517
        for setting, value in settings.iteritems():
 
518
            setattr(self, setting, value)
 
519
        
508
520
        logger.debug("Creating client %r", self.name)
509
521
        # Uppercase and remove spaces from fingerprint for later
510
522
        # comparison purposes with return value from the fingerprint()
511
523
        # function
512
 
        self.fingerprint = config["fingerprint"]
513
524
        logger.debug("  Fingerprint: %s", self.fingerprint)
514
 
        self.secret = config["secret"]
515
 
        self.host = config["host"]
516
 
        self.created = datetime.datetime.utcnow()
517
 
        self.enabled = config["enabled"]
518
 
        self.last_approval_request = None
519
 
        if self.enabled:
520
 
            self.last_enabled = datetime.datetime.utcnow()
521
 
        else:
522
 
            self.last_enabled = None
523
 
        self.last_checked_ok = None
524
 
        self.last_checker_status = None
525
 
        self.timeout = config["timeout"]
526
 
        self.extended_timeout = config["extended_timeout"]
527
 
        self.interval = config["interval"]
 
525
        self.created = settings.get("created", datetime.datetime.utcnow())
 
526
 
 
527
        # attributes specific for this server instance
528
528
        self.checker = None
529
529
        self.checker_initiator_tag = None
530
530
        self.disable_initiator_tag = None
531
 
        if self.enabled:
532
 
            self.expires = datetime.datetime.utcnow() + self.timeout
533
 
        else:
534
 
            self.expires = None
535
531
        self.checker_callback_tag = None
536
 
        self.checker_command = config["checker"]
537
532
        self.current_checker_command = None
538
533
        self.approved = None
539
 
        self.approved_by_default = config["approved_by_default"]
540
534
        self.approvals_pending = 0
541
 
        self.approval_delay = config["approval_delay"]
542
 
        self.approval_duration = config["approval_duration"]
543
535
        self.changedstate = (multiprocessing_manager
544
536
                             .Condition(multiprocessing_manager
545
537
                                        .Lock()))
1048
1040
    def __init__(self, bus = None, *args, **kwargs):
1049
1041
        self.bus = bus
1050
1042
        Client.__init__(self, *args, **kwargs)
 
1043
        self._approvals_pending = 0
1051
1044
        
1052
1045
        self._approvals_pending = 0
1053
1046
        # Only now, when this client is initialized, can it show up on
2086
2079
                                     stored_state_file)
2087
2080
    
2088
2081
    if debug:
2089
 
        initlogger(logging.DEBUG)
 
2082
        initlogger(debug, logging.DEBUG)
2090
2083
    else:
2091
2084
        if not debuglevel:
2092
 
            initlogger()
 
2085
            initlogger(debug)
2093
2086
        else:
2094
2087
            level = getattr(logging, debuglevel.upper())
2095
 
            initlogger(level)
 
2088
            initlogger(debug, level)
2096
2089
    
2097
2090
    if server_settings["servicename"] != "Mandos":
2098
2091
        syslogger.setFormatter(logging.Formatter
2164
2157
        os.dup2(null, sys.stdin.fileno())
2165
2158
        if null > 2:
2166
2159
            os.close(null)
2167
 
    else:
2168
 
        # No console logging
2169
 
        logger.removeHandler(console)
2170
2160
    
2171
2161
    # Need to fork before connecting to D-Bus
2172
2162
    if not debug:
2173
2163
        # Close all input and output, do double fork, etc.
2174
2164
        daemon()
2175
2165
    
 
2166
    gobject.threads_init()
 
2167
    
2176
2168
    global main_loop
2177
2169
    # From the Avahi example code
2178
2170
    DBusGMainLoop(set_as_default=True )
2210
2202
    
2211
2203
    client_settings = Client.config_parser(client_config)
2212
2204
    old_client_settings = {}
2213
 
    clients_data = []
 
2205
    clients_data = {}
2214
2206
    
2215
2207
    # Get client data and settings from last running state.
2216
2208
    if server_settings["restore"]:
2224
2216
                           .format(e))
2225
2217
            if e.errno != errno.ENOENT:
2226
2218
                raise
 
2219
        except EOFError as e:
 
2220
            logger.warning("Could not load persistent state: "
 
2221
                           "EOFError: {0}".format(e))
2227
2222
    
2228
2223
    with PGPEngine() as pgp:
2229
 
        for client in clients_data:
2230
 
            client_name = client["name"]
2231
 
            
 
2224
        for client_name, client in clients_data.iteritems():
2232
2225
            # Decide which value to use after restoring saved state.
2233
2226
            # We have three different values: Old config file,
2234
2227
            # new config file, and saved state.
2269
2262
                        client["expires"] = (datetime.datetime
2270
2263
                                             .utcnow()
2271
2264
                                             + client["timeout"])
2272
 
            
2273
 
            client["changedstate"] = (multiprocessing_manager
2274
 
                                      .Condition
2275
 
                                      (multiprocessing_manager
2276
 
                                       .Lock()))
2277
 
            client["checker"] = None
2278
 
            if use_dbus:
2279
 
                new_client = (ClientDBusTransitional.__new__
2280
 
                              (ClientDBusTransitional))
2281
 
                tcp_server.clients[client_name] = new_client
2282
 
                new_client.bus = bus
2283
 
                for name, value in client.iteritems():
2284
 
                    setattr(new_client, name, value)
2285
 
                client_object_name = unicode(client_name).translate(
2286
 
                    {ord("."): ord("_"),
2287
 
                     ord("-"): ord("_")})
2288
 
                new_client.dbus_object_path = (dbus.ObjectPath
2289
 
                                               ("/clients/"
2290
 
                                                + client_object_name))
2291
 
                DBusObjectWithProperties.__init__(new_client,
2292
 
                                                  new_client.bus,
2293
 
                                                  new_client
2294
 
                                                  .dbus_object_path)
2295
 
            else:
2296
 
                tcp_server.clients[client_name] = (Client.__new__
2297
 
                                                   (Client))
2298
 
                for name, value in client.iteritems():
2299
 
                    setattr(tcp_server.clients[client_name],
2300
 
                            name, value)
2301
 
            
 
2265
                    
2302
2266
            try:
2303
 
                tcp_server.clients[client_name].secret = (
2304
 
                    pgp.decrypt(tcp_server.clients[client_name]
2305
 
                                .encrypted_secret,
 
2267
                client["secret"] = (
 
2268
                    pgp.decrypt(client["encrypted_secret"],
2306
2269
                                client_settings[client_name]
2307
2270
                                ["secret"]))
2308
2271
            except PGPError:
2309
2272
                # If decryption fails, we use secret from new settings
2310
2273
                logger.debug("Failed to decrypt {0} old secret"
2311
2274
                             .format(client_name))
2312
 
                tcp_server.clients[client_name].secret = (
 
2275
                client["secret"] = (
2313
2276
                    client_settings[client_name]["secret"])
 
2277
 
2314
2278
    
2315
 
    # Create/remove clients based on new changes made to config
2316
 
    for clientname in set(old_client_settings) - set(client_settings):
2317
 
        del tcp_server.clients[clientname]
2318
 
    for clientname in set(client_settings) - set(old_client_settings):
2319
 
        tcp_server.clients[clientname] = (client_class(name = clientname,
2320
 
                                                       config =
2321
 
                                                       client_settings
2322
 
                                                       [clientname]))
 
2279
    # Add/remove clients based on new changes made to config
 
2280
    for client_name in set(old_client_settings) - set(client_settings):
 
2281
        del clients_data[client_name]
 
2282
    for client_name in set(client_settings) - set(old_client_settings):
 
2283
        clients_data[client_name] = client_settings[client_name]
 
2284
 
 
2285
    # Create clients all clients
 
2286
    for client_name, client in clients_data.iteritems():
 
2287
        tcp_server.clients[client_name] = client_class(
 
2288
            name = client_name, settings = client)
2323
2289
    
2324
2290
    if not tcp_server.clients:
2325
2291
        logger.warning("No clients defined")
2411
2377
        # Store client before exiting. Secrets are encrypted with key
2412
2378
        # based on what config file has. If config file is
2413
2379
        # removed/edited, old secret will thus be unrecovable.
2414
 
        clients = []
 
2380
        clients = {}
2415
2381
        with PGPEngine() as pgp:
2416
2382
            for client in tcp_server.clients.itervalues():
2417
2383
                key = client_settings[client.name]["secret"]
2419
2385
                                                      key)
2420
2386
                client_dict = {}
2421
2387
                
2422
 
                # A list of attributes that will not be stored when
2423
 
                # shutting down.
 
2388
                # A list of attributes that can not be pickled
 
2389
                # + secret.
2424
2390
                exclude = set(("bus", "changedstate", "secret",
2425
2391
                               "checker"))
2426
2392
                for name, typ in (inspect.getmembers
2433
2399
                    if attr not in exclude:
2434
2400
                        client_dict[attr] = getattr(client, attr)
2435
2401
                
2436
 
                clients.append(client_dict)
 
2402
                clients[client.name] = client_dict
2437
2403
                del client_settings[client.name]["secret"]
2438
2404
        
2439
2405
        try:
2440
 
            with os.fdopen(os.open(stored_state_path,
2441
 
                                   os.O_CREAT|os.O_WRONLY|os.O_TRUNC,
2442
 
                                   0600), "wb") as stored_state:
 
2406
            tempfd, tempname = tempfile.mkstemp(suffix=".pickle",
 
2407
                                                prefix="clients-",
 
2408
                                                dir=os.path.dirname
 
2409
                                                (stored_state_path))
 
2410
            with os.fdopen(tempfd, "wb") as stored_state:
2443
2411
                pickle.dump((clients, client_settings), stored_state)
 
2412
            os.rename(tempname, stored_state_path)
2444
2413
        except (IOError, OSError) as e:
2445
2414
            logger.warning("Could not save persistent state: {0}"
2446
2415
                           .format(e))
2447
 
            if e.errno not in (errno.ENOENT, errno.EACCES):
2448
 
                raise
 
2416
            if not debug:
 
2417
                try:
 
2418
                    os.remove(tempname)
 
2419
                except NameError:
 
2420
                    pass
 
2421
            if e.errno not in set((errno.ENOENT, errno.EACCES,
 
2422
                                   errno.EEXIST)):
 
2423
                raise e
2449
2424
        
2450
2425
        # Delete all clients, and settings from config
2451
2426
        while tcp_server.clients: