40
9
import gnutls.crypto
41
10
import gnutls.connection
42
11
import gnutls.errors
43
import gnutls.library.functions
44
import gnutls.library.constants
45
import gnutls.library.types
46
12
import ConfigParser
56
import logging.handlers
61
from dbus.mainloop.glib import DBusGMainLoop
66
logger = logging.Logger('mandos')
67
syslogger = logging.handlers.SysLogHandler\
68
(facility = logging.handlers.SysLogHandler.LOG_DAEMON,
70
syslogger.setFormatter(logging.Formatter\
71
('Mandos: %(levelname)s: %(message)s'))
72
logger.addHandler(syslogger)
74
console = logging.StreamHandler()
75
console.setFormatter(logging.Formatter('%(name)s: %(levelname)s:'
77
logger.addHandler(console)
79
class AvahiError(Exception):
80
def __init__(self, value):
83
return repr(self.value)
85
class AvahiServiceError(AvahiError):
88
class AvahiGroupError(AvahiError):
92
class AvahiService(object):
93
"""An Avahi (Zeroconf) service.
95
interface: integer; avahi.IF_UNSPEC or an interface index.
96
Used to optionally bind to the specified interface.
97
name: string; Example: 'Mandos'
98
type: string; Example: '_mandos._tcp'.
99
See <http://www.dns-sd.org/ServiceTypes.html>
100
port: integer; what port to announce
101
TXT: list of strings; TXT record for the service
102
domain: string; Domain to publish on, default to .local if empty.
103
host: string; Host to publish records for, default is localhost
104
max_renames: integer; maximum number of renames
105
rename_count: integer; counter so we only rename after collisions
106
a sensible number of times
108
def __init__(self, interface = avahi.IF_UNSPEC, name = None,
109
type = None, port = None, TXT = None, domain = "",
110
host = "", max_renames = 32768):
111
self.interface = interface
121
self.rename_count = 0
122
self.max_renames = max_renames
124
"""Derived from the Avahi example code"""
125
if self.rename_count >= self.max_renames:
126
logger.critical(u"No suitable service name found after %i"
127
u" retries, exiting.", rename_count)
128
raise AvahiServiceError("Too many renames")
129
self.name = server.GetAlternativeServiceName(self.name)
130
logger.info(u"Changing name to %r ...", str(self.name))
131
syslogger.setFormatter(logging.Formatter\
132
('Mandos (%s): %%(levelname)s:'
133
' %%(message)s' % self.name))
136
self.rename_count += 1
138
"""Derived from the Avahi example code"""
139
if group is not None:
142
"""Derived from the Avahi example code"""
145
group = dbus.Interface\
146
(bus.get_object(avahi.DBUS_NAME,
147
server.EntryGroupNew()),
148
avahi.DBUS_INTERFACE_ENTRY_GROUP)
149
group.connect_to_signal('StateChanged',
150
entry_group_state_changed)
151
logger.debug(u"Adding service '%s' of type '%s' ...",
152
service.name, service.type)
154
self.interface, # interface
155
avahi.PROTO_INET6, # protocol
156
dbus.UInt32(0), # flags
157
self.name, self.type,
158
self.domain, self.host,
159
dbus.UInt16(self.port),
160
avahi.string_array_to_txt_array(self.TXT))
163
# From the Avahi example code:
164
group = None # our entry group
165
# End of Avahi example code
168
14
class Client(object):
169
"""A representation of a client host served by this server.
171
name: string; from the config file, used in log messages
172
fingerprint: string (40 or 32 hexadecimal digits); used to
173
uniquely identify the client
174
secret: bytestring; sent verbatim (over TLS) to client
175
host: string; available for use by the checker command
176
created: datetime.datetime(); object creation, not client host
177
last_checked_ok: datetime.datetime() or None if not yet checked OK
178
timeout: datetime.timedelta(); How long from last_checked_ok
179
until this client is invalid
180
interval: datetime.timedelta(); How often to start a new checker
181
stop_hook: If set, called by stop() as stop_hook(self)
182
checker: subprocess.Popen(); a running checker process used
183
to see if the client lives.
184
'None' if no process is running.
185
checker_initiator_tag: a gobject event source tag, or None
186
stop_initiator_tag: - '' -
187
checker_callback_tag: - '' -
188
checker_command: string; External command which is run to check if
189
client lives. %() expansions are done at
190
runtime with vars(self) as dict, so that for
191
instance %(name)s can be used in the command.
193
_timeout: Real variable for 'timeout'
194
_interval: Real variable for 'interval'
195
_timeout_milliseconds: Used when calling gobject.timeout_add()
196
_interval_milliseconds: - '' -
198
def _set_timeout(self, timeout):
199
"Setter function for 'timeout' attribute"
200
self._timeout = timeout
201
self._timeout_milliseconds = ((self.timeout.days
202
* 24 * 60 * 60 * 1000)
203
+ (self.timeout.seconds * 1000)
204
+ (self.timeout.microseconds
206
timeout = property(lambda self: self._timeout,
209
def _set_interval(self, interval):
210
"Setter function for 'interval' attribute"
211
self._interval = interval
212
self._interval_milliseconds = ((self.interval.days
213
* 24 * 60 * 60 * 1000)
214
+ (self.interval.seconds
216
+ (self.interval.microseconds
218
interval = property(lambda self: self._interval,
221
def __init__(self, name = None, stop_hook=None, config={}):
222
"""Note: the 'checker' key in 'config' sets the
223
'checker_command' attribute and *not* the 'checker'
15
def __init__(self, name=None, dn=None, password=None,
16
passfile=None, fqdn=None, timeout=None,
226
logger.debug(u"Creating client %r", self.name)
227
# Uppercase and remove spaces from fingerprint for later
228
# comparison purposes with return value from the fingerprint()
230
self.fingerprint = config["fingerprint"].upper()\
232
logger.debug(u" Fingerprint: %s", self.fingerprint)
233
if "secret" in config:
234
self.secret = config["secret"].decode(u"base64")
235
elif "secfile" in config:
236
sf = open(config["secfile"])
237
self.secret = sf.read()
240
raise TypeError(u"No secret or secfile for client %s"
242
self.host = config.get("host", "")
243
self.created = datetime.datetime.now()
244
self.last_checked_ok = None
245
self.timeout = string_to_delta(config["timeout"])
246
self.interval = string_to_delta(config["interval"])
247
self.stop_hook = stop_hook
249
self.checker_initiator_tag = None
250
self.stop_initiator_tag = None
251
self.checker_callback_tag = None
252
self.check_command = config["checker"]
254
"""Start this client's checker and timeout hooks"""
255
# Schedule a new checker to be started an 'interval' from now,
256
# and every interval from then on.
257
self.checker_initiator_tag = gobject.timeout_add\
258
(self._interval_milliseconds,
260
# Also start a new checker *right now*.
262
# Schedule a stop() when 'timeout' has passed
263
self.stop_initiator_tag = gobject.timeout_add\
264
(self._timeout_milliseconds,
268
The possibility that a client might be restarted is left open,
269
but not currently used."""
270
# If this client doesn't have a secret, it is already stopped.
271
if hasattr(self, "secret") and self.secret:
272
logger.info(u"Stopping client %s", self.name)
276
if getattr(self, "stop_initiator_tag", False):
277
gobject.source_remove(self.stop_initiator_tag)
278
self.stop_initiator_tag = None
279
if getattr(self, "checker_initiator_tag", False):
280
gobject.source_remove(self.checker_initiator_tag)
281
self.checker_initiator_tag = None
285
# Do not run this again if called by a gobject.timeout_add
288
self.stop_hook = None
290
def checker_callback(self, pid, condition):
291
"""The checker has completed, so take appropriate actions."""
292
now = datetime.datetime.now()
293
self.checker_callback_tag = None
295
if os.WIFEXITED(condition) \
296
and (os.WEXITSTATUS(condition) == 0):
297
logger.info(u"Checker for %(name)s succeeded",
299
self.last_checked_ok = now
300
gobject.source_remove(self.stop_initiator_tag)
301
self.stop_initiator_tag = gobject.timeout_add\
302
(self._timeout_milliseconds,
304
elif not os.WIFEXITED(condition):
305
logger.warning(u"Checker for %(name)s crashed?",
308
logger.info(u"Checker for %(name)s failed",
310
def start_checker(self):
311
"""Start a new checker subprocess if one is not running.
312
If a checker already exists, leave it running and do
314
# The reason for not killing a running checker is that if we
315
# did that, then if a checker (for some reason) started
316
# running slowly and taking more than 'interval' time, the
317
# client would inevitably timeout, since no checker would get
318
# a chance to run to completion. If we instead leave running
319
# checkers alone, the checker would have to take more time
320
# than 'timeout' for the client to be declared invalid, which
321
# is as it should be.
322
if self.checker is None:
324
# In case check_command has exactly one % operator
325
command = self.check_command % self.host
327
# Escape attributes for the shell
328
escaped_attrs = dict((key, re.escape(str(val)))
330
vars(self).iteritems())
332
command = self.check_command % escaped_attrs
333
except TypeError, error:
334
logger.error(u'Could not format string "%s":'
335
u' %s', self.check_command, error)
336
return True # Try again later
338
logger.info(u"Starting checker %r for %s",
340
self.checker = subprocess.Popen(command,
343
self.checker_callback_tag = gobject.child_watch_add\
345
self.checker_callback)
346
except subprocess.OSError, error:
347
logger.error(u"Failed to start subprocess: %s",
349
# Re-run this periodically if run by gobject.timeout_add
351
def stop_checker(self):
352
"""Force the checker process, if any, to stop."""
353
if self.checker_callback_tag:
354
gobject.source_remove(self.checker_callback_tag)
355
self.checker_callback_tag = None
356
if getattr(self, "checker", None) is None:
358
logger.debug(u"Stopping checker for %(name)s", vars(self))
21
self.password = password
23
self.password = open(passfile).readall()
25
print "No Password or Passfile in client config file"
26
# raise RuntimeError XXX
27
self.password = "gazonk"
32
timeout = self.server.options.timeout
33
self.timeout = timeout
35
interval = self.server.options.interval
36
self.interval = interval
38
def server_bind(self):
39
if self.options.interface:
40
if not hasattr(socket, "SO_BINDTODEVICE"):
41
# From /usr/include/asm-i486/socket.h
42
socket.SO_BINDTODEVICE = 25
360
os.kill(self.checker.pid, signal.SIGTERM)
362
#if self.checker.poll() is None:
363
# os.kill(self.checker.pid, signal.SIGKILL)
364
except OSError, error:
365
if error.errno != errno.ESRCH: # No such process
368
def still_valid(self):
369
"""Has the timeout not yet passed for this client?"""
370
now = datetime.datetime.now()
371
if self.last_checked_ok is None:
372
return now < (self.created + self.timeout)
374
return now < (self.last_checked_ok + self.timeout)
377
def peer_certificate(session):
378
"Return the peer's OpenPGP certificate as a bytestring"
379
# If not an OpenPGP certificate...
380
if gnutls.library.functions.gnutls_certificate_type_get\
381
(session._c_object) \
382
!= gnutls.library.constants.GNUTLS_CRT_OPENPGP:
383
# ...do the normal thing
384
return session.peer_certificate
385
list_size = ctypes.c_uint()
386
cert_list = gnutls.library.functions.gnutls_certificate_get_peers\
387
(session._c_object, ctypes.byref(list_size))
388
if list_size.value == 0:
391
return ctypes.string_at(cert.data, cert.size)
394
def fingerprint(openpgp):
395
"Convert an OpenPGP bytestring to a hexdigit fingerprint string"
396
# New GnuTLS "datum" with the OpenPGP public key
397
datum = gnutls.library.types.gnutls_datum_t\
398
(ctypes.cast(ctypes.c_char_p(openpgp),
399
ctypes.POINTER(ctypes.c_ubyte)),
400
ctypes.c_uint(len(openpgp)))
401
# New empty GnuTLS certificate
402
crt = gnutls.library.types.gnutls_openpgp_crt_t()
403
gnutls.library.functions.gnutls_openpgp_crt_init\
405
# Import the OpenPGP public key into the certificate
406
gnutls.library.functions.gnutls_openpgp_crt_import\
407
(crt, ctypes.byref(datum),
408
gnutls.library.constants.GNUTLS_OPENPGP_FMT_RAW)
409
# New buffer for the fingerprint
410
buffer = ctypes.create_string_buffer(20)
411
buffer_length = ctypes.c_size_t()
412
# Get the fingerprint from the certificate into the buffer
413
gnutls.library.functions.gnutls_openpgp_crt_get_fingerprint\
414
(crt, ctypes.byref(buffer), ctypes.byref(buffer_length))
415
# Deinit the certificate
416
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
417
# Convert the buffer to a Python bytestring
418
fpr = ctypes.string_at(buffer, buffer_length.value)
419
# Convert the bytestring to hexadecimal notation
420
hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
44
self.socket.setsockopt(socket.SOL_SOCKET,
45
socket.SO_BINDTODEVICE,
46
self.options.interface)
47
except socket.error, error:
48
if error[0] == errno.EPERM:
49
print "Warning: Denied permission to bind to interface", \
50
self.options.interface
53
return super(type(self), self).server_bind()
56
def init_with_options(self, *args, **kwargs):
57
if "options" in kwargs:
58
self.options = kwargs["options"]
60
if "clients" in kwargs:
61
self.clients = kwargs["clients"]
63
if "credentials" in kwargs:
64
self.credentials = kwargs["credentials"]
65
del kwargs["credentials"]
66
return super(type(self), self).__init__(*args, **kwargs)
69
class udp_handler(SocketServer.DatagramRequestHandler, object):
71
self.wfile.write("Polo")
72
print "UDP request answered"
75
class IPv6_UDPServer(SocketServer.UDPServer, object):
76
__init__ = init_with_options
77
address_family = socket.AF_INET6
78
allow_reuse_address = True
79
server_bind = server_bind
80
def verify_request(self, request, client_address):
81
print "UDP request came"
82
return request[0] == "Marco"
424
85
class tcp_handler(SocketServer.BaseRequestHandler, object):
425
"""A TCP request handler class.
426
Instantiated by IPv6_TCPServer for each request to handle it.
427
Note: This will run in its own forked process."""
430
logger.info(u"TCP connection from: %s",
431
unicode(self.client_address))
432
session = gnutls.connection.ClientSession\
433
(self.request, gnutls.connection.X509Credentials())
435
line = self.request.makefile().readline()
436
logger.debug(u"Protocol version: %r", line)
438
if int(line.strip().split()[0]) > 1:
440
except (ValueError, IndexError, RuntimeError), error:
441
logger.error(u"Unknown protocol version: %s", error)
444
# Note: gnutls.connection.X509Credentials is really a generic
445
# GnuTLS certificate credentials object so long as no X.509
446
# keys are added to it. Therefore, we can use it here despite
447
# using OpenPGP certificates.
449
#priority = ':'.join(("NONE", "+VERS-TLS1.1", "+AES-256-CBC",
450
# "+SHA1", "+COMP-NULL", "+CTYPE-OPENPGP",
452
priority = "NORMAL" # Fallback default, since this
454
if self.server.settings["priority"]:
455
priority = self.server.settings["priority"]
456
gnutls.library.functions.gnutls_priority_set_direct\
457
(session._c_object, priority, None);
461
except gnutls.errors.GNUTLSError, error:
462
logger.warning(u"Handshake failed: %s", error)
463
# Do not run session.bye() here: the session is not
464
# established. Just abandon the request.
467
fpr = fingerprint(peer_certificate(session))
468
except (TypeError, gnutls.errors.GNUTLSError), error:
469
logger.warning(u"Bad certificate: %s", error)
472
logger.debug(u"Fingerprint: %s", fpr)
474
for c in self.server.clients:
475
if c.fingerprint == fpr:
479
logger.warning(u"Client not found for fingerprint: %s",
483
# Have to check if client.still_valid(), since it is possible
484
# that the client timed out while establishing the GnuTLS
486
if not client.still_valid():
487
logger.warning(u"Client %(name)s is invalid",
492
while sent_size < len(client.secret):
493
sent = session.send(client.secret[sent_size:])
494
logger.debug(u"Sent: %d, remaining: %d",
495
sent, len(client.secret)
496
- (sent_size + sent))
87
print "TCP request came"
88
print "Request:", self.request
89
print "Client Address:", self.client_address
90
print "Server:", self.server
91
session = gnutls.connection.ServerSession(self.request,
92
self.server.credentials)
94
if session.peer_certificate:
95
print "DN:", session.peer_certificate.subject
98
except gnutls.errors.CertificateError, error:
99
print "Verify failed", error
103
session.send(dict((client.dn, client.password)
104
for client in self.server.clients)
105
[session.peer_certificate.subject])
107
session.send("gazonk")
501
111
class IPv6_TCPServer(SocketServer.ForkingTCPServer, object):
502
"""IPv6 TCP server. Accepts 'None' as address and/or port.
504
settings: Server settings
505
clients: Set() of Client objects
112
__init__ = init_with_options
507
113
address_family = socket.AF_INET6
508
def __init__(self, *args, **kwargs):
509
if "settings" in kwargs:
510
self.settings = kwargs["settings"]
511
del kwargs["settings"]
512
if "clients" in kwargs:
513
self.clients = kwargs["clients"]
514
del kwargs["clients"]
515
return super(type(self), self).__init__(*args, **kwargs)
516
def server_bind(self):
517
"""This overrides the normal server_bind() function
518
to bind to an interface if one was specified, and also NOT to
519
bind to an address or port if they were not specified."""
520
if self.settings["interface"]:
521
# 25 is from /usr/include/asm-i486/socket.h
522
SO_BINDTODEVICE = getattr(socket, "SO_BINDTODEVICE", 25)
524
self.socket.setsockopt(socket.SOL_SOCKET,
526
self.settings["interface"])
527
except socket.error, error:
528
if error[0] == errno.EPERM:
529
logger.error(u"No permission to"
530
u" bind to interface %s",
531
self.settings["interface"])
534
# Only bind(2) the socket if we really need to.
535
if self.server_address[0] or self.server_address[1]:
536
if not self.server_address[0]:
538
self.server_address = (in6addr_any,
539
self.server_address[1])
540
elif not self.server_address[1]:
541
self.server_address = (self.server_address[0],
543
# if self.settings["interface"]:
544
# self.server_address = (self.server_address[0],
550
return super(type(self), self).server_bind()
553
def string_to_delta(interval):
554
"""Parse a string and return a datetime.timedelta
556
>>> string_to_delta('7d')
557
datetime.timedelta(7)
558
>>> string_to_delta('60s')
559
datetime.timedelta(0, 60)
560
>>> string_to_delta('60m')
561
datetime.timedelta(0, 3600)
562
>>> string_to_delta('24h')
563
datetime.timedelta(1)
564
>>> string_to_delta(u'1w')
565
datetime.timedelta(7)
566
>>> string_to_delta('5m 30s')
567
datetime.timedelta(0, 330)
569
timevalue = datetime.timedelta(0)
570
for s in interval.split():
572
suffix=unicode(s[-1])
575
delta = datetime.timedelta(value)
577
delta = datetime.timedelta(0, value)
579
delta = datetime.timedelta(0, 0, 0, 0, value)
581
delta = datetime.timedelta(0, 0, 0, 0, 0, value)
583
delta = datetime.timedelta(0, 0, 0, 0, 0, 0, value)
586
except (ValueError, IndexError):
592
def server_state_changed(state):
593
"""Derived from the Avahi example code"""
594
if state == avahi.SERVER_COLLISION:
595
logger.error(u"Server name collision")
597
elif state == avahi.SERVER_RUNNING:
601
def entry_group_state_changed(state, error):
602
"""Derived from the Avahi example code"""
603
logger.debug(u"state change: %i", state)
605
if state == avahi.ENTRY_GROUP_ESTABLISHED:
606
logger.debug(u"Service established.")
607
elif state == avahi.ENTRY_GROUP_COLLISION:
608
logger.warning(u"Service name collision.")
610
elif state == avahi.ENTRY_GROUP_FAILURE:
611
logger.critical(u"Error in group state changed %s",
613
raise AvahiGroupError("State changed: %s", str(error))
615
def if_nametoindex(interface):
616
"""Call the C function if_nametoindex(), or equivalent"""
617
global if_nametoindex
619
if "ctypes.util" not in sys.modules:
621
if_nametoindex = ctypes.cdll.LoadLibrary\
622
(ctypes.util.find_library("c")).if_nametoindex
623
except (OSError, AttributeError):
624
if "struct" not in sys.modules:
626
if "fcntl" not in sys.modules:
628
def if_nametoindex(interface):
629
"Get an interface index the hard way, i.e. using fcntl()"
630
SIOCGIFINDEX = 0x8933 # From /usr/include/linux/sockios.h
632
ifreq = fcntl.ioctl(s, SIOCGIFINDEX,
633
struct.pack("16s16x", interface))
635
interface_index = struct.unpack("I", ifreq[16:20])[0]
636
return interface_index
637
return if_nametoindex(interface)
640
def daemon(nochdir = False, noclose = False):
641
"""See daemon(3). Standard BSD Unix function.
642
This should really exist as os.daemon, but it doesn't (yet)."""
651
# Close all standard open file descriptors
652
null = os.open(os.path.devnull, os.O_NOCTTY | os.O_RDWR)
653
if not stat.S_ISCHR(os.fstat(null).st_mode):
654
raise OSError(errno.ENODEV,
655
"/dev/null not a character device")
656
os.dup2(null, sys.stdin.fileno())
657
os.dup2(null, sys.stdout.fileno())
658
os.dup2(null, sys.stderr.fileno())
114
allow_reuse_address = True
115
request_queue_size = 1024
116
server_bind = server_bind
664
global main_loop_started
665
main_loop_started = False
667
parser = OptionParser(version = "%%prog %s" % version)
124
parser = OptionParser()
668
125
parser.add_option("-i", "--interface", type="string",
669
metavar="IF", help="Bind to interface IF")
670
parser.add_option("-a", "--address", type="string",
671
help="Address to listen for requests on")
672
parser.add_option("-p", "--port", type="int",
126
default="eth0", metavar="IF",
127
help="Interface to bind to")
128
parser.add_option("--cert", type="string", default="cert.pem",
130
help="Public key certificate to use")
131
parser.add_option("--key", type="string", default="key.pem",
133
help="Private key to use")
134
parser.add_option("--ca", type="string", default="ca.pem",
136
help="Certificate Authority certificate to use")
137
parser.add_option("--crl", type="string", default="crl.pem",
139
help="Certificate Revokation List to use")
140
parser.add_option("-p", "--port", type="int", default=49001,
673
141
help="Port number to receive requests on")
674
parser.add_option("--check", action="store_true", default=False,
675
help="Run self-test")
676
parser.add_option("--debug", action="store_true",
677
help="Debug mode; run in foreground and log to"
679
parser.add_option("--priority", type="string", help="GnuTLS"
680
" priority string (see GnuTLS documentation)")
681
parser.add_option("--servicename", type="string", metavar="NAME",
682
help="Zeroconf service name")
683
parser.add_option("--configdir", type="string",
684
default="/etc/mandos", metavar="DIR",
685
help="Directory to search for configuration"
142
parser.add_option("--dh", type="int", metavar="BITS",
143
help="DH group to use")
144
parser.add_option("-t", "--timeout", type="string", # Parsed later
146
help="Amount of downtime allowed for clients")
687
147
(options, args) = parser.parse_args()
694
# Default values for config file for server-global settings
695
server_defaults = { "interface": "",
700
"SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
701
"servicename": "Mandos",
704
# Parse config file for server-global settings
705
server_config = ConfigParser.SafeConfigParser(server_defaults)
707
server_config.read(os.path.join(options.configdir, "mandos.conf"))
708
# Convert the SafeConfigParser object to a dict
709
server_settings = server_config.defaults()
710
# Use getboolean on the boolean config option
711
server_settings["debug"] = server_config.getboolean\
715
# Override the settings from the config file with command line
717
for option in ("interface", "address", "port", "debug",
718
"priority", "servicename", "configdir"):
719
value = getattr(options, option)
720
if value is not None:
721
server_settings[option] = value
723
# Now we have our good server settings in "server_settings"
725
debug = server_settings["debug"]
728
syslogger.setLevel(logging.WARNING)
729
console.setLevel(logging.WARNING)
731
if server_settings["servicename"] != "Mandos":
732
syslogger.setFormatter(logging.Formatter\
733
('Mandos (%s): %%(levelname)s:'
735
% server_settings["servicename"]))
737
# Parse config file with clients
738
client_defaults = { "timeout": "1h",
740
"checker": "fping -q -- %%(host)s",
743
client_config = ConfigParser.SafeConfigParser(client_defaults)
744
client_config.read(os.path.join(server_settings["configdir"],
748
service = AvahiService(name = server_settings["servicename"],
749
type = "_mandos._tcp", );
750
if server_settings["interface"]:
751
service.interface = if_nametoindex(server_settings["interface"])
756
# From the Avahi example code
757
DBusGMainLoop(set_as_default=True )
758
main_loop = gobject.MainLoop()
759
bus = dbus.SystemBus()
760
server = dbus.Interface(
761
bus.get_object( avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER ),
762
avahi.DBUS_INTERFACE_SERVER )
763
# End of Avahi example code
766
def remove_from_clients(client):
767
clients.remove(client)
769
logger.critical(u"No clients left, exiting")
772
clients.update(Set(Client(name = section,
773
stop_hook = remove_from_clients,
775
= dict(client_config.items(section)))
776
for section in client_config.sections()))
778
logger.critical(u"No clients defined")
782
logger.removeHandler(console)
785
pidfilename = "/var/run/mandos/mandos.pid"
149
# Parse the time argument
788
pidfile = open(pidfilename, "w")
789
pidfile.write(str(pid) + "\n")
793
logger.error(u"Could not write %s file with PID %d",
794
pidfilename, os.getpid())
797
"Cleanup function; run on exit"
799
# From the Avahi example code
800
if not group is None:
803
# End of Avahi example code
806
client = clients.pop()
807
client.stop_hook = None
810
atexit.register(cleanup)
813
signal.signal(signal.SIGINT, signal.SIG_IGN)
814
signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
815
signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
817
for client in clients:
820
tcp_server = IPv6_TCPServer((server_settings["address"],
821
server_settings["port"]),
151
suffix=options.timeout[-1]
152
value=int(options.timeout[:-1])
154
options.timeout = datetime.timedelta(value)
156
options.timeout = datetime.timedelta(0, value)
158
options.timeout = datetime.timedelta(0, 0, 0, 0, value)
160
options.timeout = datetime.timedelta(0, 0, 0, 0, 0, value)
162
options.timeout = datetime.timedelta(0, 0, 0, 0, 0, 0,
166
except (ValueError, IndexError):
167
parser.error("option --timeout: Unparseable time")
169
cert = gnutls.crypto.X509Certificate(open(options.cert).read())
170
key = gnutls.crypto.X509PrivateKey(open(options.key).read())
171
ca = gnutls.crypto.X509Certificate(open(options.ca).read())
172
crl = gnutls.crypto.X509CRL(open(options.crl).read())
173
cred = gnutls.connection.X509Credentials(cert, key, [ca], [crl])
177
client_config_object = ConfigParser.SafeConfigParser(defaults)
178
client_config_object.read("mandos-clients.conf")
179
clients = [Client(name=section,
180
**(dict(client_config_object.items(section))))
181
for section in client_config_object.sections()]
183
udp_server = IPv6_UDPServer((in6addr_any, options.port),
187
tcp_server = IPv6_TCPServer((in6addr_any, options.port),
823
settings=server_settings,
825
# Find out what port we got
826
service.port = tcp_server.socket.getsockname()[1]
827
logger.info(u"Now listening on address %r, port %d, flowinfo %d,"
828
u" scope_id %d" % tcp_server.socket.getsockname())
830
#service.interface = tcp_server.socket.getsockname()[3]
833
# From the Avahi example code
834
server.connect_to_signal("StateChanged", server_state_changed)
836
server_state_changed(server.GetState())
837
except dbus.exceptions.DBusException, error:
838
logger.critical(u"DBusException: %s", error)
840
# End of Avahi example code
842
gobject.io_add_watch(tcp_server.fileno(), gobject.IO_IN,
843
lambda *args, **kwargs:
844
tcp_server.handle_request\
845
(*args[2:], **kwargs) or True)
847
logger.debug(u"Starting main loop")
848
main_loop_started = True
850
except AvahiError, error:
851
logger.critical(u"AvahiError: %s" + unicode(error))
853
except KeyboardInterrupt:
857
if __name__ == '__main__':
194
in_, out, err = select.select((udp_server,
197
server.handle_request()
200
if __name__ == "__main__":