=== modified file 'DBUS-API' --- DBUS-API 2011-03-17 18:14:34 +0000 +++ DBUS-API 2011-10-02 19:18:24 +0000 @@ -5,7 +5,7 @@ This file documents the D-Bus interface to the Mandos server. * Bus: System bus - Bus name: "se.bsnet.fukt.Mandos" + Bus name: "se.recompile.Mandos" * Object Paths: @@ -17,7 +17,7 @@ * Mandos Server Interface: - Interface name: "se.bsnet.fukt.Mandos" + Interface name: "se.recompile.Mandos" ** Methods: *** GetAllClients() → (ao: Clients) @@ -44,7 +44,7 @@ * Mandos Client Interface: - Interface name: "se.bsnet.fukt.Mandos.Client" + Interface name: "se.recompile.Mandos.Client" ** Methods *** Approve(b: Approve) → nothing @@ -86,15 +86,17 @@ | CheckerRunning (c) | b | Read/Write | N/A | | Created (d) | s | Read | N/A | | Enabled (e) | b | Read/Write | N/A | + | Expires (f) | s | Read | N/A | + | ExtendedTimeout (a) | t | Read/Write | extended_timeout | | Fingerprint | s | Read | fingerprint | | Host | s | Read/Write | host | | Interval (a) | t | Read/Write | interval | - | LastApprovalRequest (f) | s | Read | N/A | - | LastCheckedOK (g) | s | Read/Write | N/A | - | LastEnabled (h) | s | Read | N/A | + | LastApprovalRequest (g) | s | Read | N/A | + | LastCheckedOK (h) | s | Read/Write | N/A | + | LastEnabled (i) | s | Read | N/A | | Name | s | Read | (Section name) | | ObjectPath | o | Read | N/A | - | Secret (i) | ay | Write | secret (or secfile) | + | Secret (j) | ay | Write | secret (or secfile) | | Timeout (a) | t | Read/Write | timeout | a) Represented as milliseconds. @@ -109,20 +111,23 @@ e) Setting this property is equivalent to calling Enable() or Disable(). - f) The time of the last approval request, as an RFC 3339 string, or - an empty string if this has not happened. - - g) The last time a checker was successful, as an RFC 3339 string, - or an empty string if this has not happened. Setting this - property is equivalent to calling CheckedOK(), i.e. the current - time is set, regardless of the string sent. Please always use - an empty string when setting this property, to allow for - possible future expansion. - - h) The last time this client was enabled, as an RFC 3339 string, or - an empty string if this has not happened. - - i) A raw byte array, not hexadecimal digits. + f) The date and time this client will be disabled, as an RFC 3339 + string, or an empty string if this has not happened. + + g) The date and time of the last approval request, as an RFC 3339 + string, or an empty string if this has not happened. + + h) The date and time a checker was last successful, as an RFC 3339 + string, or an empty string if this has not happened. Setting + this property is equivalent to calling CheckedOK(), i.e. the + current time is set, regardless of the string sent. Please + always use an empty string when setting this property, to allow + for possible future expansion. + + i) The date and time this client was last enabled, as an RFC 3339 + string, or an empty string if this has not happened. + + j) A raw byte array, not hexadecimal digits. ** Signals *** CheckerCompleted(n: Exitcode, x: Waitstatus, s: Command) === modified file 'Makefile' --- Makefile 2011-07-27 17:58:27 +0000 +++ Makefile 2011-10-05 16:56:06 +0000 @@ -5,7 +5,7 @@ -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings \ -Wconversion -Wstrict-prototypes -Wold-style-definition \ -Wpacked -Wnested-externs -Winline -Wvolatile-register-var -# -Wunreachable-code +# -Wunreachable-code #DEBUG=-ggdb3 # For info about _FORTIFY_SOURCE, see # @@ -54,7 +54,7 @@ CFLAGS=$(WARN) $(DEBUG) $(FORTIFY) $(COVERAGE) $(OPTIMIZE) \ $(LANGUAGE) $(GNUTLS_CFLAGS) $(AVAHI_CFLAGS) $(GPGME_CFLAGS) \ -DVERSION='"$(version)"' -LDFLAGS=$(COVERAGE) $(LINK_FORTIFY) $(foreach flag,$(LINK_FORTIFY_LD),-Xlinker $(flag)) +LDFLAGS=-Xlinker --as-needed $(COVERAGE) $(LINK_FORTIFY) $(foreach flag,$(LINK_FORTIFY_LD),-Xlinker $(flag)) # Commands to format a DocBook document into a manual page DOCBOOKTOMAN=$(strip cd $(dir $<); xsltproc --nonet --xinclude \ @@ -92,7 +92,7 @@ plugins.d/mandos-client.8mandos \ plugins.d/password-prompt.8mandos plugins.d/usplash.8mandos \ plugins.d/splashy.8mandos plugins.d/askpass-fifo.8mandos \ - plugins.d/plymouth.8mandos + plugins.d/plymouth.8mandos intro.8mandos htmldocs=$(addsuffix .xhtml,$(DOCS)) @@ -119,6 +119,11 @@ %.8mandos.xhtml: %.xml common.ent legalnotice.xml $(DOCBOOKTOHTML) +intro.8mandos: intro.xml common.ent legalnotice.xml + $(DOCBOOKTOMAN) +intro.8mandos.xhtml: intro.xml common.ent legalnotice.xml + $(DOCBOOKTOHTML) + mandos.8: mandos.xml common.ent mandos-options.xml overview.xml \ legalnotice.xml $(DOCBOOKTOMAN) === modified file 'README' --- README 2011-02-27 17:26:35 +0000 +++ README 2011-10-05 16:00:56 +0000 @@ -1,182 +1,10 @@ --*- org -*- - -* Mandos - - Have your cake and eat it too! - - You know how it is. You’ve heard of it happening. The Man comes - and takes away your servers, your friends’ servers, the servers of - everybody in the same hosting facility. The servers of their - neighbors, and their neighbors’ friends. The servers of people who - owe them money. And like *that*, they’re gone. And you doubt - you’ll ever see them again. - - That is why your servers have encrypted root file systems. However, - there’s a downside. There’s no going around it: rebooting is a - pain. Dragging out that rarely-used keyboard and screen and - unraveling cables behind your servers to plug them in to type in - that password is messy, especially if you have many servers. There - are some people who do clever things like using serial line consoles - and daisy-chain it to the next server, and keep all the servers - connected in a ring with serial cables, which will work, if your - servers are physically close enough. There are also other - out-of-band management solutions, but with *all* these, you still - have to be on hand and manually type in the password at boot time. - Otherwise the server just sits there, waiting for a password. - - Wouldn’t it be great if you could have the security of encrypted - root file systems and still have servers that could boot up - automatically if there was a short power outage while you were - asleep? That you could reboot at will, without having someone run - over to the server to type in the password? - - Well, with Mandos, you (almost) can! The gain in convenience will - only be offset by a small loss in security. The setup is as - follows: - - The server will still have its encrypted root file system. The - password to this file system will be stored on another computer - (henceforth known as the Mandos server) on the same local network. - The password will *not* be stored in plaintext, but encrypted with - OpenPGP. To decrypt this password, a key is needed. This key (the - Mandos client key) will not be stored there, but back on the - original server (henceforth known as the Mandos client) in the - initial RAM disk image. Oh, and all network Mandos client/server - communications will be encrypted, using TLS (SSL). - - So, at boot time, the Mandos client will ask for its encrypted data - over the network, decrypt it to get the password, use it to decrypt - the root file, and continue booting. - - Now, of course the initial RAM disk image is not on the encrypted - root file system, so anyone who had physical access could take the - Mandos client computer offline and read the disk with their own - tools to get the authentication keys used by a client. *But*, by - then the Mandos server should notice that the original server has - been offline for too long, and will no longer give out the encrypted - key. The timing here is the only real weak point, and the method, - frequency and timeout of the server’s checking can be adjusted to - any desired level of paranoia - - (The encrypted keys on the Mandos server is on its normal file - system, so those are safe, provided the root file system of *that* - server is encrypted.) - -* FAQ - couldn’t the security be defeated by... - -** Grabbing the Mandos client key from the initrd *really quickly*? - This, as mentioned above, is the only real weak point. But if you - set the timing values tight enough, this will be really difficult - to do. An attacker would have to physically disassemble the client - computer, extract the key from the initial RAM disk image, and then - connect to a *still online* Mandos server to get the encrypted key, - and do all this *before* the Mandos server timeout kicks in and the - Mandos server refuses to give out the key to anyone. - - Now, as the typical procedure seems to be to barge in and turn off - and grab *all* computers, to maybe look at them months later, this - is not likely. If someone does that, the whole system *will* lock - itself up completely, since Mandos servers are no longer running. - - For sophisticated attackers who *could* do the clever thing, *and* - had physical access to the server for enough time, it would be - simpler to get a key for an encrypted file system by using hardware - memory scanners and reading it right off the memory bus. - -** Replay attacks? - Nope, the network stuff is all done over TLS, which provides - protection against that. - -** Man-in-the-middle? - No. The server only gives out the passwords to clients which have - *in the TLS handshake* proven that they do indeed hold the OpenPGP - private key corresponding to that client. - -** Physically grabbing the Mandos server computer? - You could protect *that* computer the old-fashioned way, with a - must-type-in-the-password-at-boot method. Or you could have two - computers be the Mandos server for each other. - - Multiple Mandos servers can coexist on a network without any - trouble. They do not clash, and clients will try all available - servers. This means that if just one reboots then the other can - bring it back up, but if both reboot at the same time they will - stay down until someone types in the password on one of them. - -** Faking ping replies? - The default for the server is to use "fping", the replies to which - could be faked to eliminate the timeout. But this could easily be - changed to any shell command, with any security measures you like. - It could, for instance, be changed to an SSH command with strict - keychecking, which could not be faked. Or IPsec could be used for - the ping packets, making them secure. - -* Security Summary - So, in summary: The only weakness in the Mandos system is from - people who have: - 1. The power to come in and physically take your servers, *and* - 2. The cunning and patience to do it carefully, one at a time, and - *quickly*, faking Mandos client/server responses for each one - before the timeout. - - While there are some who may be threatened by people who have *both* - these attributes, they do not, probably, constitute the majority. - - If you *do* face such opponents, you must figure that they could - just as well open your servers and read the file system keys right - off the memory by running wires to the memory bus. - - What Mandos is designed to protect against is *not* such determined, - focused, and competent attacks, but against the early morning knock - on your door and the sudden absence of all the servers in your - server room. Which it does nicely. - -* The Plugin System - In the early designs, the mandos-client(8mandos) program (which - retrieves a password from the Mandos server) also prompted for a - password on the terminal, in case a Mandos server could not be - found. Other ways of retrieving a password could easily be - envisoned, but this multiplicity of purpose was seen to be too - complex to be a viable way to continue. Instead, the original - program was separated into mandos-client(8mandos) and - password-prompt(8mandos), and a plugin-runner(8mandos) exist to run - them both in parallel, allowing the first successful plugin to - provide the password. This opened up for any number of additional - plugins to run, all competing to be the first to find a password and - provide it to the plugin runner. - - Four additional plugins are provided: - * plymouth(8mandos) - This prompts for a password when using plymouth(8). - * usplash(8mandos) - This prompts for a password when using usplash(8). - * splashy(8mandos) - This prompts for a password when using splashy(8). - * askpass-fifo(8mandos) - To provide compatibility with the "askpass" program from - cryptsetup, this plugin listens to the same FIFO as askpass would - do. - - More plugins can easily be written and added by the system - administrator; see the section called "WRITING PLUGINS" in - plugin-runner(8mandos) to learn the plugin requirements. - -* Copyright - - Copyright © 2008-2011 Teddy Hogeborn - Copyright © 2008-2011 Björn Påhlsson - -** License: - - 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 - . +Please see: http://www.recompile.se/mandos/man/intro.8mandos + +This information previously in this file has been moved to the +intro(8mandos) manual page. Go to the above URL, or run this command: + + man 8mandos intro + +In short, this is the Mandos system; it allows computers to have +encrypted root file systems and at the same time be capable of remote +and/or unattended reboots. === modified file 'TODO' --- TODO 2011-07-25 18:47:45 +0000 +++ TODO 2011-10-09 15:21:16 +0000 @@ -2,21 +2,21 @@ * Use _attribute_((nonnull)) wherever possible. +* [[http://www.undeadly.org/cgi?action=article&sid=20110530221728][OpenBSD]] + * mandos-applet -* Convert README into intro(8mandos) man page - * mandos-client ** TODO [#B] Use capabilities instead of seteuid(). ** TODO [#B] Use struct sockaddr_storage instead of a union ** TODO [#B] Use getaddrinfo(hints=AI_NUMERICHOST) instead of inet_pton() ** TODO [#B] Use getnameinfo(serv=NULL, NI_NUMERICHOST) instead of inet_ntop() -** TODO [#B] Accept [] around IPv6 address in --connect option; see [[http://tools.ietf.org/html/rfc5952][RFC 5952 - A Recommendation for IPv6 Address Text Representation]] +** TODO [#B] Prefer /run/tmp over /tmp, if it exists * splashy ** TODO [#B] use scandir(3) instead of readdir(3) -* usplash +* usplash (Deprecated) ** TODO [#A] Make it work again ** TODO [#B] use scandir(3) instead of readdir(3) ** TODO Use [[info:libc:Argz%20Functions][argz_extract]] @@ -58,21 +58,8 @@ ** TODO [#C] DBusServiceObjectUsingSuper ** TODO [#B] Global enable/disable flag ** TODO [#B] By-client countdown on secrets given -** TODO [#B] Fix problem with fsck taking a really long time - Whenever a client successfully gets a secret it could get a - one-time timeout boost to allow for an fsck-incurred delay -** TODO [#A] Delay before client receives key - This would give an operator opportunity to cancel the request if - desired. -** TODO [#A] Client manual approval mode - A client needs manual approval on the server before it gets the - secret ** TODO [#B] Support RFC 3339 time duration syntax ** More D-Bus methods -*** NeedsApproval(50, True) -> timeout, default approve - Default approval is configurable, but True by default - + Approve(True) -> approve sending saved - + Approve(False) -> Close client connection immediately *** NeedsPassword(50) - Timeout, default disapprove + SetPass(u"gazonk", True) -> Approval, persistent + Approve(False) -> Close client connection immediately @@ -109,15 +96,12 @@ ** Show timeout countdown for approval * mandos-keygen -** TODO Loop until passwords match when run interactively ** TODO "--secfile" option Using the "secfile" option instead of "secret" ** TODO [#B] "--test" option For testing decryption before rebooting. * Makefile -** TODO Add "--Xlinker --as-needed" - http://udrepper.livejournal.com/19395.html ** TODO [#C] Implement DEB_BUILD_OPTIONS http://www.debian.org/doc/debian-policy/ch-source.html#s-debianrules-options @@ -130,8 +114,8 @@ From XML sources directly? * Side Stuff -** TODO Locate which packet move the other bin/sh when busy box is deactivated -** TODO contact owner of packet, and ask them to have that shell static in position regardless of busybox +** TODO Locate which package moves the other bin/sh when busybox is deactivated +** TODO contact owner of package, and ask them to have that shell static in position regardless of busybox #+STARTUP: showall === modified file 'clients.conf' --- clients.conf 2010-09-12 03:00:40 +0000 +++ clients.conf 2011-09-19 09:42:55 +0000 @@ -4,14 +4,19 @@ # How long until a client is disabled and not be allowed to get the # data this server holds. -;timeout = 1h +;timeout = 5m # How often to run the checker to confirm that a client is still up. # Note: a new checker will not be started if an old one is still # running. The server will wait for a checker to complete until the # above "timeout" occurs, at which time the client will be disabled, # and any running checker killed. -;interval = 5m +;interval = 2m + +# Extended timeout is an added timeout that is given once after a +# password has been sent sucessfully to a client. This allows for +# additional delays caused by file system checks and quota checks. +;extended_timeout = 15m # What command to run as "the checker". ;checker = fping -q -- %%(host)s @@ -70,7 +75,7 @@ ;host = 192.0.2.3 ; ;# Parameters from the [DEFAULT] section can be overridden per client. -;interval = 5m +;interval = 1m ; ;# This client requires manual approval before it receives its secret. ;approved_by_default = False === modified file 'dbus-mandos.conf' --- dbus-mandos.conf 2009-11-09 07:35:16 +0000 +++ dbus-mandos.conf 2011-10-02 19:18:24 +0000 @@ -7,12 +7,18 @@ + + + + + + === modified file 'debian/control' --- debian/control 2011-03-17 18:13:40 +0000 +++ debian/control 2011-10-05 17:03:36 +0000 @@ -1,16 +1,17 @@ Source: mandos Section: admin Priority: extra -Maintainer: Mandos Maintainers -Uploaders: Teddy Hogeborn , - Björn Påhlsson +Maintainer: Mandos Maintainers +Uploaders: Teddy Hogeborn , + Björn Påhlsson Build-Depends: debhelper (>= 7), docbook-xml, docbook-xsl, libavahi-core-dev, libgpgme11-dev, libgnutls-dev, xsltproc, pkg-config -Standards-Version: 3.9.1 -Vcs-Bzr: http://ftp.fukt.bsnet.se/pub/mandos/trunk -Vcs-Browser: http://bzr.fukt.bsnet.se/loggerhead/mandos/trunk/files -Homepage: http://www.fukt.bsnet.se/mandos +Standards-Version: 3.9.2 +Vcs-Bzr: http://ftp.recompile.se/pub/mandos/trunk +Vcs-Browser: http://bzr.recompile.se/loggerhead/mandos/trunk/files +Homepage: http://www.recompile.se/mandos +DM-Upload-Allowed: yes Package: mandos Architecture: all @@ -18,7 +19,7 @@ python-avahi, python-gobject, avahi-daemon, adduser, python-urwid, python (>=2.7) | python-argparse Recommends: fping -Description: a server giving encrypted passwords to Mandos clients +Description: server giving encrypted passwords to Mandos clients This is the server part of the Mandos system, which allows computers to have encrypted root file systems and at the same time be capable of remote and/or unattended reboots. === modified file 'debian/copyright' --- debian/copyright 2011-02-27 17:26:35 +0000 +++ debian/copyright 2011-10-05 16:00:56 +0000 @@ -1,8 +1,8 @@ Format-Specification: http://wiki.debian.org/Proposals/CopyrightFormat?action=recall&rev=233 Upstream-Name: Mandos -Upstream-Maintainer: Mandos Maintainers -Upstream-Source: +Upstream-Maintainer: Mandos Maintainers +Upstream-Source: Files: * Copyright: Copyright © 2008-2011 Teddy Hogeborn === modified file 'debian/mandos-client.README.Debian' --- debian/mandos-client.README.Debian 2010-09-27 17:53:53 +0000 +++ debian/mandos-client.README.Debian 2011-10-05 16:00:56 +0000 @@ -1,25 +1,3 @@ -* Choose the Client Network Interface - - Please make sure that the correct network interface is specified in - the DEVICE setting in the "/etc/initramfs-tools/initramfs.conf" - file. If the setting is empty, the interface will be autodetected - at boot time, which may not be correct. *If* the DEVICE setting is - changed, it will be necessary to update the initrd image by running - the command - - update-initramfs -k all -u - - The device can be overridden at boot time on the Linux kernel - command line using the sixth colon-separated field of the "ip=" - option; for exact syntax, read the documentation in the file - "/usr/share/doc/linux-doc-*/Documentation/filesystems/nfsroot.txt", - available in the "linux-doc-*" package. - - Note that since this network interface is used in the initial RAM - disk environment, the network interface *must* exist at that stage. - Thus, the interface can *not* be a pseudo-interface such as "br0" or - "tun0"; instead, a real interface (such as "eth0") must be used. - * Adding a Client Password to the Server The server must be given a password to give back to the client on @@ -46,6 +24,34 @@ it, and output it to standard output. There it can be verified to be the correct password, before rebooting. +* Emergency Escape + + If it ever should be necessary, the Mandos client can be temporarily + prevented from running at startup by passing the parameter + "mandos=off" to the kernel. + +* Specifying a Client Network Interface + + At boot time the network interface to use will by default be + automatically detected. If should result in an incorrect interface, + edit the DEVICE setting in the "/etc/initramfs-tools/initramfs.conf" + file. (The default setting is empty, meaning to autodetect the + interface.) *If* the DEVICE setting is changed, it will be + necessary to update the initrd image by running the command + + update-initramfs -k all -u + + The device can be overridden at boot time on the Linux kernel + command line using the sixth colon-separated field of the "ip=" + option; for exact syntax, read the documentation in the file + "/usr/share/doc/linux-doc-*/Documentation/filesystems/nfsroot.txt", + available in the "linux-doc-*" package. + + Note that since this network interface is used in the initial RAM + disk environment, the network interface *must* exist at that stage. + Thus, the interface can *not* be a pseudo-interface such as "br0" or + "tun0"; instead, only real interface (such as "eth0") can be used. + * User-Supplied Plugins Any plugins found in "/etc/mandos/plugins.d" will override and add @@ -62,19 +68,14 @@ Mandos client will be the new default way for getting a password for the root file system when booting. -* Emergency Escape - - If it ever should be necessary, the Mandos client can be temporarily - prevented from running at startup by passing the parameter - "mandos=off" to the kernel. - * Non-local Connection (Not Using ZeroConf) If the "ip=" kernel command line option is used to specify a complete IP address and device name, as noted above, it then becomes possible to specify a specific IP address and port to connect to, instead of using ZeroConf. The syntax for doing this is - "mandos=connect::". + "mandos=connect::" on the kernel command + line. For very advanced users, it it possible to specify simply "mandos=connect" on the kernel command line to make the system only @@ -83,4 +84,4 @@ work, "--options-for=mandos-client:--connect=
:" needs to be manually added to the file "/etc/mandos/plugin-runner.conf". - -- Teddy Hogeborn , Mon, 27 Sep 2010 19:53:21 +0200 + -- Teddy Hogeborn , Wed, 5 Oct 2011 17:50:22 +0200 === modified file 'debian/mandos.README.Debian' --- debian/mandos.README.Debian 2009-09-08 06:28:20 +0000 +++ debian/mandos.README.Debian 2011-10-05 16:00:56 +0000 @@ -1,10 +1,10 @@ The Mandos server is useless without at least one configured client in /etc/mandos/clients.conf. To create one, install the "mandos-client" -package on a client computer, and run the command +package on a client computer, and, on the client, run the command # mandos-keygen --password -there to get a config file stanza. Append the output of that command -to the file "/etc/mandos/clients.conf" on the Mandos server. +to get a config file stanza. Append the output of that command to the +file "/etc/mandos/clients.conf" on the Mandos server computer. - -- Teddy Hogeborn , Tue, 8 Sep 2009 06:57:45 +0200 + -- Teddy Hogeborn , Wed, 5 Oct 2011 17:51:22 +0200 === added file 'debian/source/local-options' --- debian/source/local-options 1970-01-01 00:00:00 +0000 +++ debian/source/local-options 2011-10-08 21:13:46 +0000 @@ -0,0 +1,1 @@ +--single-debian-patch === modified file 'debian/watch' --- debian/watch 2010-09-15 17:17:46 +0000 +++ debian/watch 2011-10-05 16:00:56 +0000 @@ -1,2 +1,2 @@ version=3 -ftp://ftp.fukt.bsnet.se/pub/mandos/mandos[-_]([^\s]+?)(?:\.orig)?\.tar\.(?:gz|bz2|7z|xz) +ftp://ftp.recompile.se/pub/mandos/mandos[-_]([^\s]+?)(?:\.orig)?\.tar\.(?:gz|bz2|7z|xz) === modified file 'init.d-mandos' --- init.d-mandos 2009-09-16 23:28:39 +0000 +++ init.d-mandos 2011-10-05 16:00:56 +0000 @@ -9,8 +9,8 @@ # Description: Gives encrypted passwords to Mandos clients ### END INIT INFO -# Author: Teddy Hogeborn -# Author: Björn Påhlsson +# Author: Teddy Hogeborn +# Author: Björn Påhlsson # # Please remove the "Author" lines above and replace them # with your own name if you copy and modify this script. === modified file 'initramfs-tools-hook' --- initramfs-tools-hook 2010-09-09 18:16:14 +0000 +++ initramfs-tools-hook 2011-10-05 16:56:06 +0000 @@ -131,7 +131,7 @@ "${DESTDIR}${CONFDIR}/plugin-runner.conf" fi -# Key files +# Key files for file in "$keydir"/*; do if [ -d "$file" ]; then continue === added file 'intro.xml' --- intro.xml 1970-01-01 00:00:00 +0000 +++ intro.xml 2011-10-05 16:00:56 +0000 @@ -0,0 +1,410 @@ + + + +%common; +]> + + + + Mandos Manual + + Mandos + &version; + &TIMESTAMP; + + + Björn + Påhlsson +
+ belorn@recompile.se +
+
+ + Teddy + Hogeborn +
+ teddy@recompile.se +
+
+
+ + 2011 + Teddy Hogeborn + Björn Påhlsson + + +
+ + + intro + 8mandos + + + + intro + + Introduction to the Mandos system + + + + + DESCRIPTION + + This is the the Mandos system, which allows computers to have + encrypted root file systems and at the same time be capable of + remote and/or unattended reboots. + + + The computers run a small client program in the initial RAM disk + environment which will communicate with a server over a network. + All network communication is encrypted using TLS. The clients + are identified by the server using an OpenPGP key; each client + has one unique to it. The server sends the clients an encrypted + password. The encrypted password is decrypted by the clients + using the same OpenPGP key, and the password is then used to + unlock the root file system, whereupon the computers can + continue booting normally. + + + + + INTRODUCTION + + You know how it is. You’ve heard of it happening. The Man + comes and takes away your servers, your friends’ servers, the + servers of everybody in the same hosting facility. The servers + of their neighbors, and their neighbors’ friends. The servers + of people who owe them money. And like + that, they’re gone. And you doubt you’ll + ever see them again. + + + That is why your servers have encrypted root file systems. + However, there’s a downside. There’s no going around it: + rebooting is a pain. Dragging out that rarely-used keyboard and + screen and unraveling cables behind your servers to plug them in + to type in that password is messy, especially if you have many + servers. There are some people who do clever things like using + serial line consoles and daisy-chain it to the next server, and + keep all the servers connected in a ring with serial cables, + which will work, if your servers are physically close enough. + There are also other out-of-band management solutions, but with + all these, you still have to be on hand and + manually type in the password at boot time. Otherwise the + server just sits there, waiting for a password. + + + Wouldn’t it be great if you could have the security of encrypted + root file systems and still have servers that could boot up + automatically if there was a short power outage while you were + asleep? That you could reboot at will, without having someone + run over to the server to type in the password? + + + Well, with Mandos, you (almost) can! The gain in convenience + will only be offset by a small loss in security. The setup is + as follows: + + + The server will still have its encrypted root file system. The + password to this file system will be stored on another computer + (henceforth known as the Mandos server) on the same local + network. The password will not be stored + in plaintext, but encrypted with OpenPGP. To decrypt this + password, a key is needed. This key (the Mandos client key) + will not be stored there, but back on the original server + (henceforth known as the Mandos client) in the initial RAM disk + image. Oh, and all network Mandos client/server communications + will be encrypted, using TLS (SSL). + + + So, at boot time, the Mandos client will ask for its encrypted + data over the network, decrypt it to get the password, use it to + decrypt the root file, and continue booting. + + + Now, of course the initial RAM disk image is not on the + encrypted root file system, so anyone who had physical access + could take the Mandos client computer offline and read the disk + with their own tools to get the authentication keys used by a + client. But, by then the Mandos server + should notice that the original server has been offline for too + long, and will no longer give out the encrypted key. The timing + here is the only real weak point, and the method, frequency and + timeout of the server’s checking can be adjusted to any desired + level of paranoia + + + (The encrypted keys on the Mandos server is on its normal file + system, so those are safe, provided the root file system of + that server is encrypted.) + + + + + FREQUENTLY ASKED QUESTIONS + + Couldn’t the security be defeated by… + + + Grabbing the Mandos client key from the + initrd <emphasis>really quickly</emphasis>? + + This, as mentioned above, is the only real weak point. But if + you set the timing values tight enough, this will be really + difficult to do. An attacker would have to physically + disassemble the client computer, extract the key from the + initial RAM disk image, and then connect to a still + online Mandos server to get the encrypted key, and do + all this before the Mandos server timeout + kicks in and the Mandos server refuses to give out the key to + anyone. + + + Now, as the typical procedure seems to be to barge in and turn + off and grab all computers, to maybe look + at them months later, this is not likely. If someone does that, + the whole system will lock itself up + completely, since Mandos servers are no longer running. + + + For sophisticated attackers who could do + the clever thing, and had physical access + to the server for enough time, it would be simpler to get a key + for an encrypted file system by using hardware memory scanners + and reading it right off the memory bus. + + + + + Replay attacks? + + Nope, the network stuff is all done over TLS, which provides + protection against that. + + + + + Man-in-the-middle? + + No. The server only gives out the passwords to clients which + have in the TLS handshake proven that + they do indeed hold the OpenPGP private key corresponding to + that client. + + + + + Physically grabbing the Mandos server computer? + + You could protect that computer the + old-fashioned way, with a must-type-in-the-password-at-boot + method. Or you could have two computers be the Mandos server + for each other. + + + Multiple Mandos servers can coexist on a network without any + trouble. They do not clash, and clients will try all + available servers. This means that if just one reboots then + the other can bring it back up, but if both reboot at the same + time they will stay down until someone types in the password + on one of them. + + + + + Faking ping replies? + + The default for the server is to use + fping, the replies to which + could be faked to eliminate the timeout. But this could + easily be changed to any shell command, with any security + measures you like. It could, for instance, be changed to an + SSH command with strict keychecking, which could not be faked. + Or IPsec could be used for the ping packets, making them + secure. + + + + + + SECURITY + + So, in summary: The only weakness in the Mandos system is from + people who have: + + + + + The power to come in and physically take your servers, + and + + + + + The cunning and patience to do it carefully, one at a time, + and quickly, faking Mandos + client/server responses for each one before the timeout. + + + + + While there are some who may be threatened by people who have + both these attributes, they do not, + probably, constitute the majority. + + + If you do face such opponents, you must + figure that they could just as well open your servers and read + the file system keys right off the memory by running wires to + the memory bus. + + + What Mandos is designed to protect against is + not such determined, focused, and competent + attacks, but against the early morning knock on your door and + the sudden absence of all the servers in your server room. + Which it does nicely. + + + + + PLUGINS + + In the early designs, the + mandos-client8mandos program (which + retrieves a password from the Mandos server) also prompted for a + password on the terminal, in case a Mandos server could not be + found. Other ways of retrieving a password could easily be + envisoned, but this multiplicity of purpose was seen to be too + complex to be a viable way to continue. Instead, the original + program was separated into mandos-client8mandos and password-prompt8mandos, and a plugin-runner8mandos exist to run them both in parallel, allowing + the first successful plugin to provide the password. This + opened up for any number of additional plugins to run, all + competing to be the first to find a password and provide it to + the plugin runner. + + + Four additional plugins are provided: + + + + + plymouth + 8mandos + + + + This prompts for a password when using + plymouth8. + + + + + + usplash + 8mandos + + + + This prompts for a password when using + usplash8. + + + + + + splashy + 8mandos + + + + This prompts for a password when using + splashy8. + + + + + + askpass-fifo + 8mandos + + + + To provide compatibility with the "askpass" program from + cryptsetup, this plugin listens to the same FIFO as + askpass would do. + + + + + + More plugins can easily be written and added by the system + administrator; see the section called "WRITING PLUGINS" in + plugin-runner + 8mandos to learn the + plugin requirements. + + + + + SEE ALSO + + mandos + 8, + mandos.conf + 5, + mandos-clients.conf + 5, + mandos-ctl + 8, + mandos-monitor + 8, + plugin-runner + 8mandos, + mandos-client + 8mandos, + password-prompt + 8mandos, + plymouth + 8mandos, + usplash + 8mandos, + splashy + 8mandos, + askpass-fifo + 8mandos, + mandos-keygen + 8 + + + + + Mandos + + + + The Mandos home page. + + + + + +
+ + + + + === modified file 'mandos' --- mandos 2011-07-27 17:58:27 +0000 +++ mandos 2011-10-09 15:19:47 +0000 @@ -28,7 +28,7 @@ # along with this program. If not, see # . # -# Contact the authors at . +# Contact the authors at . # from __future__ import (division, absolute_import, print_function, @@ -62,6 +62,7 @@ import functools import cPickle as pickle import multiprocessing +import types import dbus import dbus.service @@ -159,7 +160,8 @@ " after %i retries, exiting.", self.rename_count) raise AvahiServiceError("Too many renames") - self.name = unicode(self.server.GetAlternativeServiceName(self.name)) + self.name = unicode(self.server + .GetAlternativeServiceName(self.name)) logger.info("Changing Zeroconf service name to %r ...", self.name) syslogger.setFormatter(logging.Formatter @@ -264,6 +266,12 @@ self.server_state_changed(self.server.GetState()) +def _timedelta_to_milliseconds(td): + "Convert a datetime.timedelta() to milliseconds" + return ((td.days * 24 * 60 * 60 * 1000) + + (td.seconds * 1000) + + (td.microseconds // 1000)) + class Client(object): """A representation of a client host served by this server. @@ -297,7 +305,10 @@ secret: bytestring; sent verbatim (over TLS) to client timeout: datetime.timedelta(); How long from last_checked_ok until this client is disabled + extended_timeout: extra long timeout when password has been sent runtime_expansions: Allowed attributes for runtime expansion. + expires: datetime.datetime(); time (UTC) when a client will be + disabled, or None """ runtime_expansions = ("approval_delay", "approval_duration", @@ -305,23 +316,20 @@ "host", "interval", "last_checked_ok", "last_enabled", "name", "timeout") - @staticmethod - def _timedelta_to_milliseconds(td): - "Convert a datetime.timedelta() to milliseconds" - return ((td.days * 24 * 60 * 60 * 1000) - + (td.seconds * 1000) - + (td.microseconds // 1000)) - def timeout_milliseconds(self): "Return the 'timeout' attribute in milliseconds" - return self._timedelta_to_milliseconds(self.timeout) + return _timedelta_to_milliseconds(self.timeout) + + def extended_timeout_milliseconds(self): + "Return the 'extended_timeout' attribute in milliseconds" + return _timedelta_to_milliseconds(self.extended_timeout) def interval_milliseconds(self): "Return the 'interval' attribute in milliseconds" - return self._timedelta_to_milliseconds(self.interval) - + return _timedelta_to_milliseconds(self.interval) + def approval_delay_milliseconds(self): - return self._timedelta_to_milliseconds(self.approval_delay) + return _timedelta_to_milliseconds(self.approval_delay) def __init__(self, name = None, disable_hook=None, config=None): """Note: the 'checker' key in 'config' sets the @@ -354,11 +362,14 @@ self.last_enabled = None self.last_checked_ok = None self.timeout = string_to_delta(config["timeout"]) + self.extended_timeout = string_to_delta(config + ["extended_timeout"]) self.interval = string_to_delta(config["interval"]) self.disable_hook = disable_hook self.checker = None self.checker_initiator_tag = None self.disable_initiator_tag = None + self.expires = None self.checker_callback_tag = None self.checker_command = config["checker"] self.current_checker_command = None @@ -371,30 +382,33 @@ config["approval_delay"]) self.approval_duration = string_to_delta( config["approval_duration"]) - self.changedstate = multiprocessing_manager.Condition(multiprocessing_manager.Lock()) + self.changedstate = (multiprocessing_manager + .Condition(multiprocessing_manager + .Lock())) def send_changedstate(self): self.changedstate.acquire() self.changedstate.notify_all() self.changedstate.release() - + def enable(self): """Start this client's checker and timeout hooks""" if getattr(self, "enabled", False): # Already enabled return self.send_changedstate() - self.last_enabled = 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)) # Schedule a disable() when 'timeout' has passed + self.expires = datetime.datetime.utcnow() + self.timeout self.disable_initiator_tag = (gobject.timeout_add (self.timeout_milliseconds(), self.disable)) self.enabled = True + self.last_enabled = datetime.datetime.utcnow() # Also start a new checker *right now*. self.start_checker() @@ -409,6 +423,7 @@ if getattr(self, "disable_initiator_tag", False): gobject.source_remove(self.disable_initiator_tag) self.disable_initiator_tag = None + self.expires = None if getattr(self, "checker_initiator_tag", False): gobject.source_remove(self.checker_initiator_tag) self.checker_initiator_tag = None @@ -440,17 +455,20 @@ logger.warning("Checker for %(name)s crashed?", vars(self)) - def checked_ok(self): + def checked_ok(self, timeout=None): """Bump up the timeout for this client. This should only be called when the client has been seen, alive and well. """ + if timeout is None: + timeout = self.timeout self.last_checked_ok = datetime.datetime.utcnow() gobject.source_remove(self.disable_initiator_tag) self.disable_initiator_tag = (gobject.timeout_add - (self.timeout_milliseconds(), - self.disable)) + (_timedelta_to_milliseconds + (timeout), self.disable)) + self.expires = datetime.datetime.utcnow() + timeout def need_approval(self): self.last_approval_request = datetime.datetime.utcnow() @@ -496,7 +514,7 @@ 'replace'))) for attr in self.runtime_expansions) - + try: command = self.checker_command % escaped_attrs except TypeError as error: @@ -548,6 +566,7 @@ raise self.checker = None + def dbus_service_property(dbus_interface, signature="v", access="readwrite", byte_arrays=False): """Decorators for marking methods of a DBusObjectWithProperties to @@ -599,7 +618,7 @@ class DBusObjectWithProperties(dbus.service.Object): """A D-Bus object with properties. - + Classes inheriting from this can use the dbus_service_property decorator to expose methods as D-Bus properties. It exposes the standard Get(), Set(), and GetAll() methods on the D-Bus. @@ -612,24 +631,22 @@ def _get_all_dbus_properties(self): """Returns a generator of (name, attribute) pairs """ - return ((prop._dbus_name, prop) + return ((prop.__get__(self)._dbus_name, prop.__get__(self)) + for cls in self.__class__.__mro__ for name, prop in - inspect.getmembers(self, self._is_dbus_property)) + inspect.getmembers(cls, self._is_dbus_property)) def _get_dbus_property(self, interface_name, property_name): """Returns a bound method if one exists which is a D-Bus property with the specified name and interface. """ - for name in (property_name, - property_name + "_dbus_property"): - prop = getattr(self, name, None) - if (prop is None - or not self._is_dbus_property(prop) - or prop._dbus_name != property_name - or (interface_name and prop._dbus_interface - and interface_name != prop._dbus_interface)): - continue - return prop + for cls in self.__class__.__mro__: + for name, value in (inspect.getmembers + (cls, self._is_dbus_property)): + if (value._dbus_name == property_name + and value._dbus_interface == interface_name): + return value.__get__(self) + # No such property raise DBusPropertyNotFound(self.dbus_object_path + ":" + interface_name + "." @@ -669,7 +686,7 @@ def GetAll(self, interface_name): """Standard D-Bus property GetAll() method, see D-Bus standard. - + Note: Will not include properties with access="write". """ all = {} @@ -737,6 +754,110 @@ return xmlstring +def datetime_to_dbus (dt, variant_level=0): + """Convert a UTC datetime.datetime() to a D-Bus type.""" + if dt is None: + return dbus.String("", variant_level = variant_level) + return dbus.String(dt.isoformat(), + variant_level=variant_level) + +class AlternateDBusNamesMetaclass(DBusObjectWithProperties + .__metaclass__): + """Applied to an empty subclass of a D-Bus object, this metaclass + will add additional D-Bus attributes matching a certain pattern. + """ + def __new__(mcs, name, bases, attr): + # Go through all the base classes which could have D-Bus + # methods, signals, or properties in them + for base in (b for b in bases + if issubclass(b, dbus.service.Object)): + # Go though all attributes of the base class + for attrname, attribute in inspect.getmembers(base): + # Ignore non-D-Bus attributes, and D-Bus attributes + # with the wrong interface name + if (not hasattr(attribute, "_dbus_interface") + or not attribute._dbus_interface + .startswith("se.recompile.Mandos")): + continue + # Create an alternate D-Bus interface name based on + # the current name + alt_interface = (attribute._dbus_interface + .replace("se.recompile.Mandos", + "se.bsnet.fukt.Mandos")) + # Is this a D-Bus signal? + if getattr(attribute, "_dbus_is_signal", False): + # Extract the original non-method function by + # black magic + nonmethod_func = (dict( + zip(attribute.func_code.co_freevars, + attribute.__closure__))["func"] + .cell_contents) + # Create a new, but exactly alike, function + # object, and decorate it to be a new D-Bus signal + # with the alternate D-Bus interface name + new_function = (dbus.service.signal + (alt_interface, + attribute._dbus_signature) + (types.FunctionType( + nonmethod_func.func_code, + nonmethod_func.func_globals, + nonmethod_func.func_name, + nonmethod_func.func_defaults, + nonmethod_func.func_closure))) + # Define a creator of a function to call both the + # old and new functions, so both the old and new + # signals gets sent when the function is called + def fixscope(func1, func2): + """This function is a scope container to pass + func1 and func2 to the "call_both" function + outside of its arguments""" + def call_both(*args, **kwargs): + """This function will emit two D-Bus + signals by calling func1 and func2""" + func1(*args, **kwargs) + func2(*args, **kwargs) + return call_both + # Create the "call_both" function and add it to + # the class + attr[attrname] = fixscope(attribute, + new_function) + # Is this a D-Bus method? + elif getattr(attribute, "_dbus_is_method", False): + # Create a new, but exactly alike, function + # object. Decorate it to be a new D-Bus method + # with the alternate D-Bus interface name. Add it + # to the class. + attr[attrname] = (dbus.service.method + (alt_interface, + attribute._dbus_in_signature, + attribute._dbus_out_signature) + (types.FunctionType + (attribute.func_code, + attribute.func_globals, + attribute.func_name, + attribute.func_defaults, + attribute.func_closure))) + # Is this a D-Bus property? + elif getattr(attribute, "_dbus_is_property", False): + # Create a new, but exactly alike, function + # object, and decorate it to be a new D-Bus + # property with the alternate D-Bus interface + # name. Add it to the class. + attr[attrname] = (dbus_service_property + (alt_interface, + attribute._dbus_signature, + attribute._dbus_access, + attribute + ._dbus_get_args_options + ["byte_arrays"]) + (types.FunctionType + (attribute.func_code, + attribute.func_globals, + attribute.func_name, + attribute.func_defaults, + attribute.func_closure))) + return type.__new__(mcs, name, bases, attr) + class ClientDBus(Client, DBusObjectWithProperties): """A Client class using D-Bus @@ -764,49 +885,71 @@ DBusObjectWithProperties.__init__(self, self.bus, self.dbus_object_path) - def _get_approvals_pending(self): - return self._approvals_pending - def _set_approvals_pending(self, value): - old_value = self._approvals_pending - self._approvals_pending = value - bval = bool(value) - if (hasattr(self, "dbus_object_path") - and bval is not bool(old_value)): - dbus_bool = dbus.Boolean(bval, variant_level=1) - self.PropertyChanged(dbus.String("ApprovalPending"), - dbus_bool) + def notifychangeproperty(transform_func, + dbus_name, type_func=lambda x: x, + variant_level=1): + """ Modify a variable so that it's a property which announces + its changes to DBus. - approvals_pending = property(_get_approvals_pending, - _set_approvals_pending) - del _get_approvals_pending, _set_approvals_pending - - @staticmethod - def _datetime_to_dbus(dt, variant_level=0): - """Convert a UTC datetime.datetime() to a D-Bus type.""" - return dbus.String(dt.isoformat(), - variant_level=variant_level) - - def enable(self): - oldstate = getattr(self, "enabled", False) - r = Client.enable(self) - if oldstate != self.enabled: - # Emit D-Bus signals - self.PropertyChanged(dbus.String("Enabled"), - dbus.Boolean(True, variant_level=1)) - self.PropertyChanged( - dbus.String("LastEnabled"), - self._datetime_to_dbus(self.last_enabled, - variant_level=1)) - return r - - def disable(self, quiet = False): - oldstate = getattr(self, "enabled", False) - r = Client.disable(self, quiet=quiet) - if not quiet and oldstate != self.enabled: - # Emit D-Bus signal - self.PropertyChanged(dbus.String("Enabled"), - dbus.Boolean(False, variant_level=1)) - return r + transform_fun: Function that takes a value and transforms it + to a D-Bus type. + dbus_name: D-Bus name of the variable + type_func: Function that transform the value before sending it + to the D-Bus. Default: no transform + variant_level: D-Bus variant level. Default: 1 + """ + attrname = "_{0}".format(dbus_name) + def setter(self, value): + if hasattr(self, "dbus_object_path"): + if (not hasattr(self, attrname) or + type_func(getattr(self, attrname, None)) + != type_func(value)): + dbus_value = transform_func(type_func(value), + variant_level) + self.PropertyChanged(dbus.String(dbus_name), + dbus_value) + setattr(self, attrname, value) + + return property(lambda self: getattr(self, attrname), setter) + + + expires = notifychangeproperty(datetime_to_dbus, "Expires") + approvals_pending = notifychangeproperty(dbus.Boolean, + "ApprovalPending", + type_func = bool) + enabled = notifychangeproperty(dbus.Boolean, "Enabled") + last_enabled = notifychangeproperty(datetime_to_dbus, + "LastEnabled") + checker = notifychangeproperty(dbus.Boolean, "CheckerRunning", + type_func = lambda checker: + checker is not None) + last_checked_ok = notifychangeproperty(datetime_to_dbus, + "LastCheckedOK") + last_approval_request = notifychangeproperty( + datetime_to_dbus, "LastApprovalRequest") + approved_by_default = notifychangeproperty(dbus.Boolean, + "ApprovedByDefault") + approval_delay = notifychangeproperty(dbus.UInt16, + "ApprovalDelay", + type_func = + _timedelta_to_milliseconds) + approval_duration = notifychangeproperty( + dbus.UInt16, "ApprovalDuration", + type_func = _timedelta_to_milliseconds) + host = notifychangeproperty(dbus.String, "Host") + timeout = notifychangeproperty(dbus.UInt16, "Timeout", + type_func = + _timedelta_to_milliseconds) + extended_timeout = notifychangeproperty( + dbus.UInt16, "ExtendedTimeout", + type_func = _timedelta_to_milliseconds) + interval = notifychangeproperty(dbus.UInt16, + "Interval", + type_func = + _timedelta_to_milliseconds) + checker_command = notifychangeproperty(dbus.String, "Checker") + + del notifychangeproperty def __del__(self, *args, **kwargs): try: @@ -821,9 +964,6 @@ *args, **kwargs): self.checker_callback_tag = None self.checker = None - # Emit D-Bus signal - self.PropertyChanged(dbus.String("CheckerRunning"), - dbus.Boolean(False, variant_level=1)) if os.WIFEXITED(condition): exitstatus = os.WEXITSTATUS(condition) # Emit D-Bus signal @@ -839,23 +979,6 @@ return Client.checker_callback(self, pid, condition, command, *args, **kwargs) - def checked_ok(self, *args, **kwargs): - Client.checked_ok(self, *args, **kwargs) - # Emit D-Bus signal - self.PropertyChanged( - dbus.String("LastCheckedOK"), - (self._datetime_to_dbus(self.last_checked_ok, - variant_level=1))) - - def need_approval(self, *args, **kwargs): - r = Client.need_approval(self, *args, **kwargs) - # Emit D-Bus signal - self.PropertyChanged( - dbus.String("LastApprovalRequest"), - (self._datetime_to_dbus(self.last_approval_request, - variant_level=1))) - return r - def start_checker(self, *args, **kwargs): old_checker = self.checker if self.checker is not None: @@ -868,20 +991,8 @@ and old_checker_pid != self.checker.pid): # Emit D-Bus signal self.CheckerStarted(self.current_checker_command) - self.PropertyChanged( - dbus.String("CheckerRunning"), - dbus.Boolean(True, variant_level=1)) return r - def stop_checker(self, *args, **kwargs): - old_checker = getattr(self, "checker", None) - r = Client.stop_checker(self, *args, **kwargs) - if (old_checker is not None - and getattr(self, "checker", None) is None): - self.PropertyChanged(dbus.String("CheckerRunning"), - dbus.Boolean(False, variant_level=1)) - return r - def _reset_approved(self): self._approved = None return False @@ -889,13 +1000,13 @@ def approve(self, value=True): self.send_changedstate() self._approved = value - gobject.timeout_add(self._timedelta_to_milliseconds + gobject.timeout_add(_timedelta_to_milliseconds (self.approval_duration), self._reset_approved) ## D-Bus methods, signals & properties - _interface = "se.bsnet.fukt.Mandos.Client" + _interface = "se.recompile.Mandos.Client" ## Signals @@ -987,9 +1098,6 @@ if value is None: # get return dbus.Boolean(self.approved_by_default) self.approved_by_default = bool(value) - # Emit D-Bus signal - self.PropertyChanged(dbus.String("ApprovedByDefault"), - dbus.Boolean(value, variant_level=1)) # ApprovalDelay - property @dbus_service_property(_interface, signature="t", @@ -998,21 +1106,15 @@ if value is None: # get return dbus.UInt64(self.approval_delay_milliseconds()) self.approval_delay = datetime.timedelta(0, 0, 0, value) - # Emit D-Bus signal - self.PropertyChanged(dbus.String("ApprovalDelay"), - dbus.UInt64(value, variant_level=1)) # ApprovalDuration - property @dbus_service_property(_interface, signature="t", access="readwrite") def ApprovalDuration_dbus_property(self, value=None): if value is None: # get - return dbus.UInt64(self._timedelta_to_milliseconds( + return dbus.UInt64(_timedelta_to_milliseconds( self.approval_duration)) self.approval_duration = datetime.timedelta(0, 0, 0, value) - # Emit D-Bus signal - self.PropertyChanged(dbus.String("ApprovalDuration"), - dbus.UInt64(value, variant_level=1)) # Name - property @dbus_service_property(_interface, signature="s", access="read") @@ -1031,21 +1133,16 @@ if value is None: # get return dbus.String(self.host) self.host = value - # Emit D-Bus signal - self.PropertyChanged(dbus.String("Host"), - dbus.String(value, variant_level=1)) # Created - property @dbus_service_property(_interface, signature="s", access="read") def Created_dbus_property(self): - return dbus.String(self._datetime_to_dbus(self.created)) + return dbus.String(datetime_to_dbus(self.created)) # LastEnabled - property @dbus_service_property(_interface, signature="s", access="read") def LastEnabled_dbus_property(self): - if self.last_enabled is None: - return dbus.String("") - return dbus.String(self._datetime_to_dbus(self.last_enabled)) + return datetime_to_dbus(self.last_enabled) # Enabled - property @dbus_service_property(_interface, signature="b", @@ -1065,19 +1162,17 @@ if value is not None: self.checked_ok() return - if self.last_checked_ok is None: - return dbus.String("") - return dbus.String(self._datetime_to_dbus(self - .last_checked_ok)) + return datetime_to_dbus(self.last_checked_ok) + + # Expires - property + @dbus_service_property(_interface, signature="s", access="read") + def Expires_dbus_property(self): + return datetime_to_dbus(self.expires) # LastApprovalRequest - property @dbus_service_property(_interface, signature="s", access="read") def LastApprovalRequest_dbus_property(self): - if self.last_approval_request is None: - return dbus.String("") - return dbus.String(self. - _datetime_to_dbus(self - .last_approval_request)) + return datetime_to_dbus(self.last_approval_request) # Timeout - property @dbus_service_property(_interface, signature="t", @@ -1086,14 +1181,12 @@ if value is None: # get return dbus.UInt64(self.timeout_milliseconds()) self.timeout = datetime.timedelta(0, 0, 0, value) - # Emit D-Bus signal - self.PropertyChanged(dbus.String("Timeout"), - dbus.UInt64(value, variant_level=1)) if getattr(self, "disable_initiator_tag", None) is None: return # Reschedule timeout gobject.source_remove(self.disable_initiator_tag) self.disable_initiator_tag = None + self.expires = None time_to_die = (self. _timedelta_to_milliseconds((self .last_checked_ok @@ -1104,9 +1197,20 @@ # The timeout has passed self.disable() else: + self.expires = (datetime.datetime.utcnow() + + datetime.timedelta(milliseconds = + time_to_die)) self.disable_initiator_tag = (gobject.timeout_add (time_to_die, self.disable)) + # ExtendedTimeout - property + @dbus_service_property(_interface, signature="t", + access="readwrite") + def ExtendedTimeout_dbus_property(self, value=None): + if value is None: # get + return dbus.UInt64(self.extended_timeout_milliseconds()) + self.extended_timeout = datetime.timedelta(0, 0, 0, value) + # Interval - property @dbus_service_property(_interface, signature="t", access="readwrite") @@ -1114,9 +1218,6 @@ if value is None: # get return dbus.UInt64(self.interval_milliseconds()) self.interval = datetime.timedelta(0, 0, 0, value) - # Emit D-Bus signal - self.PropertyChanged(dbus.String("Interval"), - dbus.UInt64(value, variant_level=1)) if getattr(self, "checker_initiator_tag", None) is None: return # Reschedule checker run @@ -1124,7 +1225,7 @@ self.checker_initiator_tag = (gobject.timeout_add (value, self.start_checker)) self.start_checker() # Start one now, too - + # Checker - property @dbus_service_property(_interface, signature="s", access="readwrite") @@ -1132,10 +1233,6 @@ if value is None: # get return dbus.String(self.checker_command) self.checker_command = value - # Emit D-Bus signal - self.PropertyChanged(dbus.String("Checker"), - dbus.String(self.checker_command, - variant_level=1)) # CheckerRunning - property @dbus_service_property(_interface, signature="b", @@ -1168,7 +1265,7 @@ self._pipe.send(('init', fpr, address)) if not self._pipe.recv(): raise KeyError() - + def __getattribute__(self, name): if(name == '_pipe'): return super(ProxyClient, self).__getattribute__(name) @@ -1181,12 +1278,14 @@ self._pipe.send(('funcall', name, args, kwargs)) return self._pipe.recv()[1] return func - + def __setattr__(self, name, value): if(name == '_pipe'): return super(ProxyClient, self).__setattr__(name, value) self._pipe.send(('setattr', name, value)) +class ClientDBusTransitional(ClientDBus): + __metaclass__ = AlternateDBusNamesMetaclass class ClientHandler(socketserver.BaseRequestHandler, object): """A class to handle client connections. @@ -1200,17 +1299,17 @@ unicode(self.client_address)) logger.debug("Pipe FD: %d", self.server.child_pipe.fileno()) - + session = (gnutls.connection .ClientSession(self.request, gnutls.connection .X509Credentials())) - + # Note: gnutls.connection.X509Credentials is really a # generic GnuTLS certificate credentials object so long as # no X.509 keys are added to it. Therefore, we can use it # here despite using OpenPGP certificates. - + #priority = ':'.join(("NONE", "+VERS-TLS1.1", # "+AES-256-CBC", "+SHA1", # "+COMP-NULL", "+CTYPE-OPENPGP", @@ -1222,7 +1321,7 @@ (gnutls.library.functions .gnutls_priority_set_direct(session._c_object, priority, None)) - + # Start communication using the Mandos protocol # Get protocol number line = self.request.makefile().readline() @@ -1233,7 +1332,7 @@ except (ValueError, IndexError, RuntimeError) as error: logger.error("Unknown protocol version: %s", error) return - + # Start GnuTLS connection try: session.handshake() @@ -1243,7 +1342,7 @@ # established. Just abandon the request. return logger.debug("Handshake succeeded") - + approval_required = False try: try: @@ -1254,7 +1353,7 @@ logger.warning("Bad certificate: %s", error) return logger.debug("Fingerprint: %s", fpr) - + try: client = ProxyClient(child_pipe, fpr, self.client_address) @@ -1272,7 +1371,7 @@ client.name) if self.server.use_dbus: # Emit D-Bus signal - client.Rejected("Disabled") + client.Rejected("Disabled") return if client._approved or not client.approval_delay: @@ -1295,10 +1394,11 @@ return #wait until timeout or approved - #x = float(client._timedelta_to_milliseconds(delay)) time = datetime.datetime.now() client.changedstate.acquire() - client.changedstate.wait(float(client._timedelta_to_milliseconds(delay) / 1000)) + (client.changedstate.wait + (float(client._timedelta_to_milliseconds(delay) + / 1000))) client.changedstate.release() time2 = datetime.datetime.now() if (time2 - time) >= delay: @@ -1326,10 +1426,10 @@ sent, len(client.secret) - (sent_size + sent)) sent_size += sent - + logger.info("Sending secret to %s", client.name) # bump the timeout as if seen - client.checked_ok() + client.checked_ok(client.extended_timeout) if self.server.use_dbus: # Emit D-Bus signal client.GotSecret() @@ -1414,11 +1514,15 @@ except: self.handle_error(request, address) self.close_request(request) - + def process_request(self, request, address): """Start a new process to process the request.""" - multiprocessing.Process(target = self.sub_process_main, - args = (request, address)).start() + proc = multiprocessing.Process(target = self.sub_process_main, + args = (request, + address)) + proc.start() + return proc + class MultiprocessingMixInWithPipe(MultiprocessingMixIn, object): """ adds a pipe to the MixIn """ @@ -1428,16 +1532,17 @@ This function creates a new pipe in self.pipe """ parent_pipe, self.child_pipe = multiprocessing.Pipe() - - super(MultiprocessingMixInWithPipe, - self).process_request(request, client_address) + + proc = MultiprocessingMixIn.process_request(self, request, + client_address) self.child_pipe.close() - self.add_pipe(parent_pipe) - - def add_pipe(self, parent_pipe): + self.add_pipe(parent_pipe, proc) + + def add_pipe(self, parent_pipe, proc): """Dummy function; override as necessary""" raise NotImplementedError + class IPv6_TCPServer(MultiprocessingMixInWithPipe, socketserver.TCPServer, object): """IPv6-capable TCP server. Accepts 'None' as address and/or port @@ -1527,17 +1632,21 @@ def server_activate(self): if self.enabled: return socketserver.TCPServer.server_activate(self) + def enable(self): self.enabled = True - def add_pipe(self, parent_pipe): + + def add_pipe(self, parent_pipe, proc): # Call "handle_ipc" for both data and EOF events gobject.io_add_watch(parent_pipe.fileno(), gobject.IO_IN | gobject.IO_HUP, functools.partial(self.handle_ipc, - parent_pipe = parent_pipe)) - + parent_pipe = + parent_pipe, + proc = proc)) + def handle_ipc(self, source, condition, parent_pipe=None, - client_object=None): + proc = None, client_object=None): condition_names = { gobject.IO_IN: "IN", # There is data to read. gobject.IO_OUT: "OUT", # Data can be written (without @@ -1554,6 +1663,7 @@ if cond & condition) # error or the other end of multiprocessing.Pipe has closed if condition & (gobject.IO_ERR | condition & gobject.IO_HUP): + proc.join() return False # Read a request from the child @@ -1573,37 +1683,45 @@ "dress: %s", fpr, address) if self.use_dbus: # Emit D-Bus signal - mandos_dbus_service.ClientNotFound(fpr, address[0]) + mandos_dbus_service.ClientNotFound(fpr, + address[0]) parent_pipe.send(False) return False gobject.io_add_watch(parent_pipe.fileno(), gobject.IO_IN | gobject.IO_HUP, functools.partial(self.handle_ipc, - parent_pipe = parent_pipe, - client_object = client)) + parent_pipe = + parent_pipe, + proc = proc, + client_object = + client)) parent_pipe.send(True) - # remove the old hook in favor of the new above hook on same fileno + # remove the old hook in favor of the new above hook on + # same fileno return False if command == 'funcall': funcname = request[1] args = request[2] kwargs = request[3] - parent_pipe.send(('data', getattr(client_object, funcname)(*args, **kwargs))) - + parent_pipe.send(('data', getattr(client_object, + funcname)(*args, + **kwargs))) + if command == 'getattr': attrname = request[1] if callable(client_object.__getattribute__(attrname)): parent_pipe.send(('function',)) else: - parent_pipe.send(('data', client_object.__getattribute__(attrname))) + parent_pipe.send(('data', client_object + .__getattribute__(attrname))) if command == 'setattr': attrname = request[1] value = request[2] setattr(client_object, attrname, value) - + return True @@ -1788,7 +1906,7 @@ debuglevel = server_settings["debuglevel"] use_dbus = server_settings["use_dbus"] use_ipv6 = server_settings["use_ipv6"] - + if server_settings["servicename"] != "Mandos": syslogger.setFormatter(logging.Formatter ('Mandos (%s) [%%(process)d]:' @@ -1796,8 +1914,9 @@ % server_settings["servicename"])) # Parse config file with clients - client_defaults = { "timeout": "1h", - "interval": "5m", + client_defaults = { "timeout": "5m", + "extended_timeout": "15m", + "interval": "2m", "checker": "fping -q -- %%(host)s", "host": "", "approval_delay": "0s", @@ -1854,7 +1973,7 @@ level = getattr(logging, debuglevel.upper()) syslogger.setLevel(level) console.setLevel(level) - + if debug: # Enable all possible GnuTLS debugging @@ -1891,8 +2010,11 @@ # End of Avahi example code if use_dbus: try: - bus_name = dbus.service.BusName("se.bsnet.fukt.Mandos", + bus_name = dbus.service.BusName("se.recompile.Mandos", bus, do_not_queue=True) + old_bus_name = (dbus.service.BusName + ("se.bsnet.fukt.Mandos", bus, + do_not_queue=True)) except dbus.exceptions.NameExistsException as e: logger.error(unicode(e) + ", disabling D-Bus") use_dbus = False @@ -1911,7 +2033,8 @@ client_class = Client if use_dbus: - client_class = functools.partial(ClientDBus, bus = bus) + client_class = functools.partial(ClientDBusTransitional, + bus = bus) def client_config_items(config, section): special_settings = { "approved_by_default": @@ -1947,7 +2070,7 @@ del pidfilename signal.signal(signal.SIGINT, signal.SIG_IGN) - + signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit()) signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit()) @@ -1956,7 +2079,7 @@ """A D-Bus proxy object""" def __init__(self): dbus.service.Object.__init__(self, bus, "/") - _interface = "se.bsnet.fukt.Mandos" + _interface = "se.recompile.Mandos" @dbus.service.signal(_interface, signature="o") def ClientAdded(self, objpath): @@ -2004,12 +2127,15 @@ del _interface - mandos_dbus_service = MandosDBusService() + class MandosDBusServiceTransitional(MandosDBusService): + __metaclass__ = AlternateDBusNamesMetaclass + mandos_dbus_service = MandosDBusServiceTransitional() def cleanup(): "Cleanup function; run on exit" service.cleanup() + multiprocessing.active_children() while tcp_server.clients: client = tcp_server.clients.pop() if use_dbus: @@ -2019,7 +2145,8 @@ client.disable(quiet=True) if use_dbus: # Emit D-Bus signal - mandos_dbus_service.ClientRemoved(client.dbus_object_path, + mandos_dbus_service.ClientRemoved(client + .dbus_object_path, client.name) atexit.register(cleanup) @@ -2074,5 +2201,6 @@ # Must run before the D-Bus bus name gets deregistered cleanup() + if __name__ == '__main__': main() === modified file 'mandos-clients.conf.xml' --- mandos-clients.conf.xml 2011-02-27 17:26:35 +0000 +++ mandos-clients.conf.xml 2011-10-05 16:00:56 +0000 @@ -3,7 +3,7 @@ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ /etc/mandos/clients.conf"> - + %common; ]> @@ -20,14 +20,14 @@ Björn Påhlsson
- belorn@fukt.bsnet.se + belorn@recompile.se
Teddy Hogeborn
- teddy@fukt.bsnet.se + teddy@recompile.se
@@ -182,6 +182,29 @@ + + + + This option is optional. + + + Extended timeout is an added timeout that is given once + after a password has been sent sucessfully to a client. + The timeout is by default longer than the normal timeout, + and is used for handling the extra long downtime while a + machine is booting up. Time to take into consideration + when changing this value is file system checks and quota + checks. The default value is 15 minutes. + + + The format of TIME is the same + as for timeout below. + + + + + @@ -229,7 +252,7 @@ will wait for a checker to complete until the below timeout occurs, at which time the client will be disabled, and any running checker - killed. The default interval is 5 minutes. + killed. The default interval is 2 minutes. The format of TIME is the same @@ -299,10 +322,11 @@ This option is optional. - The timeout is how long the server will wait (for either a - successful checker run or a client receiving its secret) - until a client is disabled and not allowed to get the data - this server holds. By default Mandos will use 1 hour. + The timeout is how long the server will wait, after a + successful checker run, until a client is disabled and not + allowed to get the data this server holds. By default + Mandos will use 5 minutes. See also the + option. The TIME is specified as a @@ -420,8 +444,8 @@ [DEFAULT] -timeout = 1h -interval = 5m +timeout = 5m +interval = 2m checker = fping -q -- %%(host)s # Client "foo" @@ -460,6 +484,8 @@ SEE ALSO + intro + 8mandos, mandos-keygen 8, mandos.conf === modified file 'mandos-ctl' --- mandos-ctl 2011-07-27 17:58:27 +0000 +++ mandos-ctl 2011-10-09 12:32:13 +0000 @@ -3,8 +3,8 @@ # # Mandos Monitor - Control and monitor the Mandos server # -# Copyright © 2008-2010 Teddy Hogeborn -# Copyright © 2008-2010 Björn Påhlsson +# Copyright © 2008-2011 Teddy Hogeborn +# Copyright © 2008-2011 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 @@ -19,7 +19,7 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . # -# Contact the authors at . +# Contact the authors at . # from __future__ import (division, absolute_import, print_function, @@ -52,9 +52,10 @@ "ApprovalDelay": "Approval Delay", "ApprovalDuration": "Approval Duration", "Checker": "Checker", + "ExtendedTimeout" : "Extended Timeout" } defaultkeywords = ("Name", "Enabled", "Timeout", "LastCheckedOK") -domain = "se.bsnet.fukt" +domain = "se.recompile" busname = domain + ".Mandos" server_path = "/" server_interface = domain + ".Mandos" @@ -149,6 +150,7 @@ options.remove, options.checker is not None, options.timeout is not None, + options.extended_timeout is not None, options.interval is not None, options.approved_by_default is not None, options.approval_delay is not None, @@ -185,6 +187,8 @@ help="Set checker command for client") parser.add_argument("-t", "--timeout", help="Set timeout for client") + parser.add_argument("--extended-timeout", + help="Set extended timeout for client") parser.add_argument("-i", "--interval", help="Set checker interval for client") parser.add_argument("--approve-by-default", action="store_true", @@ -270,7 +274,8 @@ "LastEnabled", "ApprovalPending", "ApprovedByDefault", "LastApprovalRequest", "ApprovalDelay", - "ApprovalDuration", "Checker") + "ApprovalDuration", "Checker", + "ExtendedTimeout") else: keywords = defaultkeywords @@ -325,6 +330,11 @@ timedelta_to_milliseconds (string_to_delta(options.timeout)), dbus_interface=dbus.PROPERTIES_IFACE) + if options.extended_timeout: + client.Set(client_interface, "ExtendedTimeout", + timedelta_to_milliseconds + (string_to_delta(options.extended_timeout)), + dbus_interface=dbus.PROPERTIES_IFACE) if options.secret: client.Set(client_interface, "Secret", dbus.ByteArray(open(options.secret, === modified file 'mandos-ctl.xml' --- mandos-ctl.xml 2011-02-27 17:26:35 +0000 +++ mandos-ctl.xml 2011-10-05 16:00:56 +0000 @@ -2,7 +2,7 @@ - + %common; ]> @@ -19,14 +19,14 @@ Björn Påhlsson
- belorn@fukt.bsnet.se + belorn@recompile.se
Teddy Hogeborn
- teddy@fukt.bsnet.se + teddy@recompile.se
@@ -95,6 +95,11 @@ + + + +
+ + + + + + Set the extended_timeout option of the + specified client(s); see mandos-clients.conf5. + + + @@ -617,6 +618,8 @@ SEE ALSO + intro + 8mandos, cryptsetup 8, crypttab === modified file 'plugins.d/askpass-fifo.c' --- plugins.d/askpass-fifo.c 2011-07-13 02:24:39 +0000 +++ plugins.d/askpass-fifo.c 2011-10-05 16:00:56 +0000 @@ -19,7 +19,7 @@ * along with this program. If not, see * . * - * Contact the authors at . + * Contact the authors at . */ #define _GNU_SOURCE /* TEMP_FAILURE_RETRY() */ === modified file 'plugins.d/askpass-fifo.xml' --- plugins.d/askpass-fifo.xml 2009-01-04 21:54:55 +0000 +++ plugins.d/askpass-fifo.xml 2011-10-05 16:00:56 +0000 @@ -2,7 +2,7 @@ - + %common; ]> @@ -19,20 +19,21 @@ Björn Påhlsson
- belorn@fukt.bsnet.se + belorn@recompile.se
Teddy Hogeborn
- teddy@fukt.bsnet.se + teddy@recompile.se
2008 2009 + 2011 Teddy Hogeborn Björn Påhlsson @@ -148,6 +149,8 @@ SEE ALSO + intro + 8mandos, fifo 7, plugin-runner === modified file 'plugins.d/mandos-client.c' --- plugins.d/mandos-client.c 2011-07-16 00:29:19 +0000 +++ plugins.d/mandos-client.c 2011-10-05 16:00:56 +0000 @@ -26,7 +26,7 @@ * along with this program. If not, see * . * - * Contact the authors at . + * Contact the authors at . */ /* Needed by GPGME, specifically gpgme_data_seek() */ @@ -127,7 +127,7 @@ bool debug = false; static const char mandos_protocol_version[] = "1"; const char *argp_program_version = "mandos-client " VERSION; -const char *argp_program_bug_address = ""; +const char *argp_program_bug_address = ""; static const char sys_class_net[] = "/sys/class/net"; char *connect_to = NULL; @@ -187,6 +187,7 @@ return buffer_capacity; } +/* Add server to set of servers to retry periodically */ int add_server(const char *ip, uint16_t port, AvahiIfIndex if_index, int af){ @@ -204,12 +205,12 @@ perror_plus("strdup"); return -1; } - /* unique case of first server */ + /* Special case of first server */ if (mc.current_server == NULL){ new_server->next = new_server; new_server->prev = new_server; mc.current_server = new_server; - /* Placing the new server last in the list */ + /* Place the new server last in the list */ } else { new_server->next = mc.current_server; new_server->prev = mc.current_server->prev; @@ -282,7 +283,7 @@ return false; } - /* Set GPGME home directory for the OpenPGP engine only */ + /* Set GPGME home directory for the OpenPGP engine only */ rc = gpgme_get_engine_info(&engine_info); if(rc != GPG_ERR_NO_ERROR){ fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n", @@ -1205,7 +1206,7 @@ struct timespec now; struct timespec waited_time; intmax_t block_time; - + while(true){ if(mc.current_server == NULL){ if (debug){ @@ -1236,11 +1237,11 @@ block_time = ((retry_interval - ((intmax_t)waited_time.tv_sec * 1000)) - ((intmax_t)waited_time.tv_nsec / 1000000)); - + if (debug){ - fprintf(stderr, "Blocking for %ld ms\n", block_time); + fprintf(stderr, "Blocking for %" PRIdMAX " ms\n", block_time); } - + if(block_time <= 0){ ret = start_mandos_communication(mc.current_server->ip, mc.current_server->port, @@ -1411,7 +1412,8 @@ errno = 0; retry_interval = strtod(arg, &tmp); if(errno != 0 or tmp == arg or *tmp != '\0' - or (retry_interval * 1000) > INT_MAX){ + or (retry_interval * 1000) > INT_MAX + or retry_interval < 0){ argp_error(state, "Bad retry interval"); } break; @@ -1468,40 +1470,44 @@ perror_plus("seteuid"); } - int seckey_fd = open(PATHDIR "/" SECKEY, O_RDONLY); - if(seckey_fd == -1){ - perror_plus("open"); - } else { - ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st)); - if(ret == -1){ - perror_plus("fstat"); + if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){ + int seckey_fd = open(seckey, O_RDONLY); + if(seckey_fd == -1){ + perror_plus("open"); } else { - if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){ - ret = fchown(seckey_fd, uid, gid); - if(ret == -1){ - perror_plus("fchown"); + ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st)); + if(ret == -1){ + perror_plus("fstat"); + } else { + if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){ + ret = fchown(seckey_fd, uid, gid); + if(ret == -1){ + perror_plus("fchown"); + } } } + TEMP_FAILURE_RETRY(close(seckey_fd)); } - TEMP_FAILURE_RETRY(close(seckey_fd)); } - int pubkey_fd = open(PATHDIR "/" PUBKEY, O_RDONLY); - if(pubkey_fd == -1){ - perror_plus("open"); - } else { - ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st)); - if(ret == -1){ - perror_plus("fstat"); + if(strcmp(pubkey, PATHDIR "/" PUBKEY) == 0){ + int pubkey_fd = open(pubkey, O_RDONLY); + if(pubkey_fd == -1){ + perror_plus("open"); } else { - if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){ - ret = fchown(pubkey_fd, uid, gid); - if(ret == -1){ - perror_plus("fchown"); + ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st)); + if(ret == -1){ + perror_plus("fstat"); + } else { + if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){ + ret = fchown(pubkey_fd, uid, gid); + if(ret == -1){ + perror_plus("fchown"); + } } } + TEMP_FAILURE_RETRY(close(pubkey_fd)); } - TEMP_FAILURE_RETRY(close(pubkey_fd)); } /* Lower privileges */ @@ -1829,27 +1835,37 @@ port = (uint16_t)tmpmax; *address = '\0'; - address = connect_to; /* Colon in address indicates IPv6 */ int af; - if(strchr(address, ':') != NULL){ + if(strchr(connect_to, ':') != NULL){ af = AF_INET6; + /* Accept [] around IPv6 address - see RFC 5952 */ + if(connect_to[0] == '[' and address[-1] == ']') + { + connect_to++; + address[-1] = '\0'; + } } else { af = AF_INET; } + address = connect_to; if(quit_now){ goto end; } - + while(not quit_now){ ret = start_mandos_communication(address, port, if_index, af); if(quit_now or ret == 0){ break; } - sleep((int)retry_interval or 1); - }; - + if(debug){ + fprintf(stderr, "Retrying in %d seconds\n", + (int)retry_interval); + } + sleep((int)retry_interval); + } + if (not quit_now){ exitcode = EXIT_SUCCESS; } @@ -1992,9 +2008,10 @@ if(tempdir_created){ struct dirent **direntries = NULL; struct dirent *direntry = NULL; - ret = scandir(tempdir, &direntries, notdotentries, alphasort); - if (ret > 0){ - for(int i = 0; i < ret; i++){ + int numentries = scandir(tempdir, &direntries, notdotentries, + alphasort); + if (numentries > 0){ + for(int i = 0; i < numentries; i++){ direntry = direntries[i]; char *fullname = NULL; ret = asprintf(&fullname, "%s/%s", tempdir, @@ -2012,10 +2029,9 @@ } } - /* need to be cleaned even if ret == 0 because man page doesn't - specify */ + /* need to clean even if 0 because man page doesn't specify */ free(direntries); - if (ret == -1){ + if (numentries == -1){ perror_plus("scandir"); } ret = rmdir(tempdir); === modified file 'plugins.d/mandos-client.xml' --- plugins.d/mandos-client.xml 2011-06-23 22:27:15 +0000 +++ plugins.d/mandos-client.xml 2011-10-05 16:00:56 +0000 @@ -2,7 +2,7 @@ - + %common; ]> @@ -19,20 +19,21 @@ Björn Påhlsson
- belorn@fukt.bsnet.se + belorn@recompile.se
Teddy Hogeborn
- teddy@fukt.bsnet.se + teddy@recompile.se
2008 2009 + 2011 Teddy Hogeborn Björn Påhlsson @@ -137,9 +138,9 @@ using TLS with an OpenPGP key to ensure authenticity and confidentiality. This client program keeps running, trying all servers on the network, until it receives a satisfactory reply - or a TERM signal is received. If no servers are found, or after - all servers have been tried, it waits indefinitely for new - servers to appear. + or a TERM signal. After all servers have been tried, all + servers are periodically retried. If no servers are found it + will wait indefinitely for new servers to appear.
This program is not meant to be run directly; it is really meant @@ -303,10 +304,10 @@ >SECONDS - All Mandos servers servers are tried repeatedly until a - password is received. This value specifies, in seconds, - how long between each successive try for the - same server. The default is 10 seconds. + All Mandos servers are tried repeatedly until a password + is received. This value specifies, in seconds, how long + between each successive try for the same + server. The default is 10 seconds. @@ -388,9 +389,9 @@ server could be found and the password received from it could be successfully decrypted and output on standard output. The program will exit with a non-zero exit status only if a critical - error occurs. Otherwise, it will forever connect to new - Mandos servers as they appear, trying - to get a decryptable password and print it. + error occurs. Otherwise, it will forever connect to any + discovered Mandos servers, trying to + get a decryptable password and print it.
@@ -535,6 +536,8 @@ SEE ALSO + intro + 8mandos, cryptsetup 8, crypttab === modified file 'plugins.d/password-prompt.c' --- plugins.d/password-prompt.c 2011-07-27 17:58:27 +0000 +++ plugins.d/password-prompt.c 2011-10-09 12:32:13 +0000 @@ -2,8 +2,8 @@ /* * Password-prompt - Read a password from the terminal and print it * - * Copyright © 2008-2010 Teddy Hogeborn - * Copyright © 2008-2010 Björn Påhlsson + * Copyright © 2008-2011 Teddy Hogeborn + * Copyright © 2008-2011 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 @@ -19,7 +19,7 @@ * along with this program. If not, see * . * - * Contact the authors at . + * Contact the authors at . */ #define _GNU_SOURCE /* getline(), asprintf() */ @@ -67,7 +67,7 @@ int signal_received; bool debug = false; const char *argp_program_version = "password-prompt " VERSION; -const char *argp_program_bug_address = ""; +const char *argp_program_bug_address = ""; /* Needed for conflict resolution */ const char plymouth_name[] = "plymouthd"; === modified file 'plugins.d/password-prompt.xml' --- plugins.d/password-prompt.xml 2009-10-30 16:23:43 +0000 +++ plugins.d/password-prompt.xml 2011-10-05 16:00:56 +0000 @@ -2,7 +2,7 @@ - + %common; ]> @@ -19,20 +19,21 @@ Björn Påhlsson
- belorn@fukt.bsnet.se + belorn@recompile.se
Teddy Hogeborn
- teddy@fukt.bsnet.se + teddy@recompile.se
2008 2009 + 2011 Teddy Hogeborn Björn Påhlsson @@ -292,6 +293,8 @@ SEE ALSO + intro + 8mandos crypttab 5 mandos-client === modified file 'plugins.d/plymouth.c' --- plugins.d/plymouth.c 2011-07-13 02:24:39 +0000 +++ plugins.d/plymouth.c 2011-10-05 16:00:56 +0000 @@ -19,7 +19,7 @@ * along with this program. If not, see * . * - * Contact the authors at . + * Contact the authors at . */ #define _GNU_SOURCE /* asprintf(), TEMP_FAILURE_RETRY() */ @@ -54,15 +54,17 @@ #include /* va_list, va_start(), ... */ sig_atomic_t interrupted_by_signal = 0; -const char plymouth_pid[] = "/dev/.initramfs/plymouth.pid"; + +/* Used by Ubuntu 11.04 (Natty Narwahl) */ +const char plymouth_old_pid[] = "/dev/.initramfs/plymouth.pid"; +/* Used by Ubuntu 11.10 (Oneiric Ocelot) */ +const char plymouth_pid[] = "/run/initramfs/plymouth.pid"; + const char plymouth_path[] = "/bin/plymouth"; const char plymouthd_path[] = "/sbin/plymouthd"; const char *plymouthd_default_argv[] = {"/sbin/plymouthd", "--mode=boot", "--attach-to-session", - "--pid-file=" - "/dev/.initramfs/" - "plymouth.pid", NULL }; static void termination_handler(__attribute__((unused))int signum){ @@ -260,8 +262,9 @@ pid_t get_pid(void){ int ret; + uintmax_t maxvalue = 0; FILE *pidfile = fopen(plymouth_pid, "r"); - uintmax_t maxvalue = 0; + /* Try the new pid file location */ if(pidfile != NULL){ ret = fscanf(pidfile, "%" SCNuMAX, &maxvalue); if(ret != 1){ @@ -269,6 +272,18 @@ } fclose(pidfile); } + /* Try the old pid file location */ + if(maxvalue == 0){ + pidfile = fopen(plymouth_pid, "r"); + if(pidfile != NULL){ + ret = fscanf(pidfile, "%" SCNuMAX, &maxvalue); + if(ret != 1){ + maxvalue = 0; + } + fclose(pidfile); + } + } + /* Look for a plymouth process */ if(maxvalue == 0){ struct dirent **direntries = NULL; ret = scandir("/proc", &direntries, is_plymouth, alphasort); === modified file 'plugins.d/plymouth.xml' --- plugins.d/plymouth.xml 2011-02-27 17:26:35 +0000 +++ plugins.d/plymouth.xml 2011-10-05 16:00:56 +0000 @@ -2,7 +2,7 @@ - + %common; ]> @@ -19,14 +19,14 @@ Björn Påhlsson
- belorn@fukt.bsnet.se + belorn@recompile.se
Teddy Hogeborn
- teddy@fukt.bsnet.se + teddy@recompile.se
@@ -261,6 +261,8 @@ SEE ALSO + intro + 8mandos, crypttab 5, plugin-runner === modified file 'plugins.d/splashy.c' --- plugins.d/splashy.c 2011-07-13 02:24:39 +0000 +++ plugins.d/splashy.c 2011-10-05 16:00:56 +0000 @@ -19,7 +19,7 @@ * along with this program. If not, see * . * - * Contact the authors at . + * Contact the authors at . */ #define _GNU_SOURCE /* TEMP_FAILURE_RETRY(), asprintf() */ === modified file 'plugins.d/splashy.xml' --- plugins.d/splashy.xml 2009-01-04 21:54:55 +0000 +++ plugins.d/splashy.xml 2011-10-05 16:00:56 +0000 @@ -2,7 +2,7 @@ - + %common; ]> @@ -19,20 +19,21 @@ Björn Påhlsson
- belorn@fukt.bsnet.se + belorn@recompile.se
Teddy Hogeborn
- teddy@fukt.bsnet.se + teddy@recompile.se
2008 2009 + 2011 Teddy Hogeborn Björn Påhlsson @@ -263,6 +264,8 @@ SEE ALSO + intro + 8mandos, crypttab 5, plugin-runner === modified file 'plugins.d/usplash.c' --- plugins.d/usplash.c 2011-07-13 02:24:39 +0000 +++ plugins.d/usplash.c 2011-10-05 16:00:56 +0000 @@ -19,7 +19,7 @@ * along with this program. If not, see * . * - * Contact the authors at . + * Contact the authors at . */ #define _GNU_SOURCE /* asprintf(), TEMP_FAILURE_RETRY() */ === modified file 'plugins.d/usplash.xml' --- plugins.d/usplash.xml 2009-01-04 21:54:55 +0000 +++ plugins.d/usplash.xml 2011-10-05 16:00:56 +0000 @@ -2,7 +2,7 @@ - + %common; ]> @@ -19,20 +19,21 @@ Björn Påhlsson
- belorn@fukt.bsnet.se + belorn@recompile.se
Teddy Hogeborn
- teddy@fukt.bsnet.se + teddy@recompile.se
2008 2009 + 2011 Teddy Hogeborn Björn Påhlsson @@ -277,6 +278,8 @@ SEE ALSO + intro + 8mandos, crypttab 5, fifo