=== modified file 'TODO'
--- TODO 2008-10-28 18:00:20 +0000
+++ TODO 2008-12-10 01:26:02 +0000
@@ -14,6 +14,12 @@
** TODO [#B] Run-time communication with server :bugs:
Probably using D-Bus
See also [[*Mandos-tools]]
+*** Client class
+*** Main server
+ + SetLogLevel
+ syslogger.setLevel(logging.WARNING)
+ + Quit
+ + [[http://log.ometer.com/2007-05.html][Best D-Bus practices]]
** TODO Implement --foreground :bugs:
[[info:standards:Option%20Table][Table of Long Options]]
** TODO Implement --socket
@@ -21,6 +27,8 @@
** TODO Date+time on console log messages :bugs:
Is this the default?
** TODO delete hook when clients fall out by timeout
+ This will not be strictly necessary when the D-Bus interface is
+ implemented.
* Mandos-tools/utilities
All of this probably using D-Bus
=== modified file 'debian/mandos-client.postinst'
--- debian/mandos-client.postinst 2008-09-26 04:54:35 +0000
+++ debian/mandos-client.postinst 2008-12-10 01:26:02 +0000
@@ -27,10 +27,19 @@
# Add user and group
add_mandos_user(){
- if ! getent passwd mandos >/dev/null; then
- adduser --disabled-password --quiet --system \
- --home /nonexistent --no-create-home \
- --gecos "Mandos password system" --group mandos
+ # Rename old "mandos" user and group
+ case "$(getent passwd mandos)" in
+ *:Mandos\ password\ system,,,:/nonexistent:/bin/false)
+ usermod --login _mandos mandos
+ groupmod --new-name _mandos mandos
+ return
+ ;;
+ esac
+ # Create new user and group
+ if ! getent passwd _mandos >/dev/null; then
+ adduser --system --force-badname --quiet --home /nonexistent \
+ --no-create-home --group --disabled-password \
+ --gecos "Mandos password system" _mandos
fi
}
=== modified file 'debian/mandos.postinst'
--- debian/mandos.postinst 2008-09-26 04:54:35 +0000
+++ debian/mandos.postinst 2008-12-10 01:26:02 +0000
@@ -19,10 +19,19 @@
case "$1" in
configure)
- if ! getent passwd mandos >/dev/null; then
- adduser --disabled-password --quiet --system \
- --home /nonexistent --no-create-home \
- --gecos "Mandos password system" --group mandos
+ # Rename old "mandos" user and group
+ case "$(getent passwd mandos)" in
+ *:Mandos\ password\ system,,,:/nonexistent:/bin/false)
+ usermod --login _mandos mandos
+ groupmod --new-name _mandos mandos
+ ;;
+ esac
+ # Create new user and group
+ if ! getent passwd _mandos >/dev/null; then
+ adduser --system --force-badname --quiet \
+ --home /nonexistent --no-create-home --group \
+ --disabled-password --gecos "Mandos password system" \
+ _mandos
fi
;;
=== modified file 'initramfs-tools-hook'
--- initramfs-tools-hook 2008-11-01 02:26:00 +0000
+++ initramfs-tools-hook 2008-12-10 01:26:02 +0000
@@ -51,11 +51,13 @@
exit 1
fi
-mandos_user="`{ getent passwd mandos \
+mandos_user="`{ getent passwd _mandos \
+ || getent passwd mandos \
|| getent passwd nobody \
|| echo ::65534::::; } \
| awk --field-separator=: '{ print $3 }'`"
-mandos_group="`{ getent group mandos \
+mandos_group="`{ getent group _mandos \
+ || getent group mandos \
|| getent group nogroup \
|| echo ::65534:; } \
| awk --field-separator=: '{ print $3 }'`"
=== modified file 'mandos'
--- mandos 2008-11-08 17:26:35 +0000
+++ mandos 2008-12-10 01:26:02 +0000
@@ -11,7 +11,8 @@
# and some lines in "main".
#
# Everything else is
-# Copyright © 2008 Teddy Hogeborn & Björn Påhlsson
+# Copyright © 2008 Teddy Hogeborn
+# Copyright © 2008 Björn Påhlsson
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -58,6 +59,7 @@
from contextlib import closing
import dbus
+import dbus.service
import gobject
import avahi
from dbus.mainloop.glib import DBusGMainLoop
@@ -67,11 +69,11 @@
version = "1.0.2"
logger = logging.Logger('mandos')
-syslogger = logging.handlers.SysLogHandler\
- (facility = logging.handlers.SysLogHandler.LOG_DAEMON,
- address = "/dev/log")
-syslogger.setFormatter(logging.Formatter\
- ('Mandos: %(levelname)s: %(message)s'))
+syslogger = (logging.handlers.SysLogHandler
+ (facility = logging.handlers.SysLogHandler.LOG_DAEMON,
+ address = "/dev/log"))
+syslogger.setFormatter(logging.Formatter
+ ('Mandos: %(levelname)s: %(message)s'))
logger.addHandler(syslogger)
console = logging.StreamHandler()
@@ -110,16 +112,13 @@
a sensible number of times
"""
def __init__(self, interface = avahi.IF_UNSPEC, name = None,
- servicetype = None, port = None, TXT = None, domain = "",
- host = "", max_renames = 32768):
+ servicetype = None, port = None, TXT = None,
+ domain = "", host = "", max_renames = 32768):
self.interface = interface
self.name = name
self.type = servicetype
self.port = port
- if TXT is None:
- self.TXT = []
- else:
- self.TXT = TXT
+ self.TXT = TXT if TXT is not None else []
self.domain = domain
self.host = host
self.rename_count = 0
@@ -134,9 +133,9 @@
self.name = server.GetAlternativeServiceName(self.name)
logger.info(u"Changing Zeroconf service name to %r ...",
str(self.name))
- syslogger.setFormatter(logging.Formatter\
+ syslogger.setFormatter(logging.Formatter
('Mandos (%s): %%(levelname)s:'
- ' %%(message)s' % self.name))
+ ' %%(message)s' % self.name))
self.remove()
self.add()
self.rename_count += 1
@@ -148,10 +147,10 @@
"""Derived from the Avahi example code"""
global group
if group is None:
- group = dbus.Interface\
- (bus.get_object(avahi.DBUS_NAME,
+ group = dbus.Interface(bus.get_object
+ (avahi.DBUS_NAME,
server.EntryGroupNew()),
- avahi.DBUS_INTERFACE_ENTRY_GROUP)
+ avahi.DBUS_INTERFACE_ENTRY_GROUP)
group.connect_to_signal('StateChanged',
entry_group_state_changed)
logger.debug(u"Adding Zeroconf service '%s' of type '%s' ...",
@@ -171,23 +170,40 @@
# End of Avahi example code
-class Client(object):
+def _datetime_to_dbus_struct(dt, variant_level=0):
+ """Convert a UTC datetime.datetime() to a D-Bus struct.
+ The format is special to this application, since we could not find
+ any other standard way."""
+ return dbus.Struct((dbus.Int16(dt.year),
+ dbus.Byte(dt.month),
+ dbus.Byte(dt.day),
+ dbus.Byte(dt.hour),
+ dbus.Byte(dt.minute),
+ dbus.Byte(dt.second),
+ dbus.UInt32(dt.microsecond)),
+ signature="nyyyyyu",
+ variant_level=variant_level)
+
+
+class Client(dbus.service.Object):
"""A representation of a client host served by this server.
Attributes:
- name: string; from the config file, used in log messages
+ name: string; from the config file, used in log messages
fingerprint: string (40 or 32 hexadecimal digits); used to
uniquely identify the client
- secret: bytestring; sent verbatim (over TLS) to client
- host: string; available for use by the checker command
- created: datetime.datetime(); object creation, not client host
- last_checked_ok: datetime.datetime() or None if not yet checked OK
- timeout: datetime.timedelta(); How long from last_checked_ok
- until this client is invalid
- interval: datetime.timedelta(); How often to start a new checker
- stop_hook: If set, called by stop() as stop_hook(self)
- checker: subprocess.Popen(); a running checker process used
- to see if the client lives.
- 'None' if no process is running.
+ secret: bytestring; sent verbatim (over TLS) to client
+ host: string; available for use by the checker command
+ created: datetime.datetime(); (UTC) object creation
+ last_started: datetime.datetime(); (UTC)
+ started: bool()
+ last_checked_ok: datetime.datetime(); (UTC) or None
+ timeout: datetime.timedelta(); How long from last_checked_ok
+ until this client is invalid
+ interval: datetime.timedelta(); How often to start a new checker
+ stop_hook: If set, called by stop() as stop_hook(self)
+ checker: subprocess.Popen(); a running checker process used
+ to see if the client lives.
+ 'None' if no process is running.
checker_initiator_tag: a gobject event source tag, or None
stop_initiator_tag: - '' -
checker_callback_tag: - '' -
@@ -195,6 +211,7 @@
client lives. %() expansions are done at
runtime with vars(self) as dict, so that for
instance %(name)s can be used in the command.
+ dbus_object_path: dbus.ObjectPath
Private attibutes:
_timeout: Real variable for 'timeout'
_interval: Real variable for 'interval'
@@ -202,18 +219,22 @@
_interval_milliseconds: - '' -
"""
def _set_timeout(self, timeout):
- "Setter function for 'timeout' attribute"
+ "Setter function for the 'timeout' attribute"
self._timeout = timeout
self._timeout_milliseconds = ((self.timeout.days
* 24 * 60 * 60 * 1000)
+ (self.timeout.seconds * 1000)
+ (self.timeout.microseconds
// 1000))
- timeout = property(lambda self: self._timeout,
- _set_timeout)
+ # Emit D-Bus signal
+ self.PropertyChanged(dbus.String(u"timeout"),
+ (dbus.UInt64(self._timeout_milliseconds,
+ variant_level=1)))
+ timeout = property(lambda self: self._timeout, _set_timeout)
del _set_timeout
+
def _set_interval(self, interval):
- "Setter function for 'interval' attribute"
+ "Setter function for the 'interval' attribute"
self._interval = interval
self._interval_milliseconds = ((self.interval.days
* 24 * 60 * 60 * 1000)
@@ -221,13 +242,22 @@
* 1000)
+ (self.interval.microseconds
// 1000))
- interval = property(lambda self: self._interval,
- _set_interval)
+ # Emit D-Bus signal
+ self.PropertyChanged(dbus.String(u"interval"),
+ (dbus.UInt64(self._interval_milliseconds,
+ variant_level=1)))
+ interval = property(lambda self: self._interval, _set_interval)
del _set_interval
+
def __init__(self, name = None, stop_hook=None, config=None):
"""Note: the 'checker' key in 'config' sets the
'checker_command' attribute and *not* the 'checker'
attribute."""
+ self.dbus_object_path = (dbus.ObjectPath
+ ("/Mandos/clients/"
+ + name.replace(".", "_")))
+ dbus.service.Object.__init__(self, bus,
+ self.dbus_object_path)
if config is None:
config = {}
self.name = name
@@ -235,22 +265,23 @@
# Uppercase and remove spaces from fingerprint for later
# comparison purposes with return value from the fingerprint()
# function
- self.fingerprint = config["fingerprint"].upper()\
- .replace(u" ", u"")
+ self.fingerprint = (config["fingerprint"].upper()
+ .replace(u" ", u""))
logger.debug(u" Fingerprint: %s", self.fingerprint)
if "secret" in config:
self.secret = config["secret"].decode(u"base64")
elif "secfile" in config:
with closing(open(os.path.expanduser
(os.path.expandvars
- (config["secfile"])))) \
- as secfile:
+ (config["secfile"])))) as secfile:
self.secret = secfile.read()
else:
raise TypeError(u"No secret or secfile for client %s"
% self.name)
self.host = config.get("host", "")
- self.created = datetime.datetime.now()
+ self.created = datetime.datetime.utcnow()
+ self.started = False
+ self.last_started = None
self.last_checked_ok = None
self.timeout = string_to_delta(config["timeout"])
self.interval = string_to_delta(config["interval"])
@@ -259,30 +290,35 @@
self.checker_initiator_tag = None
self.stop_initiator_tag = None
self.checker_callback_tag = None
- self.check_command = config["checker"]
+ self.checker_command = config["checker"]
+
def start(self):
"""Start this client's checker and timeout hooks"""
+ self.last_started = datetime.datetime.utcnow()
# Schedule a new checker to be started an 'interval' from now,
# and every interval from then on.
- self.checker_initiator_tag = gobject.timeout_add\
- (self._interval_milliseconds,
- self.start_checker)
+ self.checker_initiator_tag = (gobject.timeout_add
+ (self._interval_milliseconds,
+ self.start_checker))
# Also start a new checker *right now*.
self.start_checker()
# Schedule a stop() when 'timeout' has passed
- self.stop_initiator_tag = gobject.timeout_add\
- (self._timeout_milliseconds,
- self.stop)
+ self.stop_initiator_tag = (gobject.timeout_add
+ (self._timeout_milliseconds,
+ self.stop))
+ self.started = True
+ # Emit D-Bus signal
+ self.PropertyChanged(dbus.String(u"started"),
+ dbus.Boolean(True, variant_level=1))
+ self.PropertyChanged(dbus.String(u"last_started"),
+ (_datetime_to_dbus_struct
+ (self.last_started, variant_level=1)))
+
def stop(self):
- """Stop this client.
- The possibility that a client might be restarted is left open,
- but not currently used."""
- # If this client doesn't have a secret, it is already stopped.
- if hasattr(self, "secret") and self.secret:
- logger.info(u"Stopping client %s", self.name)
- self.secret = None
- else:
+ """Stop this client."""
+ if not getattr(self, "started", False):
return False
+ logger.info(u"Stopping client %s", self.name)
if getattr(self, "stop_initiator_tag", False):
gobject.source_remove(self.stop_initiator_tag)
self.stop_initiator_tag = None
@@ -292,35 +328,63 @@
self.stop_checker()
if self.stop_hook:
self.stop_hook(self)
+ self.started = False
+ # Emit D-Bus signal
+ self.PropertyChanged(dbus.String(u"started"),
+ dbus.Boolean(False, variant_level=1))
# Do not run this again if called by a gobject.timeout_add
return False
+
def __del__(self):
self.stop_hook = None
self.stop()
- def checker_callback(self, pid, condition):
+
+ def checker_callback(self, pid, condition, command):
"""The checker has completed, so take appropriate actions."""
self.checker_callback_tag = None
self.checker = None
- if os.WIFEXITED(condition) \
- and (os.WEXITSTATUS(condition) == 0):
+ # Emit D-Bus signal
+ self.PropertyChanged(dbus.String(u"checker_running"),
+ dbus.Boolean(False, variant_level=1))
+ if (os.WIFEXITED(condition)
+ and (os.WEXITSTATUS(condition) == 0)):
logger.info(u"Checker for %(name)s succeeded",
vars(self))
+ # Emit D-Bus signal
+ self.CheckerCompleted(dbus.Boolean(True),
+ dbus.UInt16(condition),
+ dbus.String(command))
self.bump_timeout()
elif not os.WIFEXITED(condition):
logger.warning(u"Checker for %(name)s crashed?",
vars(self))
+ # Emit D-Bus signal
+ self.CheckerCompleted(dbus.Boolean(False),
+ dbus.UInt16(condition),
+ dbus.String(command))
else:
logger.info(u"Checker for %(name)s failed",
vars(self))
+ # Emit D-Bus signal
+ self.CheckerCompleted(dbus.Boolean(False),
+ dbus.UInt16(condition),
+ dbus.String(command))
+
def bump_timeout(self):
"""Bump up the timeout for this client.
This should only be called when the client has been seen,
alive and well.
"""
- self.last_checked_ok = datetime.datetime.now()
+ self.last_checked_ok = datetime.datetime.utcnow()
gobject.source_remove(self.stop_initiator_tag)
- self.stop_initiator_tag = gobject.timeout_add\
- (self._timeout_milliseconds, self.stop)
+ self.stop_initiator_tag = (gobject.timeout_add
+ (self._timeout_milliseconds,
+ self.stop))
+ self.PropertyChanged(dbus.String(u"last_checked_ok"),
+ (_datetime_to_dbus_struct
+ (self.last_checked_ok,
+ variant_level=1)))
+
def start_checker(self):
"""Start a new checker subprocess if one is not running.
If a checker already exists, leave it running and do
@@ -335,18 +399,18 @@
# is as it should be.
if self.checker is None:
try:
- # In case check_command has exactly one % operator
- command = self.check_command % self.host
+ # In case checker_command has exactly one % operator
+ command = self.checker_command % self.host
except TypeError:
# Escape attributes for the shell
escaped_attrs = dict((key, re.escape(str(val)))
for key, val in
vars(self).iteritems())
try:
- command = self.check_command % escaped_attrs
+ command = self.checker_command % escaped_attrs
except TypeError, error:
logger.error(u'Could not format string "%s":'
- u' %s', self.check_command, error)
+ u' %s', self.checker_command, error)
return True # Try again later
try:
logger.info(u"Starting checker %r for %s",
@@ -358,14 +422,20 @@
self.checker = subprocess.Popen(command,
close_fds=True,
shell=True, cwd="/")
- self.checker_callback_tag = gobject.child_watch_add\
- (self.checker.pid,
- self.checker_callback)
+ # Emit D-Bus signal
+ self.CheckerStarted(command)
+ self.PropertyChanged(dbus.String("checker_running"),
+ dbus.Boolean(True, variant_level=1))
+ self.checker_callback_tag = (gobject.child_watch_add
+ (self.checker.pid,
+ self.checker_callback,
+ data=command))
except OSError, error:
logger.error(u"Failed to start subprocess: %s",
error)
# Re-run this periodically if run by gobject.timeout_add
return True
+
def stop_checker(self):
"""Force the checker process, if any, to stop."""
if self.checker_callback_tag:
@@ -383,26 +453,153 @@
if error.errno != errno.ESRCH: # No such process
raise
self.checker = None
+ self.PropertyChanged(dbus.String(u"checker_running"),
+ dbus.Boolean(False, variant_level=1))
+
def still_valid(self):
"""Has the timeout not yet passed for this client?"""
- now = datetime.datetime.now()
+ if not getattr(self, "started", False):
+ return False
+ now = datetime.datetime.utcnow()
if self.last_checked_ok is None:
return now < (self.created + self.timeout)
else:
return now < (self.last_checked_ok + self.timeout)
+
+ ## D-Bus methods & signals
+ _interface = u"org.mandos_system.Mandos.Client"
+
+ # BumpTimeout - method
+ BumpTimeout = dbus.service.method(_interface)(bump_timeout)
+ BumpTimeout.__name__ = "BumpTimeout"
+
+ # CheckerCompleted - signal
+ @dbus.service.signal(_interface, signature="bqs")
+ def CheckerCompleted(self, success, condition, command):
+ "D-Bus signal"
+ pass
+
+ # CheckerStarted - signal
+ @dbus.service.signal(_interface, signature="s")
+ def CheckerStarted(self, command):
+ "D-Bus signal"
+ pass
+
+ # GetAllProperties - method
+ @dbus.service.method(_interface, out_signature="a{sv}")
+ def GetAllProperties(self):
+ "D-Bus method"
+ return dbus.Dictionary({
+ dbus.String("name"):
+ dbus.String(self.name, variant_level=1),
+ dbus.String("fingerprint"):
+ dbus.String(self.fingerprint, variant_level=1),
+ dbus.String("host"):
+ dbus.String(self.host, variant_level=1),
+ dbus.String("created"):
+ _datetime_to_dbus_struct(self.created,
+ variant_level=1),
+ dbus.String("last_started"):
+ (_datetime_to_dbus_struct(self.last_started,
+ variant_level=1)
+ if self.last_started is not None
+ else dbus.Boolean(False, variant_level=1)),
+ dbus.String("started"):
+ dbus.Boolean(self.started, variant_level=1),
+ dbus.String("last_checked_ok"):
+ (_datetime_to_dbus_struct(self.last_checked_ok,
+ variant_level=1)
+ if self.last_checked_ok is not None
+ else dbus.Boolean (False, variant_level=1)),
+ dbus.String("timeout"):
+ dbus.UInt64(self._timeout_milliseconds,
+ variant_level=1),
+ dbus.String("interval"):
+ dbus.UInt64(self._interval_milliseconds,
+ variant_level=1),
+ dbus.String("checker"):
+ dbus.String(self.checker_command,
+ variant_level=1),
+ dbus.String("checker_running"):
+ dbus.Boolean(self.checker is not None,
+ variant_level=1),
+ }, signature="sv")
+
+ # IsStillValid - method
+ IsStillValid = (dbus.service.method(_interface, out_signature="b")
+ (still_valid))
+ IsStillValid.__name__ = "IsStillValid"
+
+ # PropertyChanged - signal
+ @dbus.service.signal(_interface, signature="sv")
+ def PropertyChanged(self, property, value):
+ "D-Bus signal"
+ pass
+
+ # SetChecker - method
+ @dbus.service.method(_interface, in_signature="s")
+ def SetChecker(self, checker):
+ "D-Bus setter method"
+ self.checker_command = checker
+
+ # SetHost - method
+ @dbus.service.method(_interface, in_signature="s")
+ def SetHost(self, host):
+ "D-Bus setter method"
+ self.host = host
+
+ # SetInterval - method
+ @dbus.service.method(_interface, in_signature="t")
+ def SetInterval(self, milliseconds):
+ self.interval = datetime.timdeelta(0, 0, 0, milliseconds)
+
+ # SetSecret - method
+ @dbus.service.method(_interface, in_signature="ay",
+ byte_arrays=True)
+ def SetSecret(self, secret):
+ "D-Bus setter method"
+ self.secret = str(secret)
+
+ # SetTimeout - method
+ @dbus.service.method(_interface, in_signature="t")
+ def SetTimeout(self, milliseconds):
+ self.timeout = datetime.timedelta(0, 0, 0, milliseconds)
+
+ # Start - method
+ Start = dbus.service.method(_interface)(start)
+ Start.__name__ = "Start"
+
+ # StartChecker - method
+ @dbus.service.method(_interface)
+ def StartChecker(self):
+ "D-Bus method"
+ self.start_checker()
+
+ # Stop - method
+ @dbus.service.method(_interface)
+ def Stop(self):
+ "D-Bus method"
+ self.stop()
+
+ # StopChecker - method
+ StopChecker = dbus.service.method(_interface)(stop_checker)
+ StopChecker.__name__ = "StopChecker"
+
+ del _interface
def peer_certificate(session):
"Return the peer's OpenPGP certificate as a bytestring"
# If not an OpenPGP certificate...
- if gnutls.library.functions.gnutls_certificate_type_get\
- (session._c_object) \
- != gnutls.library.constants.GNUTLS_CRT_OPENPGP:
+ if (gnutls.library.functions
+ .gnutls_certificate_type_get(session._c_object)
+ != gnutls.library.constants.GNUTLS_CRT_OPENPGP):
# ...do the normal thing
return session.peer_certificate
list_size = ctypes.c_uint()
- cert_list = gnutls.library.functions.gnutls_certificate_get_peers\
- (session._c_object, ctypes.byref(list_size))
+ cert_list = (gnutls.library.functions
+ .gnutls_certificate_get_peers
+ (session._c_object, ctypes.byref(list_size)))
if list_size.value == 0:
return None
cert = cert_list[0]
@@ -412,22 +609,24 @@
def fingerprint(openpgp):
"Convert an OpenPGP bytestring to a hexdigit fingerprint string"
# New GnuTLS "datum" with the OpenPGP public key
- datum = gnutls.library.types.gnutls_datum_t\
- (ctypes.cast(ctypes.c_char_p(openpgp),
- ctypes.POINTER(ctypes.c_ubyte)),
- ctypes.c_uint(len(openpgp)))
+ datum = (gnutls.library.types
+ .gnutls_datum_t(ctypes.cast(ctypes.c_char_p(openpgp),
+ ctypes.POINTER
+ (ctypes.c_ubyte)),
+ ctypes.c_uint(len(openpgp))))
# New empty GnuTLS certificate
crt = gnutls.library.types.gnutls_openpgp_crt_t()
- gnutls.library.functions.gnutls_openpgp_crt_init\
- (ctypes.byref(crt))
+ (gnutls.library.functions
+ .gnutls_openpgp_crt_init(ctypes.byref(crt)))
# Import the OpenPGP public key into the certificate
- gnutls.library.functions.gnutls_openpgp_crt_import\
- (crt, ctypes.byref(datum),
- gnutls.library.constants.GNUTLS_OPENPGP_FMT_RAW)
+ (gnutls.library.functions
+ .gnutls_openpgp_crt_import(crt, ctypes.byref(datum),
+ gnutls.library.constants
+ .GNUTLS_OPENPGP_FMT_RAW))
# Verify the self signature in the key
crtverify = ctypes.c_uint()
- gnutls.library.functions.gnutls_openpgp_crt_verify_self\
- (crt, 0, ctypes.byref(crtverify))
+ (gnutls.library.functions
+ .gnutls_openpgp_crt_verify_self(crt, 0, ctypes.byref(crtverify)))
if crtverify.value != 0:
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
raise gnutls.errors.CertificateSecurityError("Verify failed")
@@ -435,8 +634,9 @@
buf = ctypes.create_string_buffer(20)
buf_len = ctypes.c_size_t()
# Get the fingerprint from the certificate into the buffer
- gnutls.library.functions.gnutls_openpgp_crt_get_fingerprint\
- (crt, ctypes.byref(buf), ctypes.byref(buf_len))
+ (gnutls.library.functions
+ .gnutls_openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
+ ctypes.byref(buf_len)))
# Deinit the certificate
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
# Convert the buffer to a Python bytestring
@@ -454,8 +654,10 @@
def handle(self):
logger.info(u"TCP connection from: %s",
unicode(self.client_address))
- session = gnutls.connection.ClientSession\
- (self.request, gnutls.connection.X509Credentials())
+ session = (gnutls.connection
+ .ClientSession(self.request,
+ gnutls.connection
+ .X509Credentials()))
line = self.request.makefile().readline()
logger.debug(u"Protocol version: %r", line)
@@ -476,8 +678,9 @@
# "+DHE-DSS"))
# Use a fallback default, since this MUST be set.
priority = self.server.settings.get("priority", "NORMAL")
- gnutls.library.functions.gnutls_priority_set_direct\
- (session._c_object, priority, None)
+ (gnutls.library.functions
+ .gnutls_priority_set_direct(session._c_object,
+ priority, None))
try:
session.handshake()
@@ -493,12 +696,11 @@
session.bye()
return
logger.debug(u"Fingerprint: %s", fpr)
- client = None
for c in self.server.clients:
if c.fingerprint == fpr:
client = c
break
- if not client:
+ else:
logger.warning(u"Client not found for fingerprint: %s",
fpr)
session.bye()
@@ -649,8 +851,9 @@
"""Call the C function if_nametoindex(), or equivalent"""
global if_nametoindex
try:
- if_nametoindex = ctypes.cdll.LoadLibrary\
- (ctypes.util.find_library("c")).if_nametoindex
+ if_nametoindex = (ctypes.cdll.LoadLibrary
+ (ctypes.util.find_library("c"))
+ .if_nametoindex)
except (OSError, AttributeError):
if "struct" not in sys.modules:
import struct
@@ -735,8 +938,8 @@
# Convert the SafeConfigParser object to a dict
server_settings = server_config.defaults()
# Use getboolean on the boolean config option
- server_settings["debug"] = server_config.getboolean\
- ("DEFAULT", "debug")
+ server_settings["debug"] = (server_config.getboolean
+ ("DEFAULT", "debug"))
del server_config
# Override the settings from the config file with command line
@@ -756,7 +959,7 @@
console.setLevel(logging.WARNING)
if server_settings["servicename"] != "Mandos":
- syslogger.setFormatter(logging.Formatter\
+ syslogger.setFormatter(logging.Formatter
('Mandos (%s): %%(levelname)s:'
' %%(message)s'
% server_settings["servicename"]))
@@ -783,22 +986,26 @@
except IOError, error:
logger.error("Could not open file %r", pidfilename)
- uid = 65534
- gid = 65534
- try:
- uid = pwd.getpwnam("mandos").pw_uid
- except KeyError:
- try:
- uid = pwd.getpwnam("nobody").pw_uid
- except KeyError:
- pass
- try:
- gid = pwd.getpwnam("mandos").pw_gid
- except KeyError:
- try:
- gid = pwd.getpwnam("nogroup").pw_gid
- except KeyError:
- pass
+ try:
+ uid = pwd.getpwnam("_mandos").pw_uid
+ except KeyError:
+ try:
+ uid = pwd.getpwnam("mandos").pw_uid
+ except KeyError:
+ try:
+ uid = pwd.getpwnam("nobody").pw_uid
+ except KeyError:
+ uid = 65534
+ try:
+ gid = pwd.getpwnam("_mandos").pw_gid
+ except KeyError:
+ try:
+ gid = pwd.getpwnam("mandos").pw_gid
+ except KeyError:
+ try:
+ gid = pwd.getpwnam("nogroup").pw_gid
+ except KeyError:
+ gid = 65534
try:
os.setuid(uid)
os.setgid(gid)
@@ -810,8 +1017,8 @@
service = AvahiService(name = server_settings["servicename"],
servicetype = "_mandos._tcp", )
if server_settings["interface"]:
- service.interface = if_nametoindex\
- (server_settings["interface"])
+ service.interface = (if_nametoindex
+ (server_settings["interface"]))
global main_loop
global bus
@@ -824,15 +1031,9 @@
avahi.DBUS_PATH_SERVER),
avahi.DBUS_INTERFACE_SERVER)
# End of Avahi example code
-
- def remove_from_clients(client):
- clients.remove(client)
- if not clients:
- logger.critical(u"No clients left, exiting")
- sys.exit()
+ bus_name = dbus.service.BusName(u"org.mandos-system.Mandos", bus)
clients.update(Set(Client(name = section,
- stop_hook = remove_from_clients,
config
= dict(client_config.items(section)))
for section in client_config.sections()))
@@ -886,7 +1087,51 @@
signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
+ class MandosServer(dbus.service.Object):
+ """A D-Bus proxy object"""
+ def __init__(self):
+ dbus.service.Object.__init__(self, bus,
+ "/Mandos")
+ _interface = u"org.mandos_system.Mandos"
+
+ @dbus.service.signal(_interface, signature="oa{sv}")
+ def ClientAdded(self, objpath, properties):
+ "D-Bus signal"
+ pass
+
+ @dbus.service.signal(_interface, signature="o")
+ def ClientRemoved(self, objpath):
+ "D-Bus signal"
+ pass
+
+ @dbus.service.method(_interface, out_signature="ao")
+ def GetAllClients(self):
+ return dbus.Array(c.dbus_object_path for c in clients)
+
+ @dbus.service.method(_interface, out_signature="a{oa{sv}}")
+ def GetAllClientsWithProperties(self):
+ return dbus.Dictionary(
+ ((c.dbus_object_path, c.GetAllProperties())
+ for c in clients),
+ signature="oa{sv}")
+
+ @dbus.service.method(_interface, in_signature="o")
+ def RemoveClient(self, object_path):
+ for c in clients:
+ if c.dbus_object_path == object_path:
+ c.stop()
+ clients.remove(c)
+ return
+ raise KeyError
+
+ del _interface
+
+ mandos_server = MandosServer()
+
for client in clients:
+ # Emit D-Bus signal
+ mandos_server.ClientAdded(client.dbus_object_path,
+ client.GetAllProperties())
client.start()
tcp_server.enable()
@@ -911,8 +1156,8 @@
gobject.io_add_watch(tcp_server.fileno(), gobject.IO_IN,
lambda *args, **kwargs:
- tcp_server.handle_request\
- (*args[2:], **kwargs) or True)
+ (tcp_server.handle_request
+ (*args[2:], **kwargs) or True))
logger.debug(u"Starting main loop")
main_loop.run()
=== modified file 'mandos-keygen'
--- mandos-keygen 2008-10-17 18:56:25 +0000
+++ mandos-keygen 2008-11-11 16:07:18 +0000
@@ -2,7 +2,8 @@
#
# Mandos key generator - create a new OpenPGP key for a Mandos client
#
-# Copyright © 2008 Teddy Hogeborn & Björn Påhlsson
+# Copyright © 2008 Teddy Hogeborn
+# Copyright © 2008 Björn Påhlsson
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
=== modified file 'mandos.lsm'
--- mandos.lsm 2008-10-18 10:58:29 +0000
+++ mandos.lsm 2008-12-10 01:26:02 +0000
@@ -1,7 +1,7 @@
Begin4
Title: Mandos
Version: 1.0.2
-Entered-date: 2008-10-18
+Entered-date: 2008-10-28
Description: The Mandos system allows computers to have encrypted
root file systems and at the same time be capable of remote and/or
unattended reboots.
=== modified file 'plugin-runner.c'
--- plugin-runner.c 2008-11-01 02:26:00 +0000
+++ plugin-runner.c 2008-11-11 16:07:18 +0000
@@ -2,7 +2,8 @@
/*
* Mandos plugin runner - Run Mandos plugins
*
- * Copyright © 2008 Teddy Hogeborn & Björn Påhlsson
+ * Copyright © 2008 Teddy Hogeborn
+ * Copyright © 2008 Björn Påhlsson
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
=== modified file 'plugins.d/askpass-fifo.c'
--- plugins.d/askpass-fifo.c 2008-09-26 19:47:21 +0000
+++ plugins.d/askpass-fifo.c 2008-11-11 16:07:18 +0000
@@ -1,3 +1,28 @@
+/* -*- coding: utf-8 -*- */
+/*
+ * Passprompt - Read a password from a FIFO and output it
+ *
+ * Copyright © 2008 Teddy Hogeborn
+ * Copyright © 2008 Björn Påhlsson
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * .
+ *
+ * Contact the authors at and
+ * .
+ */
+
#define _GNU_SOURCE /* TEMP_FAILURE_RETRY() */
#include /* ssize_t */
#include /* mkfifo(), S_IRUSR, S_IWUSR */
=== modified file 'plugins.d/mandos-client.c'
--- plugins.d/mandos-client.c 2008-09-30 07:23:39 +0000
+++ plugins.d/mandos-client.c 2008-11-11 16:07:18 +0000
@@ -9,7 +9,8 @@
* "browse_callback", and parts of "main".
*
* Everything else is
- * Copyright © 2008 Teddy Hogeborn & Björn Påhlsson
+ * Copyright © 2008 Teddy Hogeborn
+ * Copyright © 2008 Björn Påhlsson
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
=== modified file 'plugins.d/password-prompt.c'
--- plugins.d/password-prompt.c 2008-09-30 07:23:39 +0000
+++ plugins.d/password-prompt.c 2008-11-11 16:07:18 +0000
@@ -1,8 +1,9 @@
/* -*- coding: utf-8 -*- */
/*
* Passprompt - Read a password from the terminal and print it
- *
- * Copyright © 2008 Teddy Hogeborn & Björn Påhlsson
+ *
+ * Copyright © 2008 Teddy Hogeborn
+ * Copyright © 2008 Björn Påhlsson
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
=== modified file 'plugins.d/splashy.c'
--- plugins.d/splashy.c 2008-10-03 09:32:30 +0000
+++ plugins.d/splashy.c 2008-11-11 16:07:18 +0000
@@ -1,3 +1,28 @@
+/* -*- coding: utf-8 -*- */
+/*
+ * Passprompt - Read a password from splashy and output it
+ *
+ * Copyright © 2008 Teddy Hogeborn
+ * Copyright © 2008 Björn Påhlsson
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * .
+ *
+ * Contact the authors at and
+ * .
+ */
+
#define _GNU_SOURCE /* asprintf() */
#include /* sig_atomic_t, struct sigaction,
sigemptyset(), sigaddset(), SIGINT,
=== modified file 'plugins.d/usplash.c'
--- plugins.d/usplash.c 2008-10-03 09:32:30 +0000
+++ plugins.d/usplash.c 2008-11-11 16:07:18 +0000
@@ -1,3 +1,28 @@
+/* -*- coding: utf-8 -*- */
+/*
+ * Passprompt - Read a password from usplash and output it
+ *
+ * Copyright © 2008 Teddy Hogeborn
+ * Copyright © 2008 Björn Påhlsson
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * .
+ *
+ * Contact the authors at and
+ * .
+ */
+
#define _GNU_SOURCE /* asprintf() */
#include /* sig_atomic_t, struct sigaction,
sigemptyset(), sigaddset(), SIGINT,