=== modified file '.bzrignore'
--- .bzrignore 2010-09-30 06:24:20 +0000
+++ .bzrignore 2008-10-03 09:32:30 +0000
@@ -2,6 +2,8 @@
*.8
*.8mandos
confdir
+debian/po/messages.mo
+debian/po/templates.pot
keydir
man
plugin-runner
@@ -10,4 +12,3 @@
plugins.d/password-prompt
plugins.d/splashy
plugins.d/usplash
-plugins.d/plymouth
=== removed file 'DBUS-API'
--- DBUS-API 2010-09-26 18:32:58 +0000
+++ DBUS-API 1970-01-01 00:00:00 +0000
@@ -1,172 +0,0 @@
- -*- mode: org; coding: utf-8 -*-
-
- Mandos Server D-Bus Interface
-
-This file documents the D-Bus interface to the Mandos server.
-
-* Bus: System bus
- Bus name: "se.bsnet.fukt.Mandos"
-
-
-* Object Paths:
-
- | Path | Object |
- |-----------------------+-------------------|
- | "/" | The Mandos Server |
- | "/clients/CLIENTNAME" | Mandos Client |
-
-
-* Mandos Server Interface:
- Interface name: "se.bsnet.fukt.Mandos"
-
-** Methods:
-*** GetAllClients() → (ao: Clients)
- Returns an array of all client D-Bus object paths
-
-*** GetAllClientsWithProperties() → (a{oa{sv}}: ClientProperties)
- Returns an array of all clients and all their properties
-
-*** RemoveClient(o: ObjectPath) → nothing
- Removes a client
-
-** Signals:
-*** ClientAdded(o: ObjectPath)
- A new client was added.
-
-*** ClientNotFound(s: Fingerprint, s: Address)
- A client connected from Address using Fingerprint, but was
- rejected because it was not found in the server. The fingerprint
- is represented as a string of hexadecimal digits. The address is
- an IPv4 or IPv6 address in its normal string format.
-
-*** ClientRemoved(o: ObjectPath, s: Name)
- A client named Name on ObjectPath was removed.
-
-
-* Mandos Client Interface:
- Interface name: "se.bsnet.fukt.Mandos.Client"
-
-** Methods
-*** Approve(b: Approve) → nothing
- Approve or deny a connected client waiting for approval. If
- denied, a client will not be sent its secret.
-
-*** CheckedOK() → nothing
- Assert that this client has been checked and found to be alive.
- This will restart the timeout before disabling this client. See
- also the "LastCheckedOK" property.
-
-*** Disable() → nothing
- Disable this client. See also the "Enabled" property.
-
-*** Enable() → nothing
- Enable this client. See also the "Enabled" property.
-
-*** StartChecker() → nothing
- Start a new checker for this client, if none is currently
- running. See also the "CheckerRunning" property.
-
-*** StopChecker() → nothing
- Abort a running checker process for this client, if any. See also
- the "CheckerRunning" property.
-
-** Properties
-
- Note: Many of these properties directly correspond to a setting in
- "clients.conf", in which case they are fully documented in
- mandos-clients.conf(5).
-
- | Name | Type | Access | clients.conf |
- |-------------------------+------+------------+---------------------|
- | ApprovedByDefault | b | Read/Write | approved_by_default |
- | ApprovalDelay (a) | t | Read/Write | approval_delay |
- | ApprovalDuration (a) | t | Read/Write | approval_duration |
- | ApprovalPending (b) | b | Read | N/A |
- | Checker | s | Read/Write | checker |
- | CheckerRunning (c) | b | Read/Write | N/A |
- | Created (d) | s | Read | N/A |
- | Enabled (e) | b | Read/Write | N/A |
- | 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 |
- | Name | s | Read | (Section name) |
- | ObjectPath | o | Read | N/A |
- | Secret (i) | ay | Write | secret (or secfile) |
- | Timeout (a) | t | Read/Write | timeout |
-
- a) Represented as milliseconds.
-
- b) An approval is currently pending.
-
- c) Setting this property is equivalent to calling StartChecker() or
- StopChecker().
-
- d) The creation time of this client object, as a RFC 3339 string.
-
- e) Setting this property is equivalent to calling Enable() or
- Disable().
-
- f) The time of the last approval request, as a RFC 3339 string, or
- an empty string if this has not happened.
-
- g) The last time a checker was successful, as a 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 a RFC 3339 string, or
- an empty string if this has not happened.
-
- i) A raw byte array, not hexadecimal digits.
-
-** Signals
-*** CheckerCompleted(n: Exitcode, x: Waitstatus, s: Command)
- A checker (Command) has completed. Exitcode is either the exit
- code or -1 for abnormal exit. In any case, the full Waitstatus
- (as from wait(2)) is also available.
-
-*** CheckerStarted(s: Command)
- A checker command (Command) has just been started.
-
-*** GotSecret()
- This client has been sent its secret.
-
-*** NeedApproval(t: Timeout, b: ApprovedByDefault)
- This client will be approved or denied in exactly Timeout
- milliseconds, depending on ApprovedByDefault. Approve() can now
- usefully be called on this client object.
-
-*** PropertyChanged(s: Property, v: Value)
- The Property on this client has changed to Value.
-
-*** Rejected(s: Reason)
- This client was not given its secret for a specified Reason.
-
-* Copyright
-
- Copyright © 2010 Teddy Hogeborn
- Copyright © 2010 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
- .
-
-
-#+STARTUP: showall
=== modified file 'INSTALL'
--- INSTALL 2009-02-15 09:28:06 +0000
+++ INSTALL 2008-10-28 18:00:20 +0000
@@ -39,18 +39,17 @@
*** Mandos Server
+ GnuTLS 2.4 http://www.gnu.org/software/gnutls/
+ Avahi 0.6.16 http://www.avahi.org/
- + Python 2.5 http://www.python.org/
+ + Python 2.4 http://www.python.org/
+ Python-GnuTLS 1.1.5 http://pypi.python.org/pypi/python-gnutls/
+ dbus-python 0.82.4 http://dbus.freedesktop.org/doc/dbus-python/
+ python-ctypes 1.0.0 http://pypi.python.org/pypi/ctypes
- + PyGObject 2.14.2 http://library.gnome.org/devel/pygobject/
Strongly recommended:
+ fping 2.4b2-to-ipv6 http://www.fping.com/
Package names:
python-gnutls avahi-daemon python python-avahi python-dbus
- python-ctypes python-gobject
+ python-ctypes
*** Mandos Client
+ initramfs-tools 0.85i
=== modified file 'Makefile'
--- Makefile 2010-09-28 18:57:31 +0000
+++ Makefile 2008-10-28 18:00:20 +0000
@@ -1,6 +1,6 @@
WARN=-O -Wall -Wformat=2 -Winit-self -Wmissing-include-dirs \
-Wswitch-default -Wswitch-enum -Wunused-parameter \
- -Wstrict-aliasing=1 -Wextra -Wfloat-equal -Wundef -Wshadow \
+ -Wstrict-aliasing=2 -Wextra -Wfloat-equal -Wundef -Wshadow \
-Wunsafe-loop-optimizations -Wpointer-arith \
-Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings \
-Wconversion -Wstrict-prototypes -Wold-style-definition \
@@ -8,22 +8,14 @@
# -Wunreachable-code
#DEBUG=-ggdb3
# For info about _FORTIFY_SOURCE, see
-#
-# and .
-FORTIFY=-D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIC
-LINK_FORTIFY_LD=-z relro -z now
-LINK_FORTIFY=
-
-# If BROKEN_PIE is set, do not build with -pie
-ifndef BROKEN_PIE
-FORTIFY += -fPIE
-LINK_FORTIFY += -pie
-endif
+#
+FORTIFY=-D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIE -pie
+LINK_FORTIFY=-z relro -pie
#COVERAGE=--coverage
OPTIMIZE=-Os
LANGUAGE=-std=gnu99
htmldir=man
-version=1.2
+version=1.0.2
SED=sed
## Use these settings for a traditional /usr/local install
@@ -42,22 +34,21 @@
INITRAMFSTOOLS=$(DESTDIR)/usr/share/initramfs-tools
##
-GNUTLS_CFLAGS=$(shell pkg-config --cflags-only-I gnutls)
-GNUTLS_LIBS=$(shell pkg-config --libs gnutls)
+GNUTLS_CFLAGS=$(shell libgnutls-config --cflags)
+GNUTLS_LIBS=$(shell libgnutls-config --libs)
AVAHI_CFLAGS=$(shell pkg-config --cflags-only-I avahi-core)
AVAHI_LIBS=$(shell pkg-config --libs avahi-core)
-GPGME_CFLAGS=$(shell gpgme-config --cflags; getconf LFS_CFLAGS)
-GPGME_LIBS=$(shell gpgme-config --libs; getconf LFS_LIBS; \
- getconf LFS_LDFLAGS)
+GPGME_CFLAGS=$(shell gpgme-config --cflags)
+GPGME_LIBS=$(shell gpgme-config --libs)
# Do not change these two
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=$(COVERAGE) $(LINK_FORTIFY)
# Commands to format a DocBook document into a manual page
-DOCBOOKTOMAN=$(strip cd $(dir $<); xsltproc --nonet --xinclude \
+DOCBOOKTOMAN=cd $(dir $<); xsltproc --nonet --xinclude \
--param man.charmap.use.subset 0 \
--param make.year.ranges 1 \
--param make.single.year.ranges 1 \
@@ -65,11 +56,11 @@
--param man.authors.section.enabled 0 \
/usr/share/xml/docbook/stylesheet/nwalsh/manpages/docbook.xsl \
$(notdir $<); \
- $(MANPOST) $(notdir $@))
+ $(MANPOST) $(notdir $@)
# DocBook-to-man post-processing to fix a '\n' escape bug
MANPOST=$(SED) --in-place --expression='s,\\\\en,\\en,g;s,\\n,\\en,g'
-DOCBOOKTOHTML=$(strip xsltproc --nonet --xinclude \
+DOCBOOKTOHTML=xsltproc --nonet --xinclude \
--param make.year.ranges 1 \
--param make.single.year.ranges 1 \
--param man.output.quietly 1 \
@@ -77,22 +68,20 @@
--param citerefentry.link 1 \
--output $@ \
/usr/share/xml/docbook/stylesheet/nwalsh/xhtml/docbook.xsl \
- $<; $(HTMLPOST) $@)
+ $<; $(HTMLPOST) $@
# Fix citerefentry links
HTMLPOST=$(SED) --in-place \
--expression='s/\(\)\([^<]*\)\(<\/span>(\)\([^)]*\)\()<\/span><\/a>\)/\1\3.\5\2\3\4\5\6/g'
PLUGINS=plugins.d/password-prompt plugins.d/mandos-client \
- plugins.d/usplash plugins.d/splashy plugins.d/askpass-fifo \
- plugins.d/plymouth
+ plugins.d/usplash plugins.d/splashy plugins.d/askpass-fifo
CPROGS=plugin-runner $(PLUGINS)
-PROGS=mandos mandos-keygen mandos-ctl mandos-monitor $(CPROGS)
-DOCS=mandos.8 mandos-keygen.8 mandos-monitor.8 mandos-ctl.8 \
- mandos.conf.5 mandos-clients.conf.5 plugin-runner.8mandos \
+PROGS=mandos mandos-keygen $(CPROGS)
+DOCS=mandos.8 plugin-runner.8mandos mandos-keygen.8 \
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/password-prompt.8mandos mandos.conf.5 \
+ plugins.d/usplash.8mandos plugins.d/splashy.8mandos \
+ plugins.d/askpass-fifo.8mandos mandos-clients.conf.5
htmldocs=$(addsuffix .xhtml,$(DOCS))
@@ -133,20 +122,6 @@
legalnotice.xml
$(DOCBOOKTOHTML)
-mandos-monitor.8: mandos-monitor.xml common.ent overview.xml \
- legalnotice.xml
- $(DOCBOOKTOMAN)
-mandos-monitor.8.xhtml: mandos-monitor.xml common.ent overview.xml \
- legalnotice.xml
- $(DOCBOOKTOHTML)
-
-mandos-ctl.8: mandos-ctl.xml common.ent overview.xml \
- legalnotice.xml
- $(DOCBOOKTOMAN)
-mandos-ctl.8.xhtml: mandos-ctl.xml common.ent overview.xml \
- legalnotice.xml
- $(DOCBOOKTOHTML)
-
mandos.conf.5: mandos.conf.xml common.ent mandos-options.xml \
legalnotice.xml
$(DOCBOOKTOMAN)
@@ -174,44 +149,31 @@
# Update all these files with version number $(version)
common.ent: Makefile
- $(strip $(SED) --in-place \
- --expression='s/^\($$/\1$(version)">/' \
- $@)
+ $(SED) --in-place \
+ --expression='s/^\($$/\1$(version)"/' \
+ $@
mandos: Makefile
- $(strip $(SED) --in-place \
+ $(SED) --in-place \
--expression='s/^\(version = "\)[^"]*"$$/\1$(version)"/' \
- $@)
+ $@
mandos-keygen: Makefile
- $(strip $(SED) --in-place \
+ $(SED) --in-place \
--expression='s/^\(VERSION="\)[^"]*"$$/\1$(version)"/' \
- $@)
-
-mandos-ctl: Makefile
- $(strip $(SED) --in-place \
- --expression='s/^\(version = "\)[^"]*"$$/\1$(version)"/' \
- $@)
-
-mandos-monitor: Makefile
- $(strip $(SED) --in-place \
- --expression='s/^\(version = "\)[^"]*"$$/\1$(version)"/' \
- $@)
+ $@
mandos.lsm: Makefile
- $(strip $(SED) --in-place \
+ $(SED) --in-place \
--expression='s/^\(Version:\).*/\1\t$(version)/' \
- $@)
- $(strip $(SED) --in-place \
+ $@
+ $(SED) --in-place \
--expression='s/^\(Entered-date:\).*/\1\t$(shell date --rfc-3339=date --reference=Makefile)/' \
- $@)
- $(strip $(SED) --in-place \
- --expression='s/\(mandos_\)[0-9.]\+\(\.orig\.tar\.gz\)/\1$(version)\2/' \
- $@)
+ $@
-plugins.d/mandos-client: plugins.d/mandos-client.c
- $(LINK.c) $(GNUTLS_LIBS) $(AVAHI_LIBS) $(GPGME_LIBS) $(strip\
- ) $(COMMON) $^ $(LOADLIBES) $(LDLIBS) -o $@
+plugins.d/mandos-client: plugins.d/mandos-client.o
+ $(LINK.o) $(GNUTLS_LIBS) $(AVAHI_LIBS) $(GPGME_LIBS) \
+ $(COMMON) $^ $(LOADLIBES) $(LDLIBS) -o $@
.PHONY : all doc html clean distclean run-client run-server install \
install-server install-client uninstall uninstall-server \
@@ -230,21 +192,9 @@
# Run the client with a local config and key
run-client: all keydir/seckey.txt keydir/pubkey.txt
- @echo "###################################################################"
- @echo "# The following error messages are harmless and can be safely #"
- @echo "# ignored. The messages are caused by not running as root, but #"
- @echo "# you should NOT run \"make run-client\" as root unless you also #"
- @echo "# unpacked and compiled Mandos as root, which is NOT recommended. #"
- @echo "# From plugin-runner: setuid: Operation not permitted #"
- @echo "# From askpass-fifo: mkfifo: Permission denied #"
- @echo "# From mandos-client: setuid: Operation not permitted #"
- @echo "# seteuid: Operation not permitted #"
- @echo "# klogctl: Operation not permitted #"
- @echo "###################################################################"
./plugin-runner --plugin-dir=plugins.d \
--config-file=plugin-runner.conf \
- --options-for=mandos-client:--seckey=keydir/seckey.txt,--pubkey=keydir/pubkey.txt \
- $(CLIENTARGS)
+ --options-for=mandos-client:--seckey=keydir/seckey.txt,--pubkey=keydir/pubkey.txt
# Used by run-client
keydir/seckey.txt keydir/pubkey.txt: mandos-keygen
@@ -253,13 +203,7 @@
# Run the server with a local config
run-server: confdir/mandos.conf confdir/clients.conf
- @echo "#################################################################"
- @echo "# NOTE: Please IGNORE the error about \"Could not open file #"
- @echo "# u'/var/run/mandos.pid'\" - it is harmless and is caused by #"
- @echo "# the server not running as root. Do NOT run \"make run-server\" #"
- @echo "# server as root if you didn't also unpack and compile it thus. #"
- @echo "#################################################################"
- ./mandos --debug --no-dbus --configdir=confdir $(SERVERARGS)
+ ./mandos --debug --configdir=confdir
# Used by run-server
confdir/mandos.conf: mandos.conf
@@ -281,16 +225,10 @@
install-server: doc
install --directory $(CONFDIR)
install --mode=u=rwx,go=rx mandos $(PREFIX)/sbin/mandos
- install --mode=u=rwx,go=rx --target-directory=$(PREFIX)/sbin \
- mandos-ctl
- install --mode=u=rwx,go=rx --target-directory=$(PREFIX)/sbin \
- mandos-monitor
install --mode=u=rw,go=r --target-directory=$(CONFDIR) \
mandos.conf
install --mode=u=rw --target-directory=$(CONFDIR) \
clients.conf
- install --mode=u=rw,go=r dbus-mandos.conf \
- $(DESTDIR)/etc/dbus-1/system.d/mandos.conf
install --mode=u=rwx,go=rx init.d-mandos \
$(DESTDIR)/etc/init.d/mandos
install --mode=u=rw,go=r default-mandos \
@@ -300,10 +238,6 @@
fi
gzip --best --to-stdout mandos.8 \
> $(MANDIR)/man8/mandos.8.gz
- gzip --best --to-stdout mandos-monitor.8 \
- > $(MANDIR)/man8/mandos-monitor.8.gz
- gzip --best --to-stdout mandos-ctl.8 \
- > $(MANDIR)/man8/mandos-ctl.8.gz
gzip --best --to-stdout mandos.conf.5 \
> $(MANDIR)/man5/mandos.conf.5.gz
gzip --best --to-stdout mandos-clients.conf.5 \
@@ -336,32 +270,27 @@
install --mode=u=rwxs,go=rx \
--target-directory=$(PREFIX)/lib/mandos/plugins.d \
plugins.d/askpass-fifo
- install --mode=u=rwxs,go=rx \
- --target-directory=$(PREFIX)/lib/mandos/plugins.d \
- plugins.d/plymouth
install initramfs-tools-hook \
$(INITRAMFSTOOLS)/hooks/mandos
install --mode=u=rw,go=r initramfs-tools-hook-conf \
$(INITRAMFSTOOLS)/conf-hooks.d/mandos
install initramfs-tools-script \
- $(INITRAMFSTOOLS)/scripts/init-premount/mandos
+ $(INITRAMFSTOOLS)/scripts/local-top/mandos
install --mode=u=rw,go=r plugin-runner.conf $(CONFDIR)
gzip --best --to-stdout mandos-keygen.8 \
> $(MANDIR)/man8/mandos-keygen.8.gz
gzip --best --to-stdout plugin-runner.8mandos \
> $(MANDIR)/man8/plugin-runner.8mandos.gz
+ gzip --best --to-stdout plugins.d/password-prompt.8mandos \
+ > $(MANDIR)/man8/password-prompt.8mandos.gz
gzip --best --to-stdout plugins.d/mandos-client.8mandos \
> $(MANDIR)/man8/mandos-client.8mandos.gz
- gzip --best --to-stdout plugins.d/password-prompt.8mandos \
- > $(MANDIR)/man8/password-prompt.8mandos.gz
gzip --best --to-stdout plugins.d/usplash.8mandos \
> $(MANDIR)/man8/usplash.8mandos.gz
gzip --best --to-stdout plugins.d/splashy.8mandos \
> $(MANDIR)/man8/splashy.8mandos.gz
gzip --best --to-stdout plugins.d/askpass-fifo.8mandos \
> $(MANDIR)/man8/askpass-fifo.8mandos.gz
- gzip --best --to-stdout plugins.d/plymouth.8mandos \
- > $(MANDIR)/man8/plymouth.8mandos.gz
install-client: install-client-nokey
# Post-installation stuff
@@ -373,11 +302,7 @@
uninstall-server:
-rm --force $(PREFIX)/sbin/mandos \
- $(PREFIX)/sbin/mandos-ctl \
- $(PREFIX)/sbin/mandos-monitor \
$(MANDIR)/man8/mandos.8.gz \
- $(MANDIR)/man8/mandos-monitor.8.gz \
- $(MANDIR)/man8/mandos-ctl.8.gz \
$(MANDIR)/man5/mandos.conf.5.gz \
$(MANDIR)/man5/mandos-clients.conf.5.gz
update-rc.d -f mandos remove
@@ -395,18 +320,16 @@
$(PREFIX)/lib/mandos/plugins.d/usplash \
$(PREFIX)/lib/mandos/plugins.d/splashy \
$(PREFIX)/lib/mandos/plugins.d/askpass-fifo \
- $(PREFIX)/lib/mandos/plugins.d/plymouth \
$(INITRAMFSTOOLS)/hooks/mandos \
$(INITRAMFSTOOLS)/conf-hooks.d/mandos \
- $(INITRAMFSTOOLS)/scripts/init-premount/mandos \
+ $(INITRAMFSTOOLS)/scripts/local-top/mandos \
+ $(MANDIR)/man8/plugin-runner.8mandos.gz \
$(MANDIR)/man8/mandos-keygen.8.gz \
- $(MANDIR)/man8/plugin-runner.8mandos.gz \
- $(MANDIR)/man8/mandos-client.8mandos.gz
$(MANDIR)/man8/password-prompt.8mandos.gz \
$(MANDIR)/man8/usplash.8mandos.gz \
$(MANDIR)/man8/splashy.8mandos.gz \
$(MANDIR)/man8/askpass-fifo.8mandos.gz \
- $(MANDIR)/man8/plymouth.8mandos.gz \
+ $(MANDIR)/man8/mandos-client.8mandos.gz
-rmdir $(PREFIX)/lib/mandos/plugins.d $(CONFDIR)/plugins.d \
$(PREFIX)/lib/mandos $(CONFDIR) $(KEYDIR)
update-initramfs -k all -u
@@ -415,7 +338,6 @@
purge-server: uninstall-server
-rm --force $(CONFDIR)/mandos.conf $(CONFDIR)/clients.conf \
- $(DESTDIR)/etc/dbus-1/system.d/mandos.conf
$(DESTDIR)/etc/default/mandos \
$(DESTDIR)/etc/init.d/mandos \
$(DESTDIR)/var/run/mandos.pid
=== modified file 'NEWS'
--- NEWS 2010-09-28 18:57:31 +0000
+++ NEWS 2008-10-17 18:56:25 +0000
@@ -1,137 +1,6 @@
This NEWS file records noteworthy changes, very tersely.
See the manual for detailed information.
-Version 1.2 (2010-09-28)
-* Client:
-** New "plymouth" plugin to ask for a password using the Plymouth
- graphical boot system.
-** The Mandos client now automatically chooses a network interface if
- the DEVICE setting in /etc/initramfs-tools/initramfs.conf is set to
- the empty string. This is also the new default instead of "eth0".
-** The Mandos client --connect option now loops indefinitely until a
- password is received from the specified server.
-** Bug fix: Quote directory correctly in mandos-keygen with --password
-** Bug fix: don't use "echo -e" in mandos-keygen; unsupported by dash.
-* Server:
-** Terminology change: clients are now "ENABLED" or "DISABLED", not
- "valid" or "invalid".
-** New D-Bus API; see the file "DBUS-API".
-** New control utilities using the new D-Bus API:
- + mandos-ctl A command-line based utility
- + mandos-monitor A text-based GUI interface
-** New feature: manual interactive approval or denying of clients on a
- case-by-case basis.
-** New --debuglevel option to control logging
-** Will not write PID file if --debug is passed
-** Bug fix: Avoid race conditions with short "interval" values or
- fast checkers.
-** Bug fix: Don't try to bind to a network interface when none is
- specified
-
-Version 1.0.14 (2009-10-25)
-Enable building without -pie and -fPIE if BROKEN_PIE is set.
-
-Version 1.0.13 (2009-10-22)
-* Client
-** Security bug fix: If Mandos server is also installed, do not copy
- its config files (with encrypted passwords) into the initrd.img-*
- files.
-
-Version 1.0.12 (2009-09-17)
-* Client
-** Bug fix: Allow network interface renaming by "udev" by taking down
- the network interface after using it.
-** Bug fix: User-supplied plugins are now installed correctly.
-** Bug fix: If usplash was used but the password was instead provided
- by the Mandos server, the usplash daemon used to ignore the first
- command passed to it. This has been fixed.
-** Bug fix: Make the "--userid" and "--groupid" options in
- "plugin-runner.conf" work.
-* Server
-** Bug fix: Fix the LSB header in the init.d script to make dependency
- based booting work.
-** A client receiving its password now also counts as if a checker was
- run successfully (i.e. the timeout timer is reset).
-
-Version 1.0.11 (2009-05-23)
-* Client
-** Bug fix: Use "pkg-config" instead of old "libgnutls-config".
-
-Version 1.0.10 (2009-05-17)
-* Client
-** Security bug fix: Fix permissions on initrd.img-*.bak files when
- upgrading from older versions.
-
-Version 1.0.9 (2009-05-17)
-* Client
-** Security bug fix: Fix permissions on initrd.img file when
- installing new linux-image-* packages calling mkinitramfs-kpkg (all
- version lower than 2.6.28-1-* does this).
-
-Version 1.0.8 (2009-02-25)
-* Client
-** Bug fix: Fix missing quote characters in initramfs-tools-hook.
-
-Version 1.0.7 (2009-02-24)
-* Client
-** Bug fix: Do not depend on GNU awk.
-
-Version 1.0.6 (2009-02-13)
-* Server
-** Fix bug where server would stop responding, with a zombie checker
-** Support for disabling IPv6 (only for advanced users)
-** Fix bug which made server not change group ID
-
-* Client
-** Bug fix: Fix permission for /lib64 (on relevant architechtures).
-** Add support for IPv4 addresses.
-** Add support in mandos-client for not bringing up a network
- interface by specifying an empty string to "--interface".
-** Make password prompt on boot not be mangled by kernel log messages
- about network interface.
-** Get network interface from initramfs.conf and/or from kernel
- command line.
-** If set by "ip=" kernel command line, configure network on boot.
-** Support connecting directly using "mandos=connect" kernel command.
- line option, provided network is configured using "ip=".
-** Fix bug which made plugin-runner and mandos-client not change group
- ID.
-** Fix bug where the "--options-for" option of plugin-runner would
- truncate the value at the first colon character.
-** Fix bug where plugin-runner would not go to fallback if all plugins
- failed.
-** Fix bug where mandos-client would not clean temporary directory on
- a signal or on certain file systems.
-** Bug fix: remove bashism in /bin/sh script "mandos-keygen".
-
-Version 1.0.5 (2009-01-17)
-* Client
-** Fix small memory leak in plugin-runner.
-
-Version 1.0.4 (2009-01-15)
-* Server
-** Only find matched user/group pairs when searching for suitable
- nonprivileged user/group to switch to.
-
-* Client
-** New kernel parameter "mandos=off" makes client not run at boot.
-** Fix linking errors and compilation warnings on AMD64.
-** Parse numbers in command line options better.
-** The splashy and usplash plugins are more robust while traversing
- /proc, and will not abort if a process suddenly disappears.
-
-Version 1.0.3 (2009-01-06)
-* Server
-** Now tries to change to user and group "_mandos" before falling back
- to trying the old values "mandos", "nobody:nogroup", and "65534".
-** Now does not abort on startup even if no clients are defined in
- clients.conf.
-
-* Client
-** Plugins named "*.dpkg-bak" are now ignored.
-** Hopefully fixed compilation failure on some architectures where the
- C compiler does not recognize the "-z" option as a linker option.
-
Version 1.0.2 (2008-10-17)
* mandos-keygen now signs the encrypted key blobs. This signature is
not currently verified by mandos-client, but this may change in the
=== modified file 'README'
--- README 2010-09-26 18:32:58 +0000
+++ README 2008-10-28 18:00:20 +0000
@@ -99,7 +99,7 @@
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
+ bring it back up, but if both reboots at the same time they will
stay down until someone types in the password on one of them.
** Faking ping replies?
@@ -134,19 +134,15 @@
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.
+ found. This duality of purpose was seen to be too complex to be a
+ viable way to continue. Instead, the programs are now separated
+ into mandos-client(8mandos) and password-prompt(8mandos), and a
+ plugin-runner(8mandos) exist to run them both in parallel, allowing
+ the first plugin to succeed 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).
+ Three additional plugins are provided:
* usplash(8mandos)
This prompts for a password when using usplash(8).
* splashy(8mandos)
@@ -156,14 +152,16 @@
cryptsetup, this plugin listens to the same FIFO as askpass would
do.
- More plugins can easily be written and added by the system
+ (None of these take any options or reads any files.)
+
+ More plugins could 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-2010 Teddy Hogeborn
- Copyright © 2008-2010 Björn Påhlsson
+ Copyright © 2008 Teddy Hogeborn
+ Copyright © 2008 Björn Påhlsson
** License:
=== modified file 'TODO'
--- TODO 2010-09-26 18:32:58 +0000
+++ TODO 2008-12-10 01:26:02 +0000
@@ -1,134 +1,55 @@
-*- org -*-
-* Use _attribute_((nonnull)) wherever possible.
-
* mandos-client
-** TODO [#B] use scandir(3) instead of readdir(3)
-** TODO [#B] Prefix all debug output with "Mandos plugin " + program_invocation_short_name
-** TODO [#B] Retry a server which has a non-definite reply:
-*** A closed connection during the TLS handshake
-*** A TCP timeout
-** TODO [#B] Use capabilities instead of seteuid().
-** TODO [#A] Retry --connect forever
-
-* splashy
-** TODO [#B] use scandir(3) instead of readdir(3)
-** TODO [#B] Prefix all debug output with "Mandos plugin " + program_invocation_short_name
-
-* usplash
-** TODO [#A] Make it work again
-** TODO [#B] use scandir(3) instead of readdir(3)
-** TODO [#B] Prefix all debug output with "Mandos plugin " + program_invocation_short_name
-** TODO Use [[info:libc:Argz%20Functions][argz_extract]]
-
-* askpass-fifo
-** TODO [#B] Prefix all debug output with "Mandos plugin " + program_invocation_short_name
-** TODO [#B] Drop privileges after opening FIFO.
-
-* password-prompt
-** TODO [#B] Prefix all debug output with "Mandos plugin " + program_invocation_short_name
-** TODO [#B] lock stdin (with flock()?)
-
-* TODO [#B] passdev
-
-* plugin-runner
-** TODO [#B] use scandir(3) instead of readdir(3)
-** TODO [#C] use same file name rules as run-parts(8)
-** kernel command line option for debug info
-** TODO [#B] Use openat()
+** TODO [#B] Temporarily lower kernel log level
+ for less printouts during sucessfull boot.
+ klogctl(6, NULL, 0); klogctl(7, NULL, 0);
+** TODO [#C] IPv4 support
* mandos (server)
-** TODO [#B] Log level :BUGS:
-** TODO Persistent state :BUGS:
- /var/lib/mandos/*
-*** TODO /etc/mandos/clients.d/*.conf
- Watch this directory and add/remove/update clients?
-** TODO [#C] config for TXT record
-** TODO Log level option
- syslogger.setLevel(logging.WARNING)
- + SetLogLevel D-Bus call
-** TODO Implement --foreground :BUGS:
+** TODO [#B] Log level :bugs:
+** TODO /etc/mandos/clients.d/*.conf
+ Watch this directory and add/remove/update clients?
+** TODO config for TXT record
+** 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
[[info:standards:Option%20Table][Table of Long Options]]
-** TODO Date+time on console log messages :BUGS:
+** TODO Date+time on console log messages :bugs:
Is this the default?
-** 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
-** TODO [#C] python-parsedatetime
-** TODO [#C] systemd/launchd
- http://0pointer.de/blog/projects/systemd.html
-** TODO Separate logging logic to own object
-** TODO make clients to a dict!
-** TODO [#A] Limit approval_delay to max gnutls/tls timeout value
-** TODO [#B] break the wait on approval_delay if connection dies
-** TODO Generate Client.runtime_expansions from client options + extra
-** TODO Allow %%(checker)s as a runtime expansion
-
-* mandos.xml
-** Add mandos contact info in manual pages
-
-* mandos-ctl
-*** Handle "no D-Bus server" and/or "no Mandos server found" better
-*** [#B] --dump option
-** TODO Support RFC 3339 time duration syntax
-
-* TODO mandos-dispatch
- Listens for specified D-Bus signals and spawns shell commands with
- arguments.
-
-* mandos-monitor
-** TODO help should be toggable
-** Urwid client data displayer
- Better view of client data in the listing
-*** Properties popup
-** Nicer crashes. Stack traces Messes up shell.
-*** Print a nice "We are sorry" message, save stack trace to log.
-** Show timeout countdown for approval
+** 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
+** TODO List clients
+** TODO Disable client
+** TODO Enable client
+** TODO Reset timer
* 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
-
-* Package
+* [#A] Package
** /usr/share/initramfs-tools/hooks/mandos
-*** TODO [#C] use same file name rules as run-parts(8)
-*** TODO [#C] Do not install in initrd.img if configured not to.
- Use "/etc/initramfs-tools/hooksconf.d/mandos"?
-** TODO [#C] /etc/bash_completion.d/mandos
+*** TODO Do not install in initrd.img if configured not to.
+ Use "/etc/initramfs-tools/conf.d/mandos"? Definitely a debconf
+ question.
+** TODO /etc/bash_completion.d/mandos
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
-
#+STARTUP: showall
=== modified file 'clients.conf'
--- clients.conf 2010-09-12 03:00:40 +0000
+++ clients.conf 2008-09-21 13:42:34 +0000
@@ -2,28 +2,19 @@
# values, so uncomment and change them if you want different ones.
[DEFAULT]
-# How long until a client is disabled and not be allowed to get the
-# data this server holds.
+# How long until a client is considered invalid - that is, ineligible
+# to get the data this server holds.
;timeout = 1h
# 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.
+# above "timeout" occurs, at which time the client will be marked
+# invalid, and any running checker killed.
;interval = 5m
# What command to run as "the checker".
-;checker = fping -q -- %%(host)s
-
-# Whether to approve a client by default after the approval delay.
-;approved_by_default = True
-
-# How long to wait for approval.
-;approval_delay = 0s
-
-# How long one approval will last.
-;approval_duration = 1s
+;checker = fping -q -- %(host)s
;####
@@ -71,9 +62,4 @@
;
;# Parameters from the [DEFAULT] section can be overridden per client.
;interval = 5m
-;
-;# This client requires manual approval before it receives its secret.
-;approved_by_default = False
-;# Require approval within 30 seconds.
-;approval_delay = 30s
;####
=== modified file 'common.ent'
--- common.ent 2010-09-28 18:57:31 +0000
+++ common.ent 2008-09-30 07:23:39 +0000
@@ -1,3 +1,3 @@
-
+
=== removed file 'dbus-mandos.conf'
--- dbus-mandos.conf 2009-11-09 07:35:16 +0000
+++ dbus-mandos.conf 1970-01-01 00:00:00 +0000
@@ -1,18 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
=== modified file 'debian/changelog'
--- debian/changelog 2010-09-28 18:57:31 +0000
+++ debian/changelog 2008-10-17 18:56:25 +0000
@@ -1,148 +1,3 @@
-mandos (1.2-1) unstable; urgency=low
-
- * New upstream release.
- * Makefile (LINK_FORTIFY_LD): Remove "-fPIE". (Closes: #557076)
- * debian/control: Add gnupg dependency to "mandos-client" and removed it
- from "mandos". Added dependency on "python-urwid" "mandos" since the
- new "mandos-monitor" utility needs it, and on "python (>=2.6) |
- python-multiprocessing" since the Mandos server now uses it.
- * debian/rules: Set BROKEN_PIE on mips and mipsel if a known buggy
- version of binutils is used.
- * debian/mandos.docs: Also install "/usr/share/doc/mandos/DBUS-API".
- * debian/mandos.dirs: Added "etc/dbus-1/system.d".
- * debian/mandos-client.README.Debian: Update info about DEVICE setting
- of initramfs.conf.
- * debian/mandos-client.README.Debian: Remove warning about --connect not
- looping, since it now does.
-
- -- Teddy Hogeborn Tue, 28 Sep 2010 20:46:11 +0200
-
-mandos (1.0.14-1) unstable; urgency=low (HIGH on mips and mipsel)
-
- * New upstream release.
- * debian/rules: Build with BROKEN_PIE set on mips and mipsel
- architectures - fixes FTBFS there.
-
- -- Teddy Hogeborn Sun, 25 Oct 2009 20:10:09 +0100
-
-mandos (1.0.13-1) unstable; urgency=high
-
- * New upstream release.
- * Do not copy unnecessary files to initrd (Closes: #551907)
-
- -- Teddy Hogeborn Thu, 22 Oct 2009 00:53:21 +0200
-
-mandos (1.0.12-1) unstable; urgency=low
-
- * New upstream release.
- * init.d-mandos: Correct dependencies (Closes: #546928)
- * debian/control (Standards-Version): Changed to "3.8.3".
- * debian/mandos-client.README.Debian: Improved wording and formatting.
- Updated location of nfsroot.txt.
- * debian/mandos.README.Debian: Improved wording and formatting.
- * debian/mandos-client.postinst (configure): Don't look for user and
- group with the old name if upgrading from a new enough version.
- * debian/mandos.postinst (configure): - '' -
- * debian/mandos-client.README.Debian: Added text about non-usability of
- pseudo-network interfaces.
-
- -- Teddy Hogeborn Thu, 17 Sep 2009 15:03:59 +0200
-
-mandos (1.0.11-1) unstable; urgency=low
-
- * debian/control (Standards-Version): Changed to "3.8.1".
- * Makefile (GNUTLS_CFLAGS, GNUTLS_CFLAGS): Use "pkg-config" instead of
- the old "libgnutls-config" script. (Closes: #529836)
-
- -- Teddy Hogeborn Sat, 23 May 2009 07:12:20 +0200
-
-mandos (1.0.10-1) unstable; urgency=low
-
- * New upstream release.
- * debian/mandos-client.postinst (update_initramfs): Fix permissions of
- old initrd.img-*.bak files.
-
- -- Teddy Hogeborn Sun, 17 May 2009 04:56:35 +0200
-
-mandos (1.0.9-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Sun, 17 May 2009 02:59:45 +0200
-
-mandos (1.0.8-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Wed, 25 Feb 2009 02:26:57 +0100
-
-mandos (1.0.7-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Tue, 24 Feb 2009 12:58:06 +0100
-
-mandos (1.0.6-1) unstable; urgency=low
-
- * New upstream release.
- * debian/mandos-client.postinst: Converted to Bourne shell. Also
- minor message change.
- * debian/mandos-client.postrm: Minor message change.
- * debian/mandos.postinst: Converted to Bourne shell. Also minor
- message change.
- * debian/mandos.prerm: Minor message change.
- * debian/rules (install-indep): Removed "--no-start" from
- dh_installinit.
- * debian/mandos-client.lintian-overrides: Remove obsolete override for
- unbreakable line in plugin-runner manual page.
- * debian/control (mandos/Depends): Added "python-gobject".
- * debian/mandos-client.dirs: Change
- "usr/share/initramfs-tools/scripts/local-top" to
- "usr/share/initramfs-tools/scripts/init-premount".
- * debian/mandos-client.README.Debian: Add reference to initramfs.conf
- and nfsroot.txt. New section about the new non-local connection
- feature.
-
- -- Teddy Hogeborn Fri, 13 Feb 2009 09:27:25 +0100
-
-mandos (1.0.5-1) unstable; urgency=low
-
- * New upstream release.
-
- -- Teddy Hogeborn Sat, 17 Jan 2009 02:26:00 +0100
-
-mandos (1.0.4-1) unstable; urgency=low
-
- * New upstream release.
- * debian/watch: New file.
- * debian/mandos-client.README.Debian: Document new "mandos=off" kernel
- parameter.
-
- -- Teddy Hogeborn Thu, 15 Jan 2009 05:49:22 +0100
-
-mandos (1.0.3-2) unstable; urgency=low
-
- * Removed some now-unused debconf files.
- * Changed postinst scripts to not source debconf/confmodule.
- * Removed po-debconf from build-depends.
-
- -- Teddy Hogeborn Tue, 06 Jan 2009 21:28:20 +0100
-
-mandos (1.0.3-1) unstable; urgency=low
-
- * New upstream release.
- * Add -Xlinker to linker flags to fix FTBFS for some architectures.
- Thanks to Thiemo Seufer for the report and
- fix. (Closes: #509398)
- * Remove debconf use altogether, thereby stopping debconf abuse. Thanks
- to Christian Perrier . (Closes: #509653)
- * Add NEWS file to /usr/share/doc directories.
- * Use and create "_mandos" user+group. Rename old user+group created by
- older versions of this package.
- * Fix manual pages by adding build-depend on "docbook-xml".
-
- -- Teddy Hogeborn Tue, 06 Jan 2009 01:21:20 +0100
-
mandos (1.0.2-1) unstable; urgency=low
* New upstream release.
=== modified file 'debian/control'
--- debian/control 2010-10-01 18:40:55 +0000
+++ debian/control 2008-09-30 03:19:39 +0000
@@ -4,10 +4,10 @@
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,
+Build-Depends: debhelper (>= 7), docbook-xsl, libavahi-core-dev,
+ libgpgme11-dev, libgnutls-dev, xsltproc, po-debconf,
pkg-config
-Standards-Version: 3.9.1
+Standards-Version: 3.8.0
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
@@ -15,8 +15,7 @@
Package: mandos
Architecture: all
Depends: ${misc:Depends}, python (>=2.5), python-gnutls, python-dbus,
- python-avahi, python-gobject, avahi-daemon, adduser,
- python-urwid, python (>=2.6) | python-multiprocessing
+ python-avahi, avahi-daemon, gnupg (< 2), adduser
Recommends: fping
Description: a server giving encrypted passwords to Mandos clients
This is the server part of the Mandos system, which allows
@@ -35,8 +34,7 @@
Package: mandos-client
Architecture: any
-Depends: ${shlibs:Depends}, ${misc:Depends}, adduser, cryptsetup,
- gnupg (<< 2)
+Depends: ${shlibs:Depends}, ${misc:Depends}, adduser, cryptsetup
Enhances: cryptsetup
Description: do unattended reboots with an encrypted root file system
This is the client part of the Mandos system, which allows
=== modified file 'debian/copyright'
--- debian/copyright 2010-09-26 18:32:58 +0000
+++ debian/copyright 2008-10-15 19:54:11 +0000
@@ -5,8 +5,8 @@
Upstream-Source:
Files: *
-Copyright: Copyright © 2008-2010 Teddy Hogeborn
-Copyright: Copyright © 2008-2010 Björn Påhlsson
+Copyright: Copyright © 2008 Teddy Hogeborn
+Copyright: Copyright © 2008 Björn Påhlsson
License: GPL-3+
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 'debian/mandos-client.README.Debian'
--- debian/mandos-client.README.Debian 2010-09-27 17:53:53 +0000
+++ debian/mandos-client.README.Debian 2008-10-05 17:38:31 +0000
@@ -1,86 +1,45 @@
-* 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
- boot time. This password must be a one which can be used to unlock
- the root file system device. On the *client*, run this command:
-
- mandos-keygen --password
-
- It will prompt for a password and output a config file section.
- This output should be copied to the Mandos server and added to the
- file "/etc/mandos/clients.conf" there.
-
-* Testing that it Works (Without Rebooting)
-
- After the server has been started with this client's key added, it
- is possible to verify that the correct password will be received by
+* Configure The Server
+
+ A client key has been automatically created in /etc/keys/mandos.
+ The next step is to run "mandos-keygen --password" to get a config
+ file section. This should be appended to /etc/mandos/clients.conf
+ on the Mandos server.
+
+* Use the Correct Network Interface
+
+ If some other network interface than "eth0" is used, it will be
+ necessary to edit /etc/mandos/plugin-runner.conf to uncomment and
+ change the line there. If this is done, it will be necessary to
+ update the initrd image by doing "update-initramfs -k all -u".
+
+* Test the Server
+
+ After the server has been started and this client's key added, it is
+ possible to verify that the correct password will be received by
this client by running the command, on the client:
- /usr/lib/mandos/plugins.d/mandos-client \
+ # /usr/lib/mandos/plugins.d/mandos-client \
--pubkey=/etc/keys/mandos/pubkey.txt \
--seckey=/etc/keys/mandos/seckey.txt; echo
This command should retrieve the password from the server, decrypt
- it, and output it to standard output. There it can be verified to
- be the correct password, before rebooting.
+ it, and output it to standard output. It is now possible to verify
+ the correctness of the password before rebooting.
* User-Supplied Plugins
-
- Any plugins found in "/etc/mandos/plugins.d" will override and add
- to the normal Mandos plugins. When adding or changing plugins, do
- not forget to update the initital RAM disk image:
-
- update-initramfs -k all -u
-
-* Do *NOT* Edit "/etc/crypttab"
-
- It is NOT necessary to edit "/etc/crypttab" to specify
- "/usr/lib/mandos/plugin-runner" as a keyscript for the root file
+
+ Any plugins found in /etc/mandos/plugins.d will override and add to
+ the normal Mandos plugins. When adding or changing plugins, do not
+ forget to update the initital RAM disk image:
+
+ # update-initramfs -k all -u
+
+* Do *NOT* Edit /etc/crypttab
+
+ It is NOT necessary to edit /etc/crypttab to specify
+ /usr/lib/mandos/plugin-runner as a keyscript for the root file
system; if no keyscript is given for the root file system, the
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::".
-
- For very advanced users, it it possible to specify simply
- "mandos=connect" on the kernel command line to make the system only
- set up the network (using the data in the "ip=" option) and not pass
- any extra "--connect" options to mandos-client at boot. For this to
- 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 , Sun, 5 Oct 2008 19:04:26 +0200
=== added file 'debian/mandos-client.config'
--- debian/mandos-client.config 1970-01-01 00:00:00 +0000
+++ debian/mandos-client.config 2008-09-21 04:22:50 +0000
@@ -0,0 +1,27 @@
+#! /bin/sh
+#
+# config Mandos Debconf configuration.
+#
+
+# Source debconf library.
+. /usr/share/debconf/confmodule
+if ! db_version 2.0; then
+ echo "mandos.config: need DebConf 2.0 or later"
+ exit 1
+fi
+
+set -e
+umask 022
+
+# Now, interaction. Batch it in case any front ends can use this.
+db_beginblock
+
+# If this is a first time install then prompt
+if [ "$1" = "configure" -a "$2" != "" ]; then
+ db_input high mandos-client/not-yet-configured || true
+fi
+
+db_endblock
+db_go || true
+
+exit 0
=== modified file 'debian/mandos-client.dirs'
--- debian/mandos-client.dirs 2009-02-07 04:50:39 +0000
+++ debian/mandos-client.dirs 2008-09-17 00:34:09 +0000
@@ -2,4 +2,4 @@
usr/sbin
usr/share/initramfs-tools/hooks
usr/share/initramfs-tools/conf-hooks.d
-usr/share/initramfs-tools/scripts/init-premount
+usr/share/initramfs-tools/scripts/local-top
=== modified file 'debian/mandos-client.lintian-overrides'
--- debian/mandos-client.lintian-overrides 2009-01-18 06:41:57 +0000
+++ debian/mandos-client.lintian-overrides 2008-10-01 15:29:01 +0000
@@ -1,3 +1,8 @@
+# This example command line is long without spaces, but it must be
+# that way; it's part of the point of showing it.
+#
+mandos-client binary: manpage-has-errors-from-man usr/share/man/man8/plugin-runner.8mandos.gz 297: warning [p 4, 5.8i]: can't break line
+
# This directory contains secret client key files.
#
mandos-client binary: non-standard-dir-perm etc/keys/mandos/ 0700 != 0755
@@ -11,7 +16,7 @@
# These binaries must be setuid root, since they need root powers, but
# are started by plugin-runner(8mandos), which runs all plugins as
-# user/group "_mandos". These binaries are not run in a running
+# user/group "mandos". These binaries are not run in a running
# system, but in an initial RAM disk environment. Here they are
# protected from non-root access by the directory permissions, above.
#
=== modified file 'debian/mandos-client.postinst'
--- debian/mandos-client.postinst 2009-05-24 23:36:15 +0000
+++ debian/mandos-client.postinst 2008-12-10 01:26:02 +0000
@@ -1,4 +1,4 @@
-#!/bin/sh -e
+#!/bin/bash -e
# This script can be called in the following ways:
#
# After the package was installed:
@@ -15,33 +15,26 @@
# If prerm fails during replacement due to conflict:
# abort-remove in-favour
+. /usr/share/debconf/confmodule
+
# Update the initial RAM file system image
update_initramfs()
{
if [ -x /usr/sbin/update-initramfs ]; then
update-initramfs -u -k all
fi
-
- if dpkg --compare-versions "$2" lt-nl "1.0.10-1"; then
- # Make old initrd.img files unreadable too, in case they were
- # created with mandos-client 1.0.8 or older.
- find /boot -maxdepth 1 -type f -name "initrd.img-*.bak" \
- -print0 | xargs --null --no-run-if-empty chmod o-r
- fi
}
# Add user and group
add_mandos_user(){
# Rename old "mandos" user and group
- if dpkg --compare-versions "$2" lt "1.0.3-1"; then
- case "`getent passwd mandos`" in
- *:Mandos\ password\ system,,,:/nonexistent:/bin/false)
- usermod --login _mandos mandos
- groupmod --new-name _mandos mandos
- return
- ;;
- esac
- fi
+ 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 \
@@ -63,15 +56,15 @@
case "$1" in
configure)
- add_mandos_user "$@"
- create_key "$@"
- update_initramfs "$@"
+ add_mandos_user
+ create_key
+ update_initramfs
;;
abort-upgrade|abort-deconfigure|abort-remove)
;;
*)
- echo "$0 called with unknown argument '$1'" 1>&2
+ echo "$0 called with unknown argument \`$1'" 1>&2
exit 1
;;
esac
=== modified file 'debian/mandos-client.postrm'
--- debian/mandos-client.postrm 2009-01-18 00:16:57 +0000
+++ debian/mandos-client.postrm 2008-09-19 20:54:58 +0000
@@ -50,7 +50,7 @@
;;
*)
- echo "$0 called with unknown argument '$1'" 1>&2
+ echo "$0 called with unknown argument \`$1'" 1>&2
exit 1
;;
esac
=== added file 'debian/mandos-client.templates'
--- debian/mandos-client.templates 1970-01-01 00:00:00 +0000
+++ debian/mandos-client.templates 2008-09-21 04:22:50 +0000
@@ -0,0 +1,8 @@
+Template: mandos-client/not-yet-configured
+Type: note
+_Description: Your system needs more configuration[ mandos-client]
+ Your system can not function as a Mandos client until a
+ password for this client has been added to the
+ configuration on the Mandos server. Please read
+ /usr/share/doc/mandos-client/README.Debian.gz to find out
+ how.
=== modified file 'debian/mandos.README.Debian'
--- debian/mandos.README.Debian 2009-09-08 06:28:20 +0000
+++ debian/mandos.README.Debian 2008-09-21 04:22:50 +0000
@@ -1,10 +1,7 @@
-The Mandos server is useless without at least one configured client in
+The Mandos server cannot run 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
-
- # 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.
-
- -- Teddy Hogeborn , Tue, 8 Sep 2009 06:57:45 +0200
+package on a client computer, and run "mandos-keygen --password" there
+to get a config file stanza. Append that to /etc/mandos/clients.conf
+on the Mandos server.
+
+ -- Teddy Hogeborn , Sat, 20 Sep 2008 21:21:19 +0200
=== added file 'debian/mandos.config'
--- debian/mandos.config 1970-01-01 00:00:00 +0000
+++ debian/mandos.config 2008-09-21 04:22:50 +0000
@@ -0,0 +1,27 @@
+#! /bin/sh
+#
+# config Mandos Debconf configuration.
+#
+
+# Source debconf library.
+. /usr/share/debconf/confmodule
+if ! db_version 2.0; then
+ echo "mandos.config: need DebConf 2.0 or later"
+ exit 1
+fi
+
+set -e
+umask 022
+
+# Now, interaction. Batch it in case any front ends can use this.
+db_beginblock
+
+# If this is a first time install then prompt
+if [ "$1" = "configure" -a "$2" != "" ]; then
+ db_input high mandos/not-yet-configured || true
+fi
+
+db_endblock
+db_go || true
+
+exit 0
=== modified file 'debian/mandos.dirs'
--- debian/mandos.dirs 2010-09-15 17:33:14 +0000
+++ debian/mandos.dirs 2008-09-17 00:34:09 +0000
@@ -2,5 +2,4 @@
usr/share/man/man8
etc/init.d
etc/default
-etc/dbus-1/system.d
usr/sbin
=== modified file 'debian/mandos.docs'
--- debian/mandos.docs 2010-09-12 03:00:40 +0000
+++ debian/mandos.docs 2008-10-18 11:17:22 +0000
@@ -1,4 +1,3 @@
NEWS
README
TODO
-DBUS-API
=== modified file 'debian/mandos.postinst'
--- debian/mandos.postinst 2009-05-24 23:28:04 +0000
+++ debian/mandos.postinst 2008-12-10 01:26:02 +0000
@@ -1,4 +1,4 @@
-#!/bin/sh -e
+#!/bin/bash -e
# This script can be called in the following ways:
#
# After the package was installed:
@@ -15,17 +15,17 @@
# If prerm fails during replacement due to conflict:
# abort-remove in-favour
+. /usr/share/debconf/confmodule
+
case "$1" in
configure)
# Rename old "mandos" user and group
- if dpkg --compare-versions "$2" lt "1.0.3-1"; then
- case "`getent passwd mandos`" in
- *:Mandos\ password\ system,,,:/nonexistent:/bin/false)
- usermod --login _mandos mandos
- groupmod --new-name _mandos mandos
- ;;
- esac
- fi
+ 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 \
@@ -39,7 +39,7 @@
;;
*)
- echo "$0 called with unknown argument '$1'" 1>&2
+ echo "$0 called with unknown argument \`$1'" 1>&2
exit 1
;;
esac
=== modified file 'debian/mandos.prerm'
--- debian/mandos.prerm 2009-01-18 00:16:57 +0000
+++ debian/mandos.prerm 2008-09-21 13:42:34 +0000
@@ -6,12 +6,12 @@
set -e
# summary of how this script can be called:
-# * 'remove'
-# * 'upgrade'
-# * 'failed-upgrade'
-# * 'remove' 'in-favour'
-# * 'deconfigure' 'in-favour'
-# 'removing'
+# * `remove'
+# * `upgrade'
+# * `failed-upgrade'
+# * `remove' `in-favour'
+# * `deconfigure' `in-favour'
+# `removing'
#
# for details, see /usr/share/doc/packaging-manual/
@@ -28,7 +28,7 @@
upgrade|failed-upgrade)
;;
*)
- echo "prerm called with unknown argument '$1'" >&2
+ echo "prerm called with unknown argument \`$1'" >&2
exit 0
;;
esac
=== added file 'debian/mandos.templates'
--- debian/mandos.templates 1970-01-01 00:00:00 +0000
+++ debian/mandos.templates 2008-09-21 04:22:50 +0000
@@ -0,0 +1,9 @@
+Template: mandos/not-yet-configured
+Type: note
+_Description: Your system needs more configuration[ mandos]
+ Your system has not yet been completely configured as a
+ Mandos server - clients need to be added to to
+ /etc/mandos/clients.conf. Please read
+ /usr/share/doc/mandos/README.Debian.gz to find out how.
+ .
+ (The server has not been started.)
=== added file 'debian/po/POTFILES.in'
--- debian/po/POTFILES.in 1970-01-01 00:00:00 +0000
+++ debian/po/POTFILES.in 2008-09-21 04:22:50 +0000
@@ -0,0 +1,2 @@
+[type: gettext/rfc822deb] mandos.templates
+[type: gettext/rfc822deb] mandos-client.templates
=== added file 'debian/po/sv.po'
--- debian/po/sv.po 1970-01-01 00:00:00 +0000
+++ debian/po/sv.po 2008-09-21 04:22:50 +0000
@@ -0,0 +1,66 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the mandos package.
+# FIRST AUTHOR , YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: 1.0\n"
+"Report-Msgid-Bugs-To: mandos@packages.debian.org\n"
+"POT-Creation-Date: 2008-09-20 23:01+0200\n"
+"PO-Revision-Date: 2008-09-21 06:01+0200\n"
+"Last-Translator: Teddy Hogeborn \n"
+"Language-Team: Swedish \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: note
+#. Description
+#: ../mandos.templates:1001
+msgid "Your system needs more configuration[ mandos]"
+msgstr "Ditt system behöver ytterligare konfigurering"
+
+#. Type: note
+#. Description
+#: ../mandos.templates:1001
+#| msgid ""
+#| "Your system has not yet been completely configured as a Mandos server - "
+#| "you need to setup /etc/mandos/clients.conf. Please read /usr/share/doc/"
+#| "mandos/README.Debian.gz to find out how."
+msgid ""
+"Your system has not yet been completely configured as a Mandos server - "
+"clients need to be added to to /etc/mandos/clients.conf. Please read /usr/"
+"share/doc/mandos/README.Debian.gz to find out how."
+msgstr ""
+"Ditt system är inte helt inställd som en Mandos-server än -\n"
+"det behövs läggas till klienter i Mandos-serverns\n"
+"inställingar. Var vänlig läs\n"
+"/usr/share/doc/mandos-client/README.Debian.gz för att få\n"
+"veta hur."
+
+#. Type: note
+#. Description
+#: ../mandos.templates:1001
+msgid "(The server has not been started.)"
+msgstr "(Servern har inte startats.)"
+
+#. Type: note
+#. Description
+#: ../mandos-client.templates:1001
+msgid "Your system needs more configuration[ mandos-client]"
+msgstr "Ditt system behöver ytterligare konfigurering"
+
+#. Type: note
+#. Description
+#: ../mandos-client.templates:1001
+msgid ""
+"Your system can not function as a Mandos client until a password for this "
+"client has been added to the configuration on the Mandos server. Please "
+"read /usr/share/doc/mandos-client/README.Debian.gz to find out how."
+msgstr ""
+"Ditt system kan inte fungera som en Mandos-klient förrän\n"
+"ett krypterat lösenord har lagts till i Mandos-serverns\n"
+"inställingar. Var vänlig läs\n"
+"/usr/share/doc/mandos-client/README.Debian.gz för att få\n"
+"veta hur."
=== modified file 'debian/rules'
--- debian/rules 2010-09-09 18:16:14 +0000
+++ debian/rules 2008-09-30 18:59:44 +0000
@@ -15,20 +15,6 @@
# This has to be exported to make some magic below work.
export DH_OPTIONS
-# -pie was broken briefly on the mips and mipsel architectures, see
-#
-BINUTILS_V := $(shell dpkg-query --showformat='$${Version}' \
- --show binutils)
-ifeq (yes,$(shell dpkg --compare-versions $(BINUTILS_V) lt 2.20-3 \
- && dpkg --compare-versions $(BINUTILS_V) ge 2.19.1-1 \
- && echo yes))
- ifneq (,$(strip $(findstring :$(DEB_HOST_ARCH):,:mips:mipsel:) \
- $(findstring :$(DEB_BUILD_ARCH):,:mips:mipsel:)))
- BROKEN_PIE := yes
- export BROKEN_PIE
- endif
-endif
-
configure: configure-stamp
configure-stamp:
dh_testdir
@@ -52,6 +38,7 @@
rm -f build-arch-stamp build-indep-stamp configure-stamp
dh_auto_clean
dh_clean
+ debconf-updatepo
install: install-indep install-arch
install-indep:
@@ -61,7 +48,7 @@
dh_installdirs --indep
$(MAKE) DESTDIR=$(CURDIR)/debian/mandos install-server
dh_lintian
- dh_installinit --onlyscripts \
+ dh_installinit --onlyscripts --no-start \
--update-rcd-params="defaults 25 15"
dh_install --indep
@@ -79,6 +66,7 @@
dh_testroot
dh_installchangelogs
dh_installdocs
+ dh_installdebconf
dh_link
dh_strip
dh_compress
=== removed file 'debian/watch'
--- debian/watch 2010-09-15 17:17:46 +0000
+++ debian/watch 1970-01-01 00:00:00 +0000
@@ -1,2 +0,0 @@
-version=3
-ftp://ftp.fukt.bsnet.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 2008-09-21 12:04:02 +0000
@@ -1,8 +1,8 @@
#! /bin/sh
### BEGIN INIT INFO
# Provides: mandos
-# Required-Start: $remote_fs $syslog avahi
-# Required-Stop: $remote_fs $syslog avahi
+# Required-Start: $remote_fs avahi-daemon
+# Required-Stop: $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Mandos server
=== modified file 'initramfs-tools-hook'
--- initramfs-tools-hook 2010-09-09 18:16:14 +0000
+++ initramfs-tools-hook 2008-12-10 01:26:02 +0000
@@ -51,13 +51,16 @@
exit 1
fi
-set `{ getent passwd _mandos \
- || getent passwd nobody \
- || echo ::65534:65534:::; } \
- | cut --delimiter=: --fields=3,4 --only-delimited \
- --output-delimiter=" "`
-mandos_user="$1"
-mandos_group="$2"
+mandos_user="`{ getent passwd _mandos \
+ || getent passwd mandos \
+ || getent passwd nobody \
+ || echo ::65534::::; } \
+ | awk --field-separator=: '{ print $3 }'`"
+mandos_group="`{ getent group _mandos \
+ || getent group mandos \
+ || getent group nogroup \
+ || echo ::65534:; } \
+ | awk --field-separator=: '{ print $3 }'`"
# The Mandos network client uses the network
auto_add_modules net
@@ -88,10 +91,9 @@
continue
fi
case "$base" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
- : ;;
- "*") echo "W: Mandos client plugin directory is empty." >&2 ;;
- *) copy_exec "$file" "${PLUGINDIR}" ;;
+ *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert) : ;;
+ "*") :;;
+ *) copy_exec "$file" "${PLUGINDIR}";;
esac
done
@@ -99,10 +101,9 @@
for file in /etc/mandos/plugins.d/*; do
base="`basename \"$file\"`"
case "$base" in
- *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert)
- : ;;
- "*") : ;;
- *) copy_exec "$file" "${PLUGINDIR}" ;;
+ *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert) : ;;
+ "*") :;;
+ *) copy_exec "$file" "${PLUGINDIR}";;
esac
done
@@ -114,7 +115,7 @@
fi
# Config files
-for file in /etc/mandos/plugin-runner.conf; do
+for file in /etc/mandos/*; do
if [ -d "$file" ]; then
continue
fi
@@ -122,17 +123,17 @@
done
if [ ${mandos_user} != 65534 ]; then
- sed --in-place --expression="1i--userid=${mandos_user}" \
- "${DESTDIR}${CONFDIR}/plugin-runner.conf"
+ PLUGINRUNNERCONF="${DESTDIR}${CONFDIR}/plugin-runner.conf"
+ echo "--userid=${mandos_user}" >> "$PLUGINRUNNERCONF"
fi
if [ ${mandos_group} != 65534 ]; then
- sed --in-place --expression="1i--groupid=${mandos_group}" \
- "${DESTDIR}${CONFDIR}/plugin-runner.conf"
+ PLUGINRUNNERCONF="${DESTDIR}${CONFDIR}/plugin-runner.conf"
+ echo "--groupid=${mandos_group}" >> "$PLUGINRUNNERCONF"
fi
# Key files
-for file in "$keydir"/*; do
+for file in "$keydir"/*; do
if [ -d "$file" ]; then
continue
fi
@@ -167,9 +168,7 @@
chmod a+rX "${DESTDIR}$dir"
fi
done
-for dir in "${DESTDIR}"/lib* "${DESTDIR}"/usr/lib*; do
- if [ -d "$dir" ]; then
- find "$dir" \! -perm -u+rw,g+r -prune -or -print0 \
- | xargs --null --no-run-if-empty chmod a+rX
- fi
+for dir in /lib /usr/lib; do
+ find "${DESTDIR}$dir" \! -perm -u+rw,g+r -prune -or -print0 \
+ | xargs --null --no-run-if-empty chmod a+rX
done
=== modified file 'initramfs-tools-hook-conf'
--- initramfs-tools-hook-conf 2009-05-17 00:50:09 +0000
+++ initramfs-tools-hook-conf 2008-08-12 19:22:34 +0000
@@ -1,13 +1,1 @@
-# -*- shell-script -*-
-
-# if mkinitramfs is started by mkinitramfs-kpkg, mkinitramfs-kpkg has
-# already touched the initrd file with umask 022 before we had a
-# chance to affect it. We cannot allow a readable initrd file,
-# therefore we must fix this now.
-if [ -e "${outfile}" ] \
- && [ `stat --format=%s "${outfile}"` -eq 0 ]; then
- rm "${outfile}"
- (umask 027; touch "${outfile}")
-fi
-
UMASK=027
=== modified file 'initramfs-tools-script'
--- initramfs-tools-script 2009-09-16 23:28:39 +0000
+++ initramfs-tools-script 2008-09-07 15:42:11 +0000
@@ -6,102 +6,27 @@
#
# This script should be installed as
-# "/usr/share/initramfs-tools/scripts/init-premount/mandos" which will
-# eventually be "/scripts/init-premount/mandos" in the initrd.img
-# file.
+# "/usr/share/initramfs-tools/scripts/local-top/mandos" which will
+# eventually be "/scripts/local-top/mandos" in the initrd.img file.
-PREREQ="udev"
+# No initramfs pre-requirements; we must instead run BEFORE cryptroot.
+# This is not a problem, since cryptroot forces itself to run LAST.
+PREREQ=""
prereqs()
{
- echo "$PREREQ"
+ echo "$PREREQ"
}
case $1 in
prereqs)
- prereqs
- exit 0
- ;;
+ prereqs
+ exit 0
+ ;;
esac
-. /scripts/functions
-
-for param in `cat /proc/cmdline`; do
- case "$param" in
- ip=*) IPOPTS="${param#ip=}" ;;
- mandos=*)
- # Split option line on commas
- old_ifs="$IFS"
- IFS="$IFS,"
- for mpar in ${param#mandos=}; do
- IFS="$old_ifs"
- case "$mpar" in
- off) exit 0 ;;
- connect) connect="" ;;
- connect:*) connect="${mpar#connect:}" ;;
- *) log_warning_msg "$0: Bad option ${mpar}" ;;
- esac
- done
- unset mpar
- IFS="$old_ifs"
- unset old_ifs
- ;;
- esac
-done
-unset param
-
chmod a=rwxt /tmp
-test -r /conf/conf.d/cryptroot
-test -w /conf/conf.d
-
-# Get DEVICE from /conf/initramfs.conf and other files
-. /conf/initramfs.conf
-for conf in /conf/conf.d/*; do
- [ -f ${conf} ] && . ${conf}
-done
-if [ -e /conf/param.conf ]; then
- . /conf/param.conf
-fi
-
-# Override DEVICE from sixth field of ip= kernel option, if passed
-case "$IPOPTS" in
- *:*:*:*:*:*) # At least six fields
- # Remove the first five fields
- device="${IPOPTS#*:*:*:*:*:}"
- # Remove all fields except the first one
- DEVICE="${device%%:*}"
- ;;
-esac
-
-# Add device setting (if any) to plugin-runner.conf
-if [ "${DEVICE+set}" = set ]; then
- # Did we get the device from an ip= option?
- if [ "${device+set}" = set ]; then
- # Let ip= option override local config; append:
- cat <<-EOF >>/conf/conf.d/mandos/plugin-runner.conf
-
- --options-for=mandos-client:--interface=${DEVICE}
-EOF
- else
- # Prepend device setting so any later options would override:
- sed -i -e \
- '1i--options-for=mandos-client:--interface='"${DEVICE}" \
- /conf/conf.d/mandos/plugin-runner.conf
- fi
-fi
-unset device
-
-# If we are connecting directly, run "configure_networking" (from
-# /scripts/functions); it needs IPOPTS and DEVICE
-if [ "${connect+set}" = set ]; then
- configure_networking
- if [ -n "$connect" ]; then
- cat <<-EOF >>/conf/conf.d/mandos/plugin-runner.conf
-
- --options-for=mandos-client:--connect=${connect}
-EOF
- fi
-fi
+test -w /conf/conf.d/cryptroot
# Do not replace cryptroot file unless we need to.
replace_cryptroot=no
=== modified file 'mandos'
--- mandos 2010-09-28 18:57:31 +0000
+++ mandos 2008-12-10 01:26:02 +0000
@@ -6,13 +6,13 @@
# This program is partly derived from an example program for an Avahi
# service publisher, downloaded from
# . This includes the
-# methods "add", "remove", "server_state_changed",
-# "entry_group_state_changed", "cleanup", and "activate" in the
-# "AvahiService" class, and some lines in "main".
+# methods "add" and "remove" in the "AvahiService" class, the
+# "server_state_changed" and "entry_group_state_changed" functions,
+# and some lines in "main".
#
# Everything else is
-# Copyright © 2008-2010 Teddy Hogeborn
-# Copyright © 2008-2010 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
@@ -33,9 +33,9 @@
from __future__ import division, with_statement, absolute_import
-import SocketServer as socketserver
+import SocketServer
import socket
-import optparse
+from optparse import OptionParser
import datetime
import errno
import gnutls.crypto
@@ -44,23 +44,19 @@
import gnutls.library.functions
import gnutls.library.constants
import gnutls.library.types
-import ConfigParser as configparser
+import ConfigParser
import sys
import re
import os
import signal
+from sets import Set
import subprocess
import atexit
import stat
import logging
import logging.handlers
import pwd
-import contextlib
-import struct
-import fcntl
-import functools
-import cPickle as pickle
-import multiprocessing
+from contextlib import closing
import dbus
import dbus.service
@@ -69,42 +65,28 @@
from dbus.mainloop.glib import DBusGMainLoop
import ctypes
import ctypes.util
-import xml.dom.minidom
-import inspect
-
-try:
- SO_BINDTODEVICE = socket.SO_BINDTODEVICE
-except AttributeError:
- try:
- from IN import SO_BINDTODEVICE
- except ImportError:
- SO_BINDTODEVICE = None
-
-
-version = "1.2"
-
-#logger = logging.getLogger(u'mandos')
-logger = logging.Logger(u'mandos')
+
+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
- (u'Mandos [%(process)d]: %(levelname)s:'
- u' %(message)s'))
+ ('Mandos: %(levelname)s: %(message)s'))
logger.addHandler(syslogger)
console = logging.StreamHandler()
-console.setFormatter(logging.Formatter(u'%(name)s [%(process)d]:'
- u' %(levelname)s:'
- u' %(message)s'))
+console.setFormatter(logging.Formatter('%(name)s: %(levelname)s:'
+ ' %(message)s'))
logger.addHandler(console)
class AvahiError(Exception):
- def __init__(self, value, *args, **kwargs):
+ def __init__(self, value):
self.value = value
- super(AvahiError, self).__init__(value, *args, **kwargs)
- def __unicode__(self):
- return unicode(repr(self.value))
+ super(AvahiError, self).__init__()
+ def __str__(self):
+ return repr(self.value)
class AvahiServiceError(AvahiError):
pass
@@ -115,12 +97,11 @@
class AvahiService(object):
"""An Avahi (Zeroconf) service.
-
Attributes:
interface: integer; avahi.IF_UNSPEC or an interface index.
Used to optionally bind to the specified interface.
- name: string; Example: u'Mandos'
- type: string; Example: u'_mandos._tcp'.
+ name: string; Example: 'Mandos'
+ type: string; Example: '_mandos._tcp'.
See
port: integer; what port to announce
TXT: list of strings; TXT record for the service
@@ -129,14 +110,10 @@
max_renames: integer; maximum number of renames
rename_count: integer; counter so we only rename after collisions
a sensible number of times
- group: D-Bus Entry Group
- server: D-Bus Server
- bus: dbus.SystemBus()
"""
def __init__(self, interface = avahi.IF_UNSPEC, name = None,
servicetype = None, port = None, TXT = None,
- domain = u"", host = u"", max_renames = 32768,
- protocol = avahi.PROTO_UNSPEC, bus = None):
+ domain = "", host = "", max_renames = 32768):
self.interface = interface
self.name = name
self.type = servicetype
@@ -146,290 +123,270 @@
self.host = host
self.rename_count = 0
self.max_renames = max_renames
- self.protocol = protocol
- self.group = None # our entry group
- self.server = None
- self.bus = bus
def rename(self):
"""Derived from the Avahi example code"""
if self.rename_count >= self.max_renames:
logger.critical(u"No suitable Zeroconf service name found"
u" after %i retries, exiting.",
self.rename_count)
- raise AvahiServiceError(u"Too many renames")
- self.name = unicode(self.server.GetAlternativeServiceName(self.name))
+ raise AvahiServiceError("Too many renames")
+ self.name = server.GetAlternativeServiceName(self.name)
logger.info(u"Changing Zeroconf service name to %r ...",
- self.name)
+ str(self.name))
syslogger.setFormatter(logging.Formatter
- (u'Mandos (%s) [%%(process)d]:'
- u' %%(levelname)s: %%(message)s'
- % self.name))
+ ('Mandos (%s): %%(levelname)s:'
+ ' %%(message)s' % self.name))
self.remove()
- try:
- self.add()
- except dbus.exceptions.DBusException, error:
- logger.critical(u"DBusException: %s", error)
- self.cleanup()
- os._exit(1)
+ self.add()
self.rename_count += 1
def remove(self):
"""Derived from the Avahi example code"""
- if self.group is not None:
- self.group.Reset()
+ if group is not None:
+ group.Reset()
def add(self):
"""Derived from the Avahi example code"""
- if self.group is None:
- self.group = dbus.Interface(
- self.bus.get_object(avahi.DBUS_NAME,
- self.server.EntryGroupNew()),
- avahi.DBUS_INTERFACE_ENTRY_GROUP)
- self.group.connect_to_signal('StateChanged',
- self
- .entry_group_state_changed)
+ global group
+ if group is None:
+ group = dbus.Interface(bus.get_object
+ (avahi.DBUS_NAME,
+ server.EntryGroupNew()),
+ avahi.DBUS_INTERFACE_ENTRY_GROUP)
+ group.connect_to_signal('StateChanged',
+ entry_group_state_changed)
logger.debug(u"Adding Zeroconf service '%s' of type '%s' ...",
- self.name, self.type)
- self.group.AddService(
- self.interface,
- self.protocol,
- dbus.UInt32(0), # flags
- self.name, self.type,
- self.domain, self.host,
- dbus.UInt16(self.port),
- avahi.string_array_to_txt_array(self.TXT))
- self.group.Commit()
- def entry_group_state_changed(self, state, error):
- """Derived from the Avahi example code"""
- logger.debug(u"Avahi entry group state change: %i", state)
-
- if state == avahi.ENTRY_GROUP_ESTABLISHED:
- logger.debug(u"Zeroconf service established.")
- elif state == avahi.ENTRY_GROUP_COLLISION:
- logger.warning(u"Zeroconf service name collision.")
- self.rename()
- elif state == avahi.ENTRY_GROUP_FAILURE:
- logger.critical(u"Avahi: Error in group state changed %s",
- unicode(error))
- raise AvahiGroupError(u"State changed: %s"
- % unicode(error))
- def cleanup(self):
- """Derived from the Avahi example code"""
- if self.group is not None:
- self.group.Free()
- self.group = None
- def server_state_changed(self, state):
- """Derived from the Avahi example code"""
- logger.debug(u"Avahi server state change: %i", state)
- if state == avahi.SERVER_COLLISION:
- logger.error(u"Zeroconf server name collision")
- self.remove()
- elif state == avahi.SERVER_RUNNING:
- self.add()
- def activate(self):
- """Derived from the Avahi example code"""
- if self.server is None:
- self.server = dbus.Interface(
- self.bus.get_object(avahi.DBUS_NAME,
- avahi.DBUS_PATH_SERVER),
- avahi.DBUS_INTERFACE_SERVER)
- self.server.connect_to_signal(u"StateChanged",
- self.server_state_changed)
- self.server_state_changed(self.server.GetState())
-
-
-class Client(object):
+ service.name, service.type)
+ group.AddService(
+ self.interface, # interface
+ avahi.PROTO_INET6, # protocol
+ dbus.UInt32(0), # flags
+ self.name, self.type,
+ self.domain, self.host,
+ dbus.UInt16(self.port),
+ avahi.string_array_to_txt_array(self.TXT))
+ group.Commit()
+
+# From the Avahi example code:
+group = None # our entry group
+# End of Avahi example code
+
+
+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:
- _approved: bool(); 'None' if not yet approved/disapproved
- approval_delay: datetime.timedelta(); Time to wait for approval
- approval_duration: datetime.timedelta(); Duration of one approval
+ 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(); (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_callback_tag: a gobject event source tag, or None
- checker_command: string; External command which is run to check
- if client lives. %() expansions are done at
+ checker_initiator_tag: a gobject event source tag, or None
+ stop_initiator_tag: - '' -
+ checker_callback_tag: - '' -
+ checker_command: string; External command which is run to check if
+ client lives. %() expansions are done at
runtime with vars(self) as dict, so that for
instance %(name)s can be used in the command.
- checker_initiator_tag: a gobject event source tag, or None
- created: datetime.datetime(); (UTC) object creation
- current_checker_command: string; current running checker_command
- disable_hook: If set, called by disable() as disable_hook(self)
- disable_initiator_tag: a gobject event source tag, or None
- enabled: bool()
- fingerprint: string (40 or 32 hexadecimal digits); used to
- uniquely identify the client
- host: string; available for use by the checker command
- interval: datetime.timedelta(); How often to start a new checker
- last_approval_request: datetime.datetime(); (UTC) or None
- last_checked_ok: datetime.datetime(); (UTC) or None
- last_enabled: datetime.datetime(); (UTC)
- name: string; from the config file, used in log messages and
- D-Bus identifiers
- secret: bytestring; sent verbatim (over TLS) to client
- timeout: datetime.timedelta(); How long from last_checked_ok
- until this client is disabled
- runtime_expansions: Allowed attributes for runtime expansion.
+ dbus_object_path: dbus.ObjectPath
+ Private attibutes:
+ _timeout: Real variable for 'timeout'
+ _interval: Real variable for 'interval'
+ _timeout_milliseconds: Used when calling gobject.timeout_add()
+ _interval_milliseconds: - '' -
"""
-
- runtime_expansions = (u"approval_delay", u"approval_duration",
- u"created", u"enabled", u"fingerprint",
- u"host", u"interval", u"last_checked_ok",
- u"last_enabled", u"name", u"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)
-
- def interval_milliseconds(self):
- "Return the 'interval' attribute in milliseconds"
- return self._timedelta_to_milliseconds(self.interval)
-
- def approval_delay_milliseconds(self):
- return self._timedelta_to_milliseconds(self.approval_delay)
-
- def __init__(self, name = None, disable_hook=None, config=None):
+ def _set_timeout(self, timeout):
+ "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))
+ # 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 the 'interval' attribute"
+ self._interval = interval
+ self._interval_milliseconds = ((self.interval.days
+ * 24 * 60 * 60 * 1000)
+ + (self.interval.seconds
+ * 1000)
+ + (self.interval.microseconds
+ // 1000))
+ # 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.name = name
+ 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
logger.debug(u"Creating client %r", self.name)
# Uppercase and remove spaces from fingerprint for later
# comparison purposes with return value from the fingerprint()
# function
- self.fingerprint = (config[u"fingerprint"].upper()
+ self.fingerprint = (config["fingerprint"].upper()
.replace(u" ", u""))
logger.debug(u" Fingerprint: %s", self.fingerprint)
- if u"secret" in config:
- self.secret = config[u"secret"].decode(u"base64")
- elif u"secfile" in config:
- with open(os.path.expanduser(os.path.expandvars
- (config[u"secfile"])),
- "rb") as secfile:
+ 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:
self.secret = secfile.read()
else:
raise TypeError(u"No secret or secfile for client %s"
% self.name)
- self.host = config.get(u"host", u"")
+ self.host = config.get("host", "")
self.created = datetime.datetime.utcnow()
- self.enabled = False
- self.last_approval_request = None
- self.last_enabled = None
+ self.started = False
+ self.last_started = None
self.last_checked_ok = None
- self.timeout = string_to_delta(config[u"timeout"])
- self.interval = string_to_delta(config[u"interval"])
- self.disable_hook = disable_hook
+ self.timeout = string_to_delta(config["timeout"])
+ self.interval = string_to_delta(config["interval"])
+ self.stop_hook = stop_hook
self.checker = None
self.checker_initiator_tag = None
- self.disable_initiator_tag = None
+ self.stop_initiator_tag = None
self.checker_callback_tag = None
- self.checker_command = config[u"checker"]
- self.current_checker_command = None
- self.last_connect = None
- self._approved = None
- self.approved_by_default = config.get(u"approved_by_default",
- True)
- self.approvals_pending = 0
- self.approval_delay = string_to_delta(
- config[u"approval_delay"])
- self.approval_duration = string_to_delta(
- config[u"approval_duration"])
- self.changedstate = multiprocessing_manager.Condition(multiprocessing_manager.Lock())
+ self.checker_command = config["checker"]
- def send_changedstate(self):
- self.changedstate.acquire()
- self.changedstate.notify_all()
- self.changedstate.release()
-
- def enable(self):
+ def start(self):
"""Start this client's checker and timeout hooks"""
- if getattr(self, u"enabled", False):
- # Already enabled
- return
- self.send_changedstate()
- self.last_enabled = datetime.datetime.utcnow()
+ 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._interval_milliseconds,
self.start_checker))
- # Schedule a disable() when 'timeout' has passed
- self.disable_initiator_tag = (gobject.timeout_add
- (self.timeout_milliseconds(),
- self.disable))
- self.enabled = True
# 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.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 disable(self, quiet=True):
- """Disable this client."""
- if not getattr(self, "enabled", False):
+ def stop(self):
+ """Stop this client."""
+ if not getattr(self, "started", False):
return False
- if not quiet:
- self.send_changedstate()
- if not quiet:
- logger.info(u"Disabling client %s", self.name)
- if getattr(self, u"disable_initiator_tag", False):
- gobject.source_remove(self.disable_initiator_tag)
- self.disable_initiator_tag = None
- if getattr(self, u"checker_initiator_tag", 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
+ if getattr(self, "checker_initiator_tag", False):
gobject.source_remove(self.checker_initiator_tag)
self.checker_initiator_tag = None
self.stop_checker()
- if self.disable_hook:
- self.disable_hook(self)
- self.enabled = False
+ 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.disable_hook = None
- self.disable()
+ self.stop_hook = None
+ self.stop()
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):
- exitstatus = os.WEXITSTATUS(condition)
- if exitstatus == 0:
- logger.info(u"Checker for %(name)s succeeded",
- vars(self))
- self.checked_ok()
- else:
- logger.info(u"Checker for %(name)s failed",
- vars(self))
- else:
+ # 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 checked_ok(self):
+ 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.utcnow()
- gobject.source_remove(self.disable_initiator_tag)
- self.disable_initiator_tag = (gobject.timeout_add
- (self.timeout_milliseconds(),
- self.disable))
-
- def need_approval(self):
- self.last_approval_request = datetime.datetime.utcnow()
+ gobject.source_remove(self.stop_initiator_tag)
+ 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
nothing."""
# The reason for not killing a running checker is that if we
@@ -438,44 +395,23 @@
# client would inevitably timeout, since no checker would get
# a chance to run to completion. If we instead leave running
# checkers alone, the checker would have to take more time
- # than 'timeout' for the client to be disabled, which is as it
- # should be.
-
- # If a checker exists, make sure it is not a zombie
- try:
- pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
- except (AttributeError, OSError), error:
- if (isinstance(error, OSError)
- and error.errno != errno.ECHILD):
- raise error
- else:
- if pid:
- logger.warning(u"Checker was a zombie")
- gobject.source_remove(self.checker_callback_tag)
- self.checker_callback(pid, status,
- self.current_checker_command)
- # Start a new checker if needed
+ # than 'timeout' for the client to be declared invalid, which
+ # is as it should be.
if self.checker is None:
try:
# In case checker_command has exactly one % operator
command = self.checker_command % self.host
except TypeError:
# Escape attributes for the shell
- escaped_attrs = dict(
- (attr,
- re.escape(unicode(str(getattr(self, attr, u"")),
- errors=
- u'replace')))
- for attr in
- self.runtime_expansions)
-
+ escaped_attrs = dict((key, re.escape(str(val)))
+ for key, val in
+ vars(self).iteritems())
try:
command = self.checker_command % escaped_attrs
except TypeError, error:
logger.error(u'Could not format string "%s":'
u' %s', self.checker_command, error)
return True # Try again later
- self.current_checker_command = command
try:
logger.info(u"Starting checker %r for %s",
command, self.name)
@@ -485,17 +421,15 @@
# always replaced by /dev/null.)
self.checker = subprocess.Popen(command,
close_fds=True,
- shell=True, cwd=u"/")
+ shell=True, cwd="/")
+ # 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))
- # The checker may have completed before the gobject
- # watch was added. Check for this.
- pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
- if pid:
- gobject.source_remove(self.checker_callback_tag)
- self.checker_callback(pid, status, command)
except OSError, error:
logger.error(u"Failed to start subprocess: %s",
error)
@@ -507,427 +441,133 @@
if self.checker_callback_tag:
gobject.source_remove(self.checker_callback_tag)
self.checker_callback_tag = None
- if getattr(self, u"checker", None) is None:
+ if getattr(self, "checker", None) is None:
return
logger.debug(u"Stopping checker for %(name)s", vars(self))
try:
os.kill(self.checker.pid, signal.SIGTERM)
- #time.sleep(0.5)
+ #os.sleep(0.5)
#if self.checker.poll() is None:
# os.kill(self.checker.pid, signal.SIGKILL)
except OSError, error:
if error.errno != errno.ESRCH: # No such process
raise
self.checker = None
-
-def dbus_service_property(dbus_interface, signature=u"v",
- access=u"readwrite", byte_arrays=False):
- """Decorators for marking methods of a DBusObjectWithProperties to
- become properties on the D-Bus.
-
- The decorated method will be called with no arguments by "Get"
- and with one argument by "Set".
-
- The parameters, where they are supported, are the same as
- dbus.service.method, except there is only "signature", since the
- type from Get() and the type sent to Set() is the same.
- """
- # Encoding deeply encoded byte arrays is not supported yet by the
- # "Set" method, so we fail early here:
- if byte_arrays and signature != u"ay":
- raise ValueError(u"Byte arrays not supported for non-'ay'"
- u" signature %r" % signature)
- def decorator(func):
- func._dbus_is_property = True
- func._dbus_interface = dbus_interface
- func._dbus_signature = signature
- func._dbus_access = access
- func._dbus_name = func.__name__
- if func._dbus_name.endswith(u"_dbus_property"):
- func._dbus_name = func._dbus_name[:-14]
- func._dbus_get_args_options = {u'byte_arrays': byte_arrays }
- return func
- return decorator
-
-
-class DBusPropertyException(dbus.exceptions.DBusException):
- """A base class for D-Bus property-related exceptions
- """
- def __unicode__(self):
- return unicode(str(self))
-
-
-class DBusPropertyAccessException(DBusPropertyException):
- """A property's access permissions disallows an operation.
- """
- pass
-
-
-class DBusPropertyNotFound(DBusPropertyException):
- """An attempt was made to access a non-existing property.
- """
- pass
-
-
-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.
- """
-
- @staticmethod
- def _is_dbus_property(obj):
- return getattr(obj, u"_dbus_is_property", False)
-
- def _get_all_dbus_properties(self):
- """Returns a generator of (name, attribute) pairs
- """
- return ((prop._dbus_name, prop)
- for name, prop in
- inspect.getmembers(self, 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 + u"_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
- # No such property
- raise DBusPropertyNotFound(self.dbus_object_path + u":"
- + interface_name + u"."
- + property_name)
-
- @dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"ss",
- out_signature=u"v")
- def Get(self, interface_name, property_name):
- """Standard D-Bus property Get() method, see D-Bus standard.
- """
- prop = self._get_dbus_property(interface_name, property_name)
- if prop._dbus_access == u"write":
- raise DBusPropertyAccessException(property_name)
- value = prop()
- if not hasattr(value, u"variant_level"):
- return value
- return type(value)(value, variant_level=value.variant_level+1)
-
- @dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"ssv")
- def Set(self, interface_name, property_name, value):
- """Standard D-Bus property Set() method, see D-Bus standard.
- """
- prop = self._get_dbus_property(interface_name, property_name)
- if prop._dbus_access == u"read":
- raise DBusPropertyAccessException(property_name)
- if prop._dbus_get_args_options[u"byte_arrays"]:
- # The byte_arrays option is not supported yet on
- # signatures other than "ay".
- if prop._dbus_signature != u"ay":
- raise ValueError
- value = dbus.ByteArray(''.join(unichr(byte)
- for byte in value))
- prop(value)
-
- @dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"s",
- out_signature=u"a{sv}")
- def GetAll(self, interface_name):
- """Standard D-Bus property GetAll() method, see D-Bus
- standard.
-
- Note: Will not include properties with access="write".
- """
- all = {}
- for name, prop in self._get_all_dbus_properties():
- if (interface_name
- and interface_name != prop._dbus_interface):
- # Interface non-empty but did not match
- continue
- # Ignore write-only properties
- if prop._dbus_access == u"write":
- continue
- value = prop()
- if not hasattr(value, u"variant_level"):
- all[name] = value
- continue
- all[name] = type(value)(value, variant_level=
- value.variant_level+1)
- return dbus.Dictionary(all, signature=u"sv")
-
- @dbus.service.method(dbus.INTROSPECTABLE_IFACE,
- out_signature=u"s",
- path_keyword='object_path',
- connection_keyword='connection')
- def Introspect(self, object_path, connection):
- """Standard D-Bus method, overloaded to insert property tags.
- """
- xmlstring = dbus.service.Object.Introspect(self, object_path,
- connection)
- try:
- document = xml.dom.minidom.parseString(xmlstring)
- def make_tag(document, name, prop):
- e = document.createElement(u"property")
- e.setAttribute(u"name", name)
- e.setAttribute(u"type", prop._dbus_signature)
- e.setAttribute(u"access", prop._dbus_access)
- return e
- for if_tag in document.getElementsByTagName(u"interface"):
- for tag in (make_tag(document, name, prop)
- for name, prop
- in self._get_all_dbus_properties()
- if prop._dbus_interface
- == if_tag.getAttribute(u"name")):
- if_tag.appendChild(tag)
- # Add the names to the return values for the
- # "org.freedesktop.DBus.Properties" methods
- if (if_tag.getAttribute(u"name")
- == u"org.freedesktop.DBus.Properties"):
- for cn in if_tag.getElementsByTagName(u"method"):
- if cn.getAttribute(u"name") == u"Get":
- for arg in cn.getElementsByTagName(u"arg"):
- if (arg.getAttribute(u"direction")
- == u"out"):
- arg.setAttribute(u"name", u"value")
- elif cn.getAttribute(u"name") == u"GetAll":
- for arg in cn.getElementsByTagName(u"arg"):
- if (arg.getAttribute(u"direction")
- == u"out"):
- arg.setAttribute(u"name", u"props")
- xmlstring = document.toxml(u"utf-8")
- document.unlink()
- except (AttributeError, xml.dom.DOMException,
- xml.parsers.expat.ExpatError), error:
- logger.error(u"Failed to override Introspection method",
- error)
- return xmlstring
-
-
-class ClientDBus(Client, DBusObjectWithProperties):
- """A Client class using D-Bus
-
- Attributes:
- dbus_object_path: dbus.ObjectPath
- bus: dbus.SystemBus()
- """
-
- runtime_expansions = (Client.runtime_expansions
- + (u"dbus_object_path",))
-
- # dbus.service.Object doesn't use super(), so we can't either.
-
- def __init__(self, bus = None, *args, **kwargs):
- self._approvals_pending = 0
- self.bus = bus
- Client.__init__(self, *args, **kwargs)
- # Only now, when this client is initialized, can it show up on
- # the D-Bus
- client_object_name = unicode(self.name).translate(
- {ord(u"."): ord(u"_"),
- ord(u"-"): ord(u"_")})
- self.dbus_object_path = (dbus.ObjectPath
- (u"/clients/" + client_object_name))
- 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(u"ApprovalPending"),
- dbus_bool)
-
- 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, u"enabled", False)
- r = Client.enable(self)
- if oldstate != self.enabled:
- # Emit D-Bus signals
- self.PropertyChanged(dbus.String(u"Enabled"),
- dbus.Boolean(True, variant_level=1))
- self.PropertyChanged(
- dbus.String(u"LastEnabled"),
- self._datetime_to_dbus(self.last_enabled,
- variant_level=1))
- return r
-
- def disable(self, quiet = False):
- oldstate = getattr(self, u"enabled", False)
- r = Client.disable(self, quiet=quiet)
- if not quiet and oldstate != self.enabled:
- # Emit D-Bus signal
- self.PropertyChanged(dbus.String(u"Enabled"),
- dbus.Boolean(False, variant_level=1))
- return r
-
- def __del__(self, *args, **kwargs):
- try:
- self.remove_from_connection()
- except LookupError:
- pass
- if hasattr(DBusObjectWithProperties, u"__del__"):
- DBusObjectWithProperties.__del__(self, *args, **kwargs)
- Client.__del__(self, *args, **kwargs)
-
- def checker_callback(self, pid, condition, command,
- *args, **kwargs):
- self.checker_callback_tag = None
- self.checker = None
- # Emit D-Bus signal
- self.PropertyChanged(dbus.String(u"CheckerRunning"),
+ self.PropertyChanged(dbus.String(u"checker_running"),
dbus.Boolean(False, variant_level=1))
- if os.WIFEXITED(condition):
- exitstatus = os.WEXITSTATUS(condition)
- # Emit D-Bus signal
- self.CheckerCompleted(dbus.Int16(exitstatus),
- dbus.Int64(condition),
- dbus.String(command))
- else:
- # Emit D-Bus signal
- self.CheckerCompleted(dbus.Int16(-1),
- dbus.Int64(condition),
- dbus.String(command))
-
- return Client.checker_callback(self, pid, condition, command,
- *args, **kwargs)
-
- def checked_ok(self, *args, **kwargs):
- r = Client.checked_ok(self, *args, **kwargs)
- # Emit D-Bus signal
- self.PropertyChanged(
- dbus.String(u"LastCheckedOK"),
- (self._datetime_to_dbus(self.last_checked_ok,
- variant_level=1)))
- return r
-
- def need_approval(self, *args, **kwargs):
- r = Client.need_approval(self, *args, **kwargs)
- # Emit D-Bus signal
- self.PropertyChanged(
- dbus.String(u"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:
- old_checker_pid = self.checker.pid
- else:
- old_checker_pid = None
- r = Client.start_checker(self, *args, **kwargs)
- # Only if new checker process was started
- if (self.checker is not None
- and old_checker_pid != self.checker.pid):
- # Emit D-Bus signal
- self.CheckerStarted(self.current_checker_command)
- self.PropertyChanged(
- dbus.String(u"CheckerRunning"),
- dbus.Boolean(True, variant_level=1))
- return r
-
- def stop_checker(self, *args, **kwargs):
- old_checker = getattr(self, u"checker", None)
- r = Client.stop_checker(self, *args, **kwargs)
- if (old_checker is not None
- and getattr(self, u"checker", None) is None):
- self.PropertyChanged(dbus.String(u"CheckerRunning"),
- dbus.Boolean(False, variant_level=1))
- return r
-
- def _reset_approved(self):
- self._approved = None
- return False
-
- def approve(self, value=True):
- self.send_changedstate()
- self._approved = value
- gobject.timeout_add(self._timedelta_to_milliseconds
- (self.approval_duration),
- self._reset_approved)
-
-
- ## D-Bus methods, signals & properties
- _interface = u"se.bsnet.fukt.Mandos.Client"
-
- ## Signals
+
+ def still_valid(self):
+ """Has the timeout not yet passed for this client?"""
+ 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=u"nxs")
- def CheckerCompleted(self, exitcode, waitstatus, command):
+ @dbus.service.signal(_interface, signature="bqs")
+ def CheckerCompleted(self, success, condition, command):
"D-Bus signal"
pass
# CheckerStarted - signal
- @dbus.service.signal(_interface, signature=u"s")
+ @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=u"sv")
+ @dbus.service.signal(_interface, signature="sv")
def PropertyChanged(self, property, value):
"D-Bus signal"
pass
- # GotSecret - signal
- @dbus.service.signal(_interface)
- def GotSecret(self):
- """D-Bus signal
- Is sent after a successful transfer of secret from the Mandos
- server to mandos-client
- """
- pass
-
- # Rejected - signal
- @dbus.service.signal(_interface, signature=u"s")
- def Rejected(self, reason):
- "D-Bus signal"
- pass
-
- # NeedApproval - signal
- @dbus.service.signal(_interface, signature=u"tb")
- def NeedApproval(self, timeout, default):
- "D-Bus signal"
- return self.need_approval()
-
- ## Methods
-
- # Approve - method
- @dbus.service.method(_interface, in_signature=u"b")
- def Approve(self, value):
- self.approve(value)
-
- # CheckedOK - method
- @dbus.service.method(_interface)
- def CheckedOK(self):
- return self.checked_ok()
-
- # Enable - method
- @dbus.service.method(_interface)
- def Enable(self):
- "D-Bus method"
- self.enable()
+ # 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)
@@ -935,664 +575,230 @@
"D-Bus method"
self.start_checker()
- # Disable - method
+ # Stop - method
@dbus.service.method(_interface)
- def Disable(self):
+ def Stop(self):
"D-Bus method"
- self.disable()
+ self.stop()
# StopChecker - method
- @dbus.service.method(_interface)
- def StopChecker(self):
- self.stop_checker()
-
- ## Properties
-
- # ApprovalPending - property
- @dbus_service_property(_interface, signature=u"b", access=u"read")
- def ApprovalPending_dbus_property(self):
- return dbus.Boolean(bool(self.approvals_pending))
-
- # ApprovedByDefault - property
- @dbus_service_property(_interface, signature=u"b",
- access=u"readwrite")
- def ApprovedByDefault_dbus_property(self, value=None):
- 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(u"ApprovedByDefault"),
- dbus.Boolean(value, variant_level=1))
-
- # ApprovalDelay - property
- @dbus_service_property(_interface, signature=u"t",
- access=u"readwrite")
- def ApprovalDelay_dbus_property(self, value=None):
- 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(u"ApprovalDelay"),
- dbus.UInt64(value, variant_level=1))
-
- # ApprovalDuration - property
- @dbus_service_property(_interface, signature=u"t",
- access=u"readwrite")
- def ApprovalDuration_dbus_property(self, value=None):
- if value is None: # get
- return dbus.UInt64(self._timedelta_to_milliseconds(
- self.approval_duration))
- self.approval_duration = datetime.timedelta(0, 0, 0, value)
- # Emit D-Bus signal
- self.PropertyChanged(dbus.String(u"ApprovalDuration"),
- dbus.UInt64(value, variant_level=1))
-
- # Name - property
- @dbus_service_property(_interface, signature=u"s", access=u"read")
- def Name_dbus_property(self):
- return dbus.String(self.name)
-
- # Fingerprint - property
- @dbus_service_property(_interface, signature=u"s", access=u"read")
- def Fingerprint_dbus_property(self):
- return dbus.String(self.fingerprint)
-
- # Host - property
- @dbus_service_property(_interface, signature=u"s",
- access=u"readwrite")
- def Host_dbus_property(self, value=None):
- if value is None: # get
- return dbus.String(self.host)
- self.host = value
- # Emit D-Bus signal
- self.PropertyChanged(dbus.String(u"Host"),
- dbus.String(value, variant_level=1))
-
- # Created - property
- @dbus_service_property(_interface, signature=u"s", access=u"read")
- def Created_dbus_property(self):
- return dbus.String(self._datetime_to_dbus(self.created))
-
- # LastEnabled - property
- @dbus_service_property(_interface, signature=u"s", access=u"read")
- def LastEnabled_dbus_property(self):
- if self.last_enabled is None:
- return dbus.String(u"")
- return dbus.String(self._datetime_to_dbus(self.last_enabled))
-
- # Enabled - property
- @dbus_service_property(_interface, signature=u"b",
- access=u"readwrite")
- def Enabled_dbus_property(self, value=None):
- if value is None: # get
- return dbus.Boolean(self.enabled)
- if value:
- self.enable()
- else:
- self.disable()
-
- # LastCheckedOK - property
- @dbus_service_property(_interface, signature=u"s",
- access=u"readwrite")
- def LastCheckedOK_dbus_property(self, value=None):
- if value is not None:
- self.checked_ok()
- return
- if self.last_checked_ok is None:
- return dbus.String(u"")
- return dbus.String(self._datetime_to_dbus(self
- .last_checked_ok))
-
- # LastApprovalRequest - property
- @dbus_service_property(_interface, signature=u"s", access=u"read")
- def LastApprovalRequest_dbus_property(self):
- if self.last_approval_request is None:
- return dbus.String(u"")
- return dbus.String(self.
- _datetime_to_dbus(self
- .last_approval_request))
-
- # Timeout - property
- @dbus_service_property(_interface, signature=u"t",
- access=u"readwrite")
- def Timeout_dbus_property(self, value=None):
- 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(u"Timeout"),
- dbus.UInt64(value, variant_level=1))
- if getattr(self, u"disable_initiator_tag", None) is None:
- return
- # Reschedule timeout
- gobject.source_remove(self.disable_initiator_tag)
- self.disable_initiator_tag = None
- time_to_die = (self.
- _timedelta_to_milliseconds((self
- .last_checked_ok
- + self.timeout)
- - datetime.datetime
- .utcnow()))
- if time_to_die <= 0:
- # The timeout has passed
- self.disable()
- else:
- self.disable_initiator_tag = (gobject.timeout_add
- (time_to_die, self.disable))
-
- # Interval - property
- @dbus_service_property(_interface, signature=u"t",
- access=u"readwrite")
- def Interval_dbus_property(self, value=None):
- 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(u"Interval"),
- dbus.UInt64(value, variant_level=1))
- if getattr(self, u"checker_initiator_tag", None) is None:
- return
- # Reschedule checker run
- gobject.source_remove(self.checker_initiator_tag)
- 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=u"s",
- access=u"readwrite")
- def Checker_dbus_property(self, value=None):
- if value is None: # get
- return dbus.String(self.checker_command)
- self.checker_command = value
- # Emit D-Bus signal
- self.PropertyChanged(dbus.String(u"Checker"),
- dbus.String(self.checker_command,
- variant_level=1))
-
- # CheckerRunning - property
- @dbus_service_property(_interface, signature=u"b",
- access=u"readwrite")
- def CheckerRunning_dbus_property(self, value=None):
- if value is None: # get
- return dbus.Boolean(self.checker is not None)
- if value:
- self.start_checker()
- else:
- self.stop_checker()
-
- # ObjectPath - property
- @dbus_service_property(_interface, signature=u"o", access=u"read")
- def ObjectPath_dbus_property(self):
- return self.dbus_object_path # is already a dbus.ObjectPath
-
- # Secret = property
- @dbus_service_property(_interface, signature=u"ay",
- access=u"write", byte_arrays=True)
- def Secret_dbus_property(self, value):
- self.secret = str(value)
+ StopChecker = dbus.service.method(_interface)(stop_checker)
+ StopChecker.__name__ = "StopChecker"
del _interface
-class ProxyClient(object):
- def __init__(self, child_pipe, fpr, address):
- self._pipe = child_pipe
- 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)
- self._pipe.send(('getattr', name))
- data = self._pipe.recv()
- if data[0] == 'data':
- return data[1]
- if data[0] == 'function':
- def func(*args, **kwargs):
- 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 ClientHandler(socketserver.BaseRequestHandler, object):
- """A class to handle client connections.
-
- Instantiated once for each connection to handle it.
+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):
+ # ...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)))
+ if list_size.value == 0:
+ return None
+ cert = cert_list[0]
+ return ctypes.string_at(cert.data, cert.size)
+
+
+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))))
+ # New empty GnuTLS certificate
+ crt = gnutls.library.types.gnutls_openpgp_crt_t()
+ (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))
+ # Verify the self signature in the key
+ crtverify = ctypes.c_uint()
+ (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")
+ # New buffer for the fingerprint
+ 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)))
+ # Deinit the certificate
+ gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
+ # Convert the buffer to a Python bytestring
+ fpr = ctypes.string_at(buf, buf_len.value)
+ # Convert the bytestring to hexadecimal notation
+ hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
+ return hex_fpr
+
+
+class TCP_handler(SocketServer.BaseRequestHandler, object):
+ """A TCP request handler class.
+ Instantiated by IPv6_TCPServer for each request to handle it.
Note: This will run in its own forked process."""
def handle(self):
- with contextlib.closing(self.server.child_pipe) as child_pipe:
- logger.info(u"TCP connection from: %s",
- unicode(self.client_address))
- logger.debug(u"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 = u':'.join((u"NONE", u"+VERS-TLS1.1",
- # u"+AES-256-CBC", u"+SHA1",
- # u"+COMP-NULL", u"+CTYPE-OPENPGP",
- # u"+DHE-DSS"))
- # Use a fallback default, since this MUST be set.
- priority = self.server.gnutls_priority
- if priority is None:
- priority = u"NORMAL"
- (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()
- logger.debug(u"Protocol version: %r", line)
- try:
- if int(line.strip().split()[0]) > 1:
- raise RuntimeError
- except (ValueError, IndexError, RuntimeError), error:
- logger.error(u"Unknown protocol version: %s", error)
- return
-
- # Start GnuTLS connection
- try:
- session.handshake()
- except gnutls.errors.GNUTLSError, error:
- logger.warning(u"Handshake failed: %s", error)
- # Do not run session.bye() here: the session is not
- # established. Just abandon the request.
- return
- logger.debug(u"Handshake succeeded")
-
- approval_required = False
- try:
- try:
- fpr = self.fingerprint(self.peer_certificate
- (session))
- except (TypeError, gnutls.errors.GNUTLSError), error:
- logger.warning(u"Bad certificate: %s", error)
- return
- logger.debug(u"Fingerprint: %s", fpr)
-
- try:
- client = ProxyClient(child_pipe, fpr,
- self.client_address)
- except KeyError:
- return
-
- if client.approval_delay:
- delay = client.approval_delay
- client.approvals_pending += 1
- approval_required = True
-
- while True:
- if not client.enabled:
- logger.warning(u"Client %s is disabled",
- client.name)
- if self.server.use_dbus:
- # Emit D-Bus signal
- client.Rejected("Disabled")
- return
-
- if client._approved or not client.approval_delay:
- #We are approved or approval is disabled
- break
- elif client._approved is None:
- logger.info(u"Client %s needs approval",
- client.name)
- if self.server.use_dbus:
- # Emit D-Bus signal
- client.NeedApproval(
- client.approval_delay_milliseconds(),
- client.approved_by_default)
- else:
- logger.warning(u"Client %s was not approved",
- client.name)
- if self.server.use_dbus:
- # Emit D-Bus signal
- client.Rejected("Denied")
- 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.release()
- time2 = datetime.datetime.now()
- if (time2 - time) >= delay:
- if not client.approved_by_default:
- logger.warning("Client %s timed out while"
- " waiting for approval",
- client.name)
- if self.server.use_dbus:
- # Emit D-Bus signal
- client.Rejected("Approval timed out")
- return
- else:
- break
- else:
- delay -= time2 - time
-
- sent_size = 0
- while sent_size < len(client.secret):
- try:
- sent = session.send(client.secret[sent_size:])
- except (gnutls.errors.GNUTLSError), error:
- logger.warning("gnutls send failed")
- return
- logger.debug(u"Sent: %d, remaining: %d",
- sent, len(client.secret)
- - (sent_size + sent))
- sent_size += sent
-
- logger.info(u"Sending secret to %s", client.name)
- # bump the timeout as if seen
- client.checked_ok()
- if self.server.use_dbus:
- # Emit D-Bus signal
- client.GotSecret()
-
- finally:
- if approval_required:
- client.approvals_pending -= 1
- try:
- session.bye()
- except (gnutls.errors.GNUTLSError), error:
- logger.warning("GnuTLS bye failed")
-
- @staticmethod
- 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):
- # ...do the normal thing
- return session.peer_certificate
- list_size = ctypes.c_uint(1)
- cert_list = (gnutls.library.functions
- .gnutls_certificate_get_peers
- (session._c_object, ctypes.byref(list_size)))
- if not bool(cert_list) and list_size.value != 0:
- raise gnutls.errors.GNUTLSError(u"error getting peer"
- u" certificate")
- if list_size.value == 0:
- return None
- cert = cert_list[0]
- return ctypes.string_at(cert.data, cert.size)
-
- @staticmethod
- def fingerprint(openpgp):
- "Convert an OpenPGP bytestring to a hexdigit fingerprint"
- # 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))))
- # New empty GnuTLS certificate
- crt = gnutls.library.types.gnutls_openpgp_crt_t()
- (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))
- # Verify the self signature in the key
- crtverify = ctypes.c_uint()
- (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
- (u"Verify failed"))
- # New buffer for the fingerprint
- 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)))
- # Deinit the certificate
- gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
- # Convert the buffer to a Python bytestring
- fpr = ctypes.string_at(buf, buf_len.value)
- # Convert the bytestring to hexadecimal notation
- hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
- return hex_fpr
-
-
-class MultiprocessingMixIn(object):
- """Like socketserver.ThreadingMixIn, but with multiprocessing"""
- def sub_process_main(self, request, address):
- try:
- self.finish_request(request, address)
- 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()
-
-class MultiprocessingMixInWithPipe(MultiprocessingMixIn, object):
- """ adds a pipe to the MixIn """
- def process_request(self, request, client_address):
- """Overrides and wraps the original process_request().
-
- This function creates a new pipe in self.pipe
- """
- parent_pipe, self.child_pipe = multiprocessing.Pipe()
-
- super(MultiprocessingMixInWithPipe,
- self).process_request(request, client_address)
- self.child_pipe.close()
- self.add_pipe(parent_pipe)
-
- def add_pipe(self, parent_pipe):
- """Dummy function; override as necessary"""
- pass
-
-class IPv6_TCPServer(MultiprocessingMixInWithPipe,
- socketserver.TCPServer, object):
- """IPv6-capable TCP server. Accepts 'None' as address and/or port
-
+ logger.info(u"TCP connection from: %s",
+ unicode(self.client_address))
+ session = (gnutls.connection
+ .ClientSession(self.request,
+ gnutls.connection
+ .X509Credentials()))
+
+ line = self.request.makefile().readline()
+ logger.debug(u"Protocol version: %r", line)
+ try:
+ if int(line.strip().split()[0]) > 1:
+ raise RuntimeError
+ except (ValueError, IndexError, RuntimeError), error:
+ logger.error(u"Unknown protocol version: %s", error)
+ return
+
+ # 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",
+ # "+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))
+
+ try:
+ session.handshake()
+ except gnutls.errors.GNUTLSError, error:
+ logger.warning(u"Handshake failed: %s", error)
+ # Do not run session.bye() here: the session is not
+ # established. Just abandon the request.
+ return
+ try:
+ fpr = fingerprint(peer_certificate(session))
+ except (TypeError, gnutls.errors.GNUTLSError), error:
+ logger.warning(u"Bad certificate: %s", error)
+ session.bye()
+ return
+ logger.debug(u"Fingerprint: %s", fpr)
+ for c in self.server.clients:
+ if c.fingerprint == fpr:
+ client = c
+ break
+ else:
+ logger.warning(u"Client not found for fingerprint: %s",
+ fpr)
+ session.bye()
+ return
+ # Have to check if client.still_valid(), since it is possible
+ # that the client timed out while establishing the GnuTLS
+ # session.
+ if not client.still_valid():
+ logger.warning(u"Client %(name)s is invalid",
+ vars(client))
+ session.bye()
+ return
+ ## This won't work here, since we're in a fork.
+ # client.bump_timeout()
+ sent_size = 0
+ while sent_size < len(client.secret):
+ sent = session.send(client.secret[sent_size:])
+ logger.debug(u"Sent: %d, remaining: %d",
+ sent, len(client.secret)
+ - (sent_size + sent))
+ sent_size += sent
+ session.bye()
+
+
+class IPv6_TCPServer(SocketServer.ForkingMixIn,
+ SocketServer.TCPServer, object):
+ """IPv6 TCP server. Accepts 'None' as address and/or port.
Attributes:
+ settings: Server settings
+ clients: Set() of Client objects
enabled: Boolean; whether this server is activated yet
- interface: None or a network interface name (string)
- use_ipv6: Boolean; to use IPv6 or not
"""
- def __init__(self, server_address, RequestHandlerClass,
- interface=None, use_ipv6=True):
- self.interface = interface
- if use_ipv6:
- self.address_family = socket.AF_INET6
- socketserver.TCPServer.__init__(self, server_address,
- RequestHandlerClass)
+ address_family = socket.AF_INET6
+ def __init__(self, *args, **kwargs):
+ if "settings" in kwargs:
+ self.settings = kwargs["settings"]
+ del kwargs["settings"]
+ if "clients" in kwargs:
+ self.clients = kwargs["clients"]
+ del kwargs["clients"]
+ self.enabled = False
+ super(IPv6_TCPServer, self).__init__(*args, **kwargs)
def server_bind(self):
"""This overrides the normal server_bind() function
to bind to an interface if one was specified, and also NOT to
bind to an address or port if they were not specified."""
- if self.interface is not None:
- if SO_BINDTODEVICE is None:
- logger.error(u"SO_BINDTODEVICE does not exist;"
- u" cannot bind to interface %s",
- self.interface)
- else:
- try:
- self.socket.setsockopt(socket.SOL_SOCKET,
- SO_BINDTODEVICE,
- str(self.interface
- + u'\0'))
- except socket.error, error:
- if error[0] == errno.EPERM:
- logger.error(u"No permission to"
- u" bind to interface %s",
- self.interface)
- elif error[0] == errno.ENOPROTOOPT:
- logger.error(u"SO_BINDTODEVICE not available;"
- u" cannot bind to interface %s",
- self.interface)
- else:
- raise
+ if self.settings["interface"]:
+ # 25 is from /usr/include/asm-i486/socket.h
+ SO_BINDTODEVICE = getattr(socket, "SO_BINDTODEVICE", 25)
+ try:
+ self.socket.setsockopt(socket.SOL_SOCKET,
+ SO_BINDTODEVICE,
+ self.settings["interface"])
+ except socket.error, error:
+ if error[0] == errno.EPERM:
+ logger.error(u"No permission to"
+ u" bind to interface %s",
+ self.settings["interface"])
+ else:
+ raise error
# Only bind(2) the socket if we really need to.
if self.server_address[0] or self.server_address[1]:
if not self.server_address[0]:
- if self.address_family == socket.AF_INET6:
- any_address = u"::" # in6addr_any
- else:
- any_address = socket.INADDR_ANY
- self.server_address = (any_address,
+ in6addr_any = "::"
+ self.server_address = (in6addr_any,
self.server_address[1])
elif not self.server_address[1]:
self.server_address = (self.server_address[0],
0)
-# if self.interface:
+# if self.settings["interface"]:
# self.server_address = (self.server_address[0],
# 0, # port
# 0, # flowinfo
# if_nametoindex
-# (self.interface))
- return socketserver.TCPServer.server_bind(self)
-
-
-class MandosServer(IPv6_TCPServer):
- """Mandos server.
-
- Attributes:
- clients: set of Client objects
- gnutls_priority GnuTLS priority string
- use_dbus: Boolean; to emit D-Bus signals or not
-
- Assumes a gobject.MainLoop event loop.
- """
- def __init__(self, server_address, RequestHandlerClass,
- interface=None, use_ipv6=True, clients=None,
- gnutls_priority=None, use_dbus=True):
- self.enabled = False
- self.clients = clients
- if self.clients is None:
- self.clients = set()
- self.use_dbus = use_dbus
- self.gnutls_priority = gnutls_priority
- IPv6_TCPServer.__init__(self, server_address,
- RequestHandlerClass,
- interface = interface,
- use_ipv6 = use_ipv6)
+# (self.settings
+# ["interface"]))
+ return super(IPv6_TCPServer, self).server_bind()
def server_activate(self):
if self.enabled:
- return socketserver.TCPServer.server_activate(self)
+ return super(IPv6_TCPServer, self).server_activate()
def enable(self):
self.enabled = True
- def add_pipe(self, parent_pipe):
- # 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))
-
- def handle_ipc(self, source, condition, parent_pipe=None,
- client_object=None):
- condition_names = {
- gobject.IO_IN: u"IN", # There is data to read.
- gobject.IO_OUT: u"OUT", # Data can be written (without
- # blocking).
- gobject.IO_PRI: u"PRI", # There is urgent data to read.
- gobject.IO_ERR: u"ERR", # Error condition.
- gobject.IO_HUP: u"HUP" # Hung up (the connection has been
- # broken, usually for pipes and
- # sockets).
- }
- conditions_string = ' | '.join(name
- for cond, name in
- condition_names.iteritems()
- if cond & condition)
- # error or the other end of multiprocessing.Pipe has closed
- if condition & (gobject.IO_ERR | condition & gobject.IO_HUP):
- return False
-
- # Read a request from the child
- request = parent_pipe.recv()
- command = request[0]
-
- if command == 'init':
- fpr = request[1]
- address = request[2]
-
- for c in self.clients:
- if c.fingerprint == fpr:
- client = c
- break
- else:
- logger.warning(u"Client not found for fingerprint: %s, ad"
- u"dress: %s", fpr, address)
- if self.use_dbus:
- # Emit D-Bus signal
- 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.send(True)
- # 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)))
-
- 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)))
-
- if command == 'setattr':
- attrname = request[1]
- value = request[2]
- setattr(client_object, attrname, value)
-
- return True
def string_to_delta(interval):
"""Parse a string and return a datetime.timedelta
-
- >>> string_to_delta(u'7d')
+
+ >>> string_to_delta('7d')
datetime.timedelta(7)
- >>> string_to_delta(u'60s')
+ >>> string_to_delta('60s')
datetime.timedelta(0, 60)
- >>> string_to_delta(u'60m')
+ >>> string_to_delta('60m')
datetime.timedelta(0, 3600)
- >>> string_to_delta(u'24h')
+ >>> string_to_delta('24h')
datetime.timedelta(1)
>>> string_to_delta(u'1w')
datetime.timedelta(7)
- >>> string_to_delta(u'5m 30s')
+ >>> string_to_delta('5m 30s')
datetime.timedelta(0, 330)
"""
timevalue = datetime.timedelta(0)
@@ -1611,46 +817,67 @@
elif suffix == u"w":
delta = datetime.timedelta(0, 0, 0, 0, 0, 0, value)
else:
- raise ValueError(u"Unknown suffix %r" % suffix)
- except (ValueError, IndexError), e:
- raise ValueError(e.message)
+ raise ValueError
+ except (ValueError, IndexError):
+ raise ValueError
timevalue += delta
return timevalue
+def server_state_changed(state):
+ """Derived from the Avahi example code"""
+ if state == avahi.SERVER_COLLISION:
+ logger.error(u"Zeroconf server name collision")
+ service.remove()
+ elif state == avahi.SERVER_RUNNING:
+ service.add()
+
+
+def entry_group_state_changed(state, error):
+ """Derived from the Avahi example code"""
+ logger.debug(u"Avahi state change: %i", state)
+
+ if state == avahi.ENTRY_GROUP_ESTABLISHED:
+ logger.debug(u"Zeroconf service established.")
+ elif state == avahi.ENTRY_GROUP_COLLISION:
+ logger.warning(u"Zeroconf service name collision.")
+ service.rename()
+ elif state == avahi.ENTRY_GROUP_FAILURE:
+ logger.critical(u"Avahi: Error in group state changed %s",
+ unicode(error))
+ raise AvahiGroupError("State changed: %s", str(error))
+
def if_nametoindex(interface):
- """Call the C function if_nametoindex(), or equivalent
-
- Note: This function cannot accept a unicode string."""
+ """Call the C function if_nametoindex(), or equivalent"""
global if_nametoindex
try:
if_nametoindex = (ctypes.cdll.LoadLibrary
- (ctypes.util.find_library(u"c"))
+ (ctypes.util.find_library("c"))
.if_nametoindex)
except (OSError, AttributeError):
- logger.warning(u"Doing if_nametoindex the hard way")
+ if "struct" not in sys.modules:
+ import struct
+ if "fcntl" not in sys.modules:
+ import fcntl
def if_nametoindex(interface):
"Get an interface index the hard way, i.e. using fcntl()"
SIOCGIFINDEX = 0x8933 # From /usr/include/linux/sockios.h
- with contextlib.closing(socket.socket()) as s:
+ with closing(socket.socket()) as s:
ifreq = fcntl.ioctl(s, SIOCGIFINDEX,
- struct.pack(str(u"16s16x"),
- interface))
- interface_index = struct.unpack(str(u"I"),
- ifreq[16:20])[0]
+ struct.pack("16s16x", interface))
+ interface_index = struct.unpack("I", ifreq[16:20])[0]
return interface_index
return if_nametoindex(interface)
def daemon(nochdir = False, noclose = False):
"""See daemon(3). Standard BSD Unix function.
-
This should really exist as os.daemon, but it doesn't (yet)."""
if os.fork():
sys.exit()
os.setsid()
if not nochdir:
- os.chdir(u"/")
+ os.chdir("/")
if os.fork():
sys.exit()
if not noclose:
@@ -1658,8 +885,7 @@
null = os.open(os.path.devnull, os.O_NOCTTY | os.O_RDWR)
if not stat.S_ISCHR(os.fstat(null).st_mode):
raise OSError(errno.ENODEV,
- u"%s not a character device"
- % os.path.devnull)
+ "/dev/null not a character device")
os.dup2(null, sys.stdin.fileno())
os.dup2(null, sys.stdout.fileno())
os.dup2(null, sys.stderr.fileno())
@@ -1668,37 +894,26 @@
def main():
-
- ##################################################################
- # Parsing of options, both command line and config file
-
- parser = optparse.OptionParser(version = "%%prog %s" % version)
- parser.add_option("-i", u"--interface", type=u"string",
- metavar="IF", help=u"Bind to interface IF")
- parser.add_option("-a", u"--address", type=u"string",
- help=u"Address to listen for requests on")
- parser.add_option("-p", u"--port", type=u"int",
- help=u"Port number to receive requests on")
- parser.add_option("--check", action=u"store_true",
- help=u"Run self-test")
- parser.add_option("--debug", action=u"store_true",
- help=u"Debug mode; run in foreground and log to"
- u" terminal")
- parser.add_option("--debuglevel", type=u"string", metavar="LEVEL",
- help=u"Debug level for stdout output")
- parser.add_option("--priority", type=u"string", help=u"GnuTLS"
- u" priority string (see GnuTLS documentation)")
- parser.add_option("--servicename", type=u"string",
- metavar=u"NAME", help=u"Zeroconf service name")
- parser.add_option("--configdir", type=u"string",
- default=u"/etc/mandos", metavar=u"DIR",
- help=u"Directory to search for configuration"
- u" files")
- parser.add_option("--no-dbus", action=u"store_false",
- dest=u"use_dbus", help=u"Do not provide D-Bus"
- u" system bus interface")
- parser.add_option("--no-ipv6", action=u"store_false",
- dest=u"use_ipv6", help=u"Do not use IPv6")
+ parser = OptionParser(version = "%%prog %s" % version)
+ parser.add_option("-i", "--interface", type="string",
+ metavar="IF", help="Bind to interface IF")
+ parser.add_option("-a", "--address", type="string",
+ help="Address to listen for requests on")
+ parser.add_option("-p", "--port", type="int",
+ help="Port number to receive requests on")
+ parser.add_option("--check", action="store_true", default=False,
+ help="Run self-test")
+ parser.add_option("--debug", action="store_true",
+ help="Debug mode; run in foreground and log to"
+ " terminal")
+ parser.add_option("--priority", type="string", help="GnuTLS"
+ " priority string (see GnuTLS documentation)")
+ parser.add_option("--servicename", type="string", metavar="NAME",
+ help="Zeroconf service name")
+ parser.add_option("--configdir", type="string",
+ default="/etc/mandos", metavar="DIR",
+ help="Directory to search for configuration"
+ " files")
options = parser.parse_args()[0]
if options.check:
@@ -1707,320 +922,235 @@
sys.exit()
# Default values for config file for server-global settings
- server_defaults = { u"interface": u"",
- u"address": u"",
- u"port": u"",
- u"debug": u"False",
- u"priority":
- u"SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
- u"servicename": u"Mandos",
- u"use_dbus": u"True",
- u"use_ipv6": u"True",
- u"debuglevel": u"",
+ server_defaults = { "interface": "",
+ "address": "",
+ "port": "",
+ "debug": "False",
+ "priority":
+ "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
+ "servicename": "Mandos",
}
# Parse config file for server-global settings
- server_config = configparser.SafeConfigParser(server_defaults)
+ server_config = ConfigParser.SafeConfigParser(server_defaults)
del server_defaults
- server_config.read(os.path.join(options.configdir,
- u"mandos.conf"))
+ server_config.read(os.path.join(options.configdir, "mandos.conf"))
# Convert the SafeConfigParser object to a dict
server_settings = server_config.defaults()
- # Use the appropriate methods on the non-string config options
- for option in (u"debug", u"use_dbus", u"use_ipv6"):
- server_settings[option] = server_config.getboolean(u"DEFAULT",
- option)
- if server_settings["port"]:
- server_settings["port"] = server_config.getint(u"DEFAULT",
- u"port")
+ # Use getboolean on the boolean config option
+ server_settings["debug"] = (server_config.getboolean
+ ("DEFAULT", "debug"))
del server_config
# Override the settings from the config file with command line
# options, if set.
- for option in (u"interface", u"address", u"port", u"debug",
- u"priority", u"servicename", u"configdir",
- u"use_dbus", u"use_ipv6", u"debuglevel"):
+ for option in ("interface", "address", "port", "debug",
+ "priority", "servicename", "configdir"):
value = getattr(options, option)
if value is not None:
server_settings[option] = value
del options
- # Force all strings to be unicode
- for option in server_settings.keys():
- if type(server_settings[option]) is str:
- server_settings[option] = unicode(server_settings[option])
# Now we have our good server settings in "server_settings"
- ##################################################################
-
- # For convenience
- debug = server_settings[u"debug"]
- debuglevel = server_settings[u"debuglevel"]
- use_dbus = server_settings[u"use_dbus"]
- use_ipv6 = server_settings[u"use_ipv6"]
-
- if server_settings[u"servicename"] != u"Mandos":
+ debug = server_settings["debug"]
+
+ if not debug:
+ syslogger.setLevel(logging.WARNING)
+ console.setLevel(logging.WARNING)
+
+ if server_settings["servicename"] != "Mandos":
syslogger.setFormatter(logging.Formatter
- (u'Mandos (%s) [%%(process)d]:'
- u' %%(levelname)s: %%(message)s'
- % server_settings[u"servicename"]))
+ ('Mandos (%s): %%(levelname)s:'
+ ' %%(message)s'
+ % server_settings["servicename"]))
# Parse config file with clients
- client_defaults = { u"timeout": u"1h",
- u"interval": u"5m",
- u"checker": u"fping -q -- %%(host)s",
- u"host": u"",
- u"approval_delay": u"0s",
- u"approval_duration": u"1s",
+ client_defaults = { "timeout": "1h",
+ "interval": "5m",
+ "checker": "fping -q -- %(host)s",
+ "host": "",
}
- client_config = configparser.SafeConfigParser(client_defaults)
- client_config.read(os.path.join(server_settings[u"configdir"],
- u"clients.conf"))
-
- global mandos_dbus_service
- mandos_dbus_service = None
-
- tcp_server = MandosServer((server_settings[u"address"],
- server_settings[u"port"]),
- ClientHandler,
- interface=(server_settings[u"interface"]
- or None),
- use_ipv6=use_ipv6,
- gnutls_priority=
- server_settings[u"priority"],
- use_dbus=use_dbus)
- if not debug:
- pidfilename = u"/var/run/mandos.pid"
- try:
- pidfile = open(pidfilename, u"w")
- except IOError:
- logger.error(u"Could not open file %r", pidfilename)
-
- try:
- uid = pwd.getpwnam(u"_mandos").pw_uid
- gid = pwd.getpwnam(u"_mandos").pw_gid
+ client_config = ConfigParser.SafeConfigParser(client_defaults)
+ client_config.read(os.path.join(server_settings["configdir"],
+ "clients.conf"))
+
+ clients = Set()
+ tcp_server = IPv6_TCPServer((server_settings["address"],
+ server_settings["port"]),
+ TCP_handler,
+ settings=server_settings,
+ clients=clients)
+ pidfilename = "/var/run/mandos.pid"
+ try:
+ pidfile = open(pidfilename, "w")
+ except IOError, error:
+ logger.error("Could not open file %r", pidfilename)
+
+ try:
+ uid = pwd.getpwnam("_mandos").pw_uid
except KeyError:
try:
- uid = pwd.getpwnam(u"mandos").pw_uid
- gid = pwd.getpwnam(u"mandos").pw_gid
+ uid = pwd.getpwnam("mandos").pw_uid
except KeyError:
try:
- uid = pwd.getpwnam(u"nobody").pw_uid
- gid = pwd.getpwnam(u"nobody").pw_gid
+ 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)
- os.setuid(uid)
except OSError, error:
if error[0] != errno.EPERM:
raise error
- if not debug and not debuglevel:
- syslogger.setLevel(logging.WARNING)
- console.setLevel(logging.WARNING)
- if debuglevel:
- level = getattr(logging, debuglevel.upper())
- syslogger.setLevel(level)
- console.setLevel(level)
-
- if debug:
- # Enable all possible GnuTLS debugging
-
- # "Use a log level over 10 to enable all debugging options."
- # - GnuTLS manual
- gnutls.library.functions.gnutls_global_set_log_level(11)
-
- @gnutls.library.types.gnutls_log_func
- def debug_gnutls(level, string):
- logger.debug(u"GnuTLS: %s", string[:-1])
-
- (gnutls.library.functions
- .gnutls_global_set_log_function(debug_gnutls))
-
- # Redirect stdin so all checkers get /dev/null
- null = os.open(os.path.devnull, os.O_NOCTTY | os.O_RDWR)
- os.dup2(null, sys.stdin.fileno())
- if null > 2:
- os.close(null)
- else:
- # No console logging
- logger.removeHandler(console)
-
+ global service
+ service = AvahiService(name = server_settings["servicename"],
+ servicetype = "_mandos._tcp", )
+ if server_settings["interface"]:
+ service.interface = (if_nametoindex
+ (server_settings["interface"]))
global main_loop
+ global bus
+ global server
# From the Avahi example code
DBusGMainLoop(set_as_default=True )
main_loop = gobject.MainLoop()
bus = dbus.SystemBus()
+ server = dbus.Interface(bus.get_object(avahi.DBUS_NAME,
+ avahi.DBUS_PATH_SERVER),
+ avahi.DBUS_INTERFACE_SERVER)
# End of Avahi example code
- if use_dbus:
- try:
- bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos",
- bus, do_not_queue=True)
- except dbus.exceptions.NameExistsException, e:
- logger.error(unicode(e) + u", disabling D-Bus")
- use_dbus = False
- server_settings[u"use_dbus"] = False
- tcp_server.use_dbus = False
- protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
- service = AvahiService(name = server_settings[u"servicename"],
- servicetype = u"_mandos._tcp",
- protocol = protocol, bus = bus)
- if server_settings["interface"]:
- service.interface = (if_nametoindex
- (str(server_settings[u"interface"])))
-
- if not debug:
+ bus_name = dbus.service.BusName(u"org.mandos-system.Mandos", bus)
+
+ clients.update(Set(Client(name = section,
+ config
+ = dict(client_config.items(section)))
+ for section in client_config.sections()))
+ if not clients:
+ logger.critical(u"No clients defined")
+ sys.exit(1)
+
+ if debug:
+ # Redirect stdin so all checkers get /dev/null
+ null = os.open(os.path.devnull, os.O_NOCTTY | os.O_RDWR)
+ os.dup2(null, sys.stdin.fileno())
+ if null > 2:
+ os.close(null)
+ else:
+ # No console logging
+ logger.removeHandler(console)
# Close all input and output, do double fork, etc.
daemon()
-
- global multiprocessing_manager
- multiprocessing_manager = multiprocessing.Manager()
-
- client_class = Client
- if use_dbus:
- client_class = functools.partial(ClientDBus, bus = bus)
- def client_config_items(config, section):
- special_settings = {
- "approved_by_default":
- lambda: config.getboolean(section,
- "approved_by_default"),
- }
- for name, value in config.items(section):
- try:
- yield (name, special_settings[name]())
- except KeyError:
- yield (name, value)
-
- tcp_server.clients.update(set(
- client_class(name = section,
- config= dict(client_config_items(
- client_config, section)))
- for section in client_config.sections()))
- if not tcp_server.clients:
- logger.warning(u"No clients defined")
-
+
+ try:
+ pid = os.getpid()
+ pidfile.write(str(pid) + "\n")
+ pidfile.close()
+ del pidfile
+ except IOError:
+ logger.error(u"Could not write to file %r with PID %d",
+ pidfilename, pid)
+ except NameError:
+ # "pidfile" was never created
+ pass
+ del pidfilename
+
+ def cleanup():
+ "Cleanup function; run on exit"
+ global group
+ # From the Avahi example code
+ if not group is None:
+ group.Free()
+ group = None
+ # End of Avahi example code
+
+ while clients:
+ client = clients.pop()
+ client.stop_hook = None
+ client.stop()
+
+ atexit.register(cleanup)
+
if not debug:
- try:
- with pidfile:
- pid = os.getpid()
- pidfile.write(str(pid) + "\n")
- del pidfile
- except IOError:
- logger.error(u"Could not write to file %r with PID %d",
- pidfilename, pid)
- except NameError:
- # "pidfile" was never created
- pass
- 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())
- if use_dbus:
- class MandosDBusService(dbus.service.Object):
- """A D-Bus proxy object"""
- def __init__(self):
- dbus.service.Object.__init__(self, bus, u"/")
- _interface = u"se.bsnet.fukt.Mandos"
-
- @dbus.service.signal(_interface, signature=u"o")
- def ClientAdded(self, objpath):
- "D-Bus signal"
- pass
-
- @dbus.service.signal(_interface, signature=u"ss")
- def ClientNotFound(self, fingerprint, address):
- "D-Bus signal"
- pass
-
- @dbus.service.signal(_interface, signature=u"os")
- def ClientRemoved(self, objpath, name):
- "D-Bus signal"
- pass
-
- @dbus.service.method(_interface, out_signature=u"ao")
- def GetAllClients(self):
- "D-Bus method"
- return dbus.Array(c.dbus_object_path
- for c in tcp_server.clients)
-
- @dbus.service.method(_interface,
- out_signature=u"a{oa{sv}}")
- def GetAllClientsWithProperties(self):
- "D-Bus method"
- return dbus.Dictionary(
- ((c.dbus_object_path, c.GetAll(u""))
- for c in tcp_server.clients),
- signature=u"oa{sv}")
-
- @dbus.service.method(_interface, in_signature=u"o")
- def RemoveClient(self, object_path):
- "D-Bus method"
- for c in tcp_server.clients:
- if c.dbus_object_path == object_path:
- tcp_server.clients.remove(c)
- c.remove_from_connection()
- # Don't signal anything except ClientRemoved
- c.disable(quiet=True)
- # Emit D-Bus signal
- self.ClientRemoved(object_path, c.name)
- return
- raise KeyError(object_path)
-
- del _interface
-
- mandos_dbus_service = MandosDBusService()
-
- def cleanup():
- "Cleanup function; run on exit"
- service.cleanup()
-
- while tcp_server.clients:
- client = tcp_server.clients.pop()
- if use_dbus:
- client.remove_from_connection()
- client.disable_hook = None
- # Don't signal anything except ClientRemoved
- client.disable(quiet=True)
- if use_dbus:
- # Emit D-Bus signal
- mandos_dbus_service.ClientRemoved(client.dbus_object_path,
- client.name)
-
- atexit.register(cleanup)
-
- for client in tcp_server.clients:
- if use_dbus:
- # Emit D-Bus signal
- mandos_dbus_service.ClientAdded(client.dbus_object_path)
- client.enable()
+ 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()
tcp_server.server_activate()
# Find out what port we got
service.port = tcp_server.socket.getsockname()[1]
- if use_ipv6:
- logger.info(u"Now listening on address %r, port %d,"
- " flowinfo %d, scope_id %d"
- % tcp_server.socket.getsockname())
- else: # IPv4
- logger.info(u"Now listening on address %r, port %d"
- % tcp_server.socket.getsockname())
+ logger.info(u"Now listening on address %r, port %d, flowinfo %d,"
+ u" scope_id %d" % tcp_server.socket.getsockname())
#service.interface = tcp_server.socket.getsockname()[3]
try:
# From the Avahi example code
+ server.connect_to_signal("StateChanged", server_state_changed)
try:
- service.activate()
+ server_state_changed(server.GetState())
except dbus.exceptions.DBusException, error:
logger.critical(u"DBusException: %s", error)
- cleanup()
sys.exit(1)
# End of Avahi example code
@@ -2032,16 +1162,11 @@
logger.debug(u"Starting main loop")
main_loop.run()
except AvahiError, error:
- logger.critical(u"AvahiError: %s", error)
- cleanup()
+ logger.critical(u"AvahiError: %s" + unicode(error))
sys.exit(1)
except KeyboardInterrupt:
if debug:
- print >> sys.stderr
- logger.debug(u"Server received KeyboardInterrupt")
- logger.debug(u"Server exiting")
- # Must run before the D-Bus bus name gets deregistered
- cleanup()
+ print
if __name__ == '__main__':
main()
=== modified file 'mandos-clients.conf.xml'
--- mandos-clients.conf.xml 2010-09-27 18:57:12 +0000
+++ mandos-clients.conf.xml 2008-10-07 21:31:09 +0000
@@ -3,7 +3,7 @@
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
/etc/mandos/clients.conf">
-
+
%common;
]>
@@ -33,8 +33,6 @@
2008
- 2009
- 2010
Teddy Hogeborn
Björn Påhlsson
@@ -64,8 +62,9 @@
>mandos
8, read by it at startup.
The file needs to list all clients that should be able to use
- the service. All clients listed will be regarded as enabled,
- even if a client was disabled in a previous run of the server.
+ the service. All clients listed will be regarded as valid, even
+ if a client was declared invalid in a previous run of the
+ server.
The format starts with a [section
@@ -101,53 +100,53 @@
-
-
-
- This option is optional.
-
-
- How long to wait for external approval before resorting to
- use the value. The
- default is 0s
, i.e. not to wait.
-
-
- The format of TIME is the same
- as for timeout below.
-
-
-
-
-
-
-
-
- This option is optional.
-
-
- How long an external approval lasts. The default is 1
- second.
-
-
- The format of TIME is the same
- as for timeout below.
-
-
-
-
-
-
-
-
- Whether to approve a client by default after
- the . The default
- is True
.
+
+
+
+ This option is optional.
+
+
+ The timeout is how long the server will wait for a
+ successful checker run until a client is considered
+ invalid - that is, ineligible to get the data this server
+ holds. By default Mandos will use 1 hour.
+
+
+ The TIME is specified as a
+ space-separated number of values, each of which is a
+ number and a one-character suffix. The suffix must be one
+ of d
, s
, m
,
+ h
, and w
for days, seconds,
+ minutes, hours, and weeks, respectively. The values are
+ added together to give the total time value, so all of
+ 330s
,
+ 110s 110s 110s
, and
+ 5m 30s
will give a value
+ of five minutes and thirty seconds.
+
+
+
+
+
+
+
+
+ This option is optional.
+
+
+ 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 marked invalid, and any running
+ checker killed. The default interval is 5 minutes.
+
+
+ The format of TIME is the same
+ as for timeout above.
@@ -170,7 +169,7 @@
PATH will be searched. The default
value for the checker command is fping %%(host)s
.
+ >-- %(host)s.
In addition to normal start time expansion, this option
@@ -197,70 +196,6 @@
-
-
-
- This option is optional, but highly
- recommended unless the
- option is modified to a
- non-standard value without %%(host)s
in it.
-
-
- Host name for this client. This is not used by the server
- directly, but can be, and is by default, used by the
- checker. See the option.
-
-
-
-
-
-
-
-
- This option is optional.
-
-
- 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 below
- timeout
occurs, at which
- time the client will be disabled, and any running checker
- killed. The default interval is 5 minutes.
-
-
- The format of TIME is the same
- as for timeout below.
-
-
-
-
-
-
-
-
- This option is only used if is not
- specified, in which case this option is
- required.
-
-
- Similar to the , except the secret
- data is in an external file. The contents of the file
- should not be base64-encoded, but
- will be sent to clients verbatim.
-
-
- File names of the form ~user/foo/bar
- and $ENVVAR/foo/bar
- are supported.
-
-
-
-
-
@@ -291,30 +226,42 @@
-
-
-
- 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 TIME is specified as a
- space-separated number of values, each of which is a
- number and a one-character suffix. The suffix must be one
- of d
, s
, m
,
- h
, and w
for days, seconds,
- minutes, hours, and weeks, respectively. The values are
- added together to give the total time value, so all of
- 330s
,
- 110s 110s 110s
, and
- 5m 30s
will give a value
- of five minutes and thirty seconds.
+
+
+
+ This option is only used if is not
+ specified, in which case this option is
+ required.
+
+
+ Similar to the , except the secret
+ data is in an external file. The contents of the file
+ should not be base64-encoded, but
+ will be sent to clients verbatim.
+
+
+ File names of the form ~user/foo/bar
+ and $ENVVAR/foo/bar
+ are supported.
+
+
+
+
+
+
+
+
+ This option is optional, but highly
+ recommended unless the
+ option is modified to a
+ non-standard value without %(host)s
in it.
+
+
+ Host name for this client. This is not used by the server
+ directly, but can be, and is by default, used by the
+ checker. See the option.
@@ -357,28 +304,10 @@
%%(foo)s
will be replaced by the value of the attribute
foo of the internal
- Client
object in the
- Mandos server. The currently allowed values for
- foo are:
- approval_delay
,
- approval_duration
,
- created
,
- enabled
,
- fingerprint
,
- host
,
- interval
,
- last_approval_request
,
- last_checked_ok
,
- last_enabled
,
- name
,
- timeout
, and, if using
- D-Bus, dbus_object_path
.
- See the source code for details. Currently, none of these attributes
- except host
are guaranteed
- to be valid in future versions. Therefore, please
- let the authors know of any attributes that are useful so they
- may be preserved to any new versions of this software.
+ Client
object. See the
+ source code for details, and let the authors know of any
+ attributes that are useful so they may be preserved to any new
+ versions of this software.
Note that this means that, in order to include an actual
@@ -421,7 +350,7 @@
[DEFAULT]
timeout = 1h
interval = 5m
-checker = fping -q -- %%(host)s
+checker = fping -q -- %(host)s
# Client "foo"
[foo]
@@ -450,8 +379,6 @@
fingerprint = 3e393aeaefb84c7e89e2f547b3a107558fca3a27
secfile = /etc/mandos/bar-secret
timeout = 15m
-approved_by_default = False
-approval_delay = 30s
=== removed file 'mandos-ctl'
--- mandos-ctl 2010-09-28 18:57:31 +0000
+++ mandos-ctl 1970-01-01 00:00:00 +0000
@@ -1,337 +0,0 @@
-#!/usr/bin/python
-# -*- mode: python; coding: utf-8 -*-
-#
-# Mandos Monitor - Control and monitor the Mandos server
-#
-# Copyright © 2008-2010 Teddy Hogeborn
-# Copyright © 2008-2010 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 .
-#
-
-from __future__ import division
-import sys
-import dbus
-from optparse import OptionParser
-import locale
-import datetime
-import re
-import os
-
-locale.setlocale(locale.LC_ALL, u'')
-
-tablewords = {
- 'Name': u'Name',
- 'Enabled': u'Enabled',
- 'Timeout': u'Timeout',
- 'LastCheckedOK': u'Last Successful Check',
- 'LastApprovalRequest': u'Last Approval Request',
- 'Created': u'Created',
- 'Interval': u'Interval',
- 'Host': u'Host',
- 'Fingerprint': u'Fingerprint',
- 'CheckerRunning': u'Check Is Running',
- 'LastEnabled': u'Last Enabled',
- 'ApprovalPending': u'Approval Is Pending',
- 'ApprovedByDefault': u'Approved By Default',
- 'ApprovalDelay': u"Approval Delay",
- 'ApprovalDuration': u"Approval Duration",
- 'Checker': u'Checker',
- }
-defaultkeywords = ('Name', 'Enabled', 'Timeout', 'LastCheckedOK')
-domain = 'se.bsnet.fukt'
-busname = domain + '.Mandos'
-server_path = '/'
-server_interface = domain + '.Mandos'
-client_interface = domain + '.Mandos.Client'
-version = "1.2"
-
-def timedelta_to_milliseconds(td):
- "Convert a datetime.timedelta object to milliseconds"
- return ((td.days * 24 * 60 * 60 * 1000)
- + (td.seconds * 1000)
- + (td.microseconds // 1000))
-
-def milliseconds_to_string(ms):
- td = datetime.timedelta(0, 0, 0, ms)
- return (u"%(days)s%(hours)02d:%(minutes)02d:%(seconds)02d"
- % { "days": "%dT" % td.days if td.days else "",
- "hours": td.seconds // 3600,
- "minutes": (td.seconds % 3600) // 60,
- "seconds": td.seconds % 60,
- })
-
-
-def string_to_delta(interval):
- """Parse a string and return a datetime.timedelta
-
- >>> string_to_delta('7d')
- datetime.timedelta(7)
- >>> string_to_delta('60s')
- datetime.timedelta(0, 60)
- >>> string_to_delta('60m')
- datetime.timedelta(0, 3600)
- >>> string_to_delta('24h')
- datetime.timedelta(1)
- >>> string_to_delta(u'1w')
- datetime.timedelta(7)
- >>> string_to_delta('5m 30s')
- datetime.timedelta(0, 330)
- """
- timevalue = datetime.timedelta(0)
- regexp = re.compile("\d+[dsmhw]")
-
- for s in regexp.findall(interval):
- try:
- suffix = unicode(s[-1])
- value = int(s[:-1])
- if suffix == u"d":
- delta = datetime.timedelta(value)
- elif suffix == u"s":
- delta = datetime.timedelta(0, value)
- elif suffix == u"m":
- delta = datetime.timedelta(0, 0, 0, 0, value)
- elif suffix == u"h":
- delta = datetime.timedelta(0, 0, 0, 0, 0, value)
- elif suffix == u"w":
- delta = datetime.timedelta(0, 0, 0, 0, 0, 0, value)
- else:
- raise ValueError
- except (ValueError, IndexError):
- raise ValueError
- timevalue += delta
- return timevalue
-
-def print_clients(clients, keywords):
- def valuetostring(value, keyword):
- if type(value) is dbus.Boolean:
- return u"Yes" if value else u"No"
- if keyword in (u"Timeout", u"Interval", u"ApprovalDelay",
- u"ApprovalDuration"):
- return milliseconds_to_string(value)
- return unicode(value)
-
- # Create format string to print table rows
- format_string = u' '.join(u'%%-%ds' %
- max(len(tablewords[key]),
- max(len(valuetostring(client[key],
- key))
- for client in
- clients))
- for key in keywords)
- # Print header line
- print format_string % tuple(tablewords[key] for key in keywords)
- for client in clients:
- print format_string % tuple(valuetostring(client[key], key)
- for key in keywords)
-
-def has_actions(options):
- return any((options.enable,
- options.disable,
- options.bump_timeout,
- options.start_checker,
- options.stop_checker,
- options.is_enabled,
- options.remove,
- options.checker is not None,
- options.timeout is not None,
- options.interval is not None,
- options.approved_by_default is not None,
- options.approval_delay is not None,
- options.approval_duration is not None,
- options.host is not None,
- options.secret is not None,
- options.approve,
- options.deny))
-
-def main():
- parser = OptionParser(version = "%%prog %s" % version)
- parser.add_option("-a", "--all", action="store_true",
- help="Select all clients")
- parser.add_option("-v", "--verbose", action="store_true",
- help="Print all fields")
- parser.add_option("-e", "--enable", action="store_true",
- help="Enable client")
- parser.add_option("-d", "--disable", action="store_true",
- help="disable client")
- parser.add_option("-b", "--bump-timeout", action="store_true",
- help="Bump timeout for client")
- parser.add_option("--start-checker", action="store_true",
- help="Start checker for client")
- parser.add_option("--stop-checker", action="store_true",
- help="Stop checker for client")
- parser.add_option("-V", "--is-enabled", action="store_true",
- help="Check if client is enabled")
- parser.add_option("-r", "--remove", action="store_true",
- help="Remove client")
- parser.add_option("-c", "--checker", type="string",
- help="Set checker command for client")
- parser.add_option("-t", "--timeout", type="string",
- help="Set timeout for client")
- parser.add_option("-i", "--interval", type="string",
- help="Set checker interval for client")
- parser.add_option("--approve-by-default", action="store_true",
- dest=u"approved_by_default",
- help="Set client to be approved by default")
- parser.add_option("--deny-by-default", action="store_false",
- dest=u"approved_by_default",
- help="Set client to be denied by default")
- parser.add_option("--approval-delay", type="string",
- help="Set delay before client approve/deny")
- parser.add_option("--approval-duration", type="string",
- help="Set duration of one client approval")
- parser.add_option("-H", "--host", type="string",
- help="Set host for client")
- parser.add_option("-s", "--secret", type="string",
- help="Set password blob (file) for client")
- parser.add_option("-A", "--approve", action="store_true",
- help="Approve any current client request")
- parser.add_option("-D", "--deny", action="store_true",
- help="Deny any current client request")
- options, client_names = parser.parse_args()
-
- if has_actions(options) and not client_names and not options.all:
- parser.error('Options require clients names or --all.')
- if options.verbose and has_actions(options):
- parser.error('--verbose can only be used alone or with'
- ' --all.')
- if options.all and not has_actions(options):
- parser.error('--all requires an action.')
-
- try:
- bus = dbus.SystemBus()
- mandos_dbus_objc = bus.get_object(busname, server_path)
- except dbus.exceptions.DBusException:
- print >> sys.stderr, "Could not connect to Mandos server"
- sys.exit(1)
-
- mandos_serv = dbus.Interface(mandos_dbus_objc,
- dbus_interface = server_interface)
-
- #block stderr since dbus library prints to stderr
- null = os.open(os.path.devnull, os.O_RDWR)
- stderrcopy = os.dup(sys.stderr.fileno())
- os.dup2(null, sys.stderr.fileno())
- os.close(null)
- try:
- try:
- mandos_clients = mandos_serv.GetAllClientsWithProperties()
- finally:
- #restore stderr
- os.dup2(stderrcopy, sys.stderr.fileno())
- os.close(stderrcopy)
- except dbus.exceptions.DBusException, e:
- print >> sys.stderr, "Access denied: Accessing mandos server through dbus."
- sys.exit(1)
-
- # Compile dict of (clients: properties) to process
- clients={}
-
- if options.all or not client_names:
- clients = dict((bus.get_object(busname, path), properties)
- for path, properties in
- mandos_clients.iteritems())
- else:
- for name in client_names:
- for path, client in mandos_clients.iteritems():
- if client['Name'] == name:
- client_objc = bus.get_object(busname, path)
- clients[client_objc] = client
- break
- else:
- print >> sys.stderr, "Client not found on server: %r" % name
- sys.exit(1)
-
- if not has_actions(options) and clients:
- if options.verbose:
- keywords = ('Name', 'Enabled', 'Timeout',
- 'LastCheckedOK', 'Created', 'Interval',
- 'Host', 'Fingerprint', 'CheckerRunning',
- 'LastEnabled', 'ApprovalPending',
- 'ApprovedByDefault',
- 'LastApprovalRequest', 'ApprovalDelay',
- 'ApprovalDuration', 'Checker')
- else:
- keywords = defaultkeywords
-
- print_clients(clients.values(), keywords)
- else:
- # Process each client in the list by all selected options
- for client in clients:
- if options.remove:
- mandos_serv.RemoveClient(client.__dbus_object_path__)
- if options.enable:
- client.Enable(dbus_interface=client_interface)
- if options.disable:
- client.Disable(dbus_interface=client_interface)
- if options.bump_timeout:
- client.CheckedOK(dbus_interface=client_interface)
- if options.start_checker:
- client.StartChecker(dbus_interface=client_interface)
- if options.stop_checker:
- client.StopChecker(dbus_interface=client_interface)
- if options.is_enabled:
- sys.exit(0 if client.Get(client_interface,
- u"Enabled",
- dbus_interface=dbus.PROPERTIES_IFACE)
- else 1)
- if options.checker:
- client.Set(client_interface, u"Checker", options.checker,
- dbus_interface=dbus.PROPERTIES_IFACE)
- if options.host:
- client.Set(client_interface, u"Host", options.host,
- dbus_interface=dbus.PROPERTIES_IFACE)
- if options.interval:
- client.Set(client_interface, u"Interval",
- timedelta_to_milliseconds
- (string_to_delta(options.interval)),
- dbus_interface=dbus.PROPERTIES_IFACE)
- if options.approval_delay:
- client.Set(client_interface, u"ApprovalDelay",
- timedelta_to_milliseconds
- (string_to_delta(options.
- approval_delay)),
- dbus_interface=dbus.PROPERTIES_IFACE)
- if options.approval_duration:
- client.Set(client_interface, u"ApprovalDuration",
- timedelta_to_milliseconds
- (string_to_delta(options.
- approval_duration)),
- dbus_interface=dbus.PROPERTIES_IFACE)
- if options.timeout:
- client.Set(client_interface, u"Timeout",
- timedelta_to_milliseconds
- (string_to_delta(options.timeout)),
- dbus_interface=dbus.PROPERTIES_IFACE)
- if options.secret:
- client.Set(client_interface, u"Secret",
- dbus.ByteArray(open(options.secret,
- u'rb').read()),
- dbus_interface=dbus.PROPERTIES_IFACE)
- if options.approved_by_default is not None:
- client.Set(client_interface, u"ApprovedByDefault",
- dbus.Boolean(options
- .approved_by_default),
- dbus_interface=dbus.PROPERTIES_IFACE)
- if options.approve:
- client.Approve(dbus.Boolean(True),
- dbus_interface=client_interface)
- elif options.deny:
- client.Approve(dbus.Boolean(False),
- dbus_interface=client_interface)
-
-if __name__ == '__main__':
- main()
=== removed file 'mandos-ctl.xml'
--- mandos-ctl.xml 2010-09-25 23:52:17 +0000
+++ mandos-ctl.xml 1970-01-01 00:00:00 +0000
@@ -1,570 +0,0 @@
-
-
-
-
-%common;
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &version;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@fukt.bsnet.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@fukt.bsnet.se
-
-
-
-
- 2010
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &COMMANDNAME;
- 8
-
-
-
- &COMMANDNAME;
-
- Control the operation of the Mandos server
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- CLIENT
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
- CLIENT
-
-
-
-
- &COMMANDNAME;
-
-
-
-
- CLIENT
-
-
- &COMMANDNAME;
-
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
-
-
-
-
- DESCRIPTION
-
- &COMMANDNAME; is a program to control the
- operation of the Mandos server mandos8.
-
-
- This program can be used to change client settings, approve or
- deny client requests, and to remove clients from the server.
-
-
-
-
- PURPOSE
-
- The purpose of this is to enable remote and unattended
- rebooting of client host computer with an
- encrypted root file system. See for details.
-
-
-
-
- OPTIONS
-
-
-
-
-
-
-
- Show a help message and exit
-
-
-
-
-
-
-
-
-
- Enable client(s). An enabled client will be eligble to
- receive its secret.
-
-
-
-
-
-
-
-
-
- Disable client(s). A disabled client will not be eligble
- to receive its secret, and no checkers will be started for
- it.
-
-
-
-
-
-
-
-
- Bump the timeout of the specified client(s), just as if a
- checker had completed successfully for it/them.
-
-
-
-
-
-
-
-
- Start a new checker now for the specified client(s).
-
-
-
-
-
-
-
-
- Stop any running checker for the specified client(s).
-
-
-
-
-
-
-
-
-
- Remove the specified client(s) from the server.
-
-
-
-
-
-
-
-
-
- Set the checker option of the specified
- client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
-
- Set the timeout option of the specified
- client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
-
- Set the interval option of the
- specified client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
-
- Set the approved_by_default option of
- the specified client(s) to True or
- False, respectively; see
- mandos-clients.conf5.
-
-
-
-
-
-
-
-
- Set the approval_delay option of the
- specified client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
- Set the approval_duration option of the
- specified client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
-
- Set the host option of the specified
- client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
-
- Set the secfile option of the specified
- client(s); see mandos-clients.conf5.
-
-
-
-
-
-
-
-
-
- Approve client(s) if currently waiting for approval.
-
-
-
-
-
-
-
-
-
- Deny client(s) if currently waiting for approval.
-
-
-
-
-
-
-
-
-
- Make the client-modifying options modify all clients.
-
-
-
-
-
-
-
-
-
- Show all client settings, not just a subset.
-
-
-
-
-
-
-
-
-
- Check if a single client is enabled or not, and exit with
- a successful exit status only if the client is enabled.
-
-
-
-
-
-
-
-
- OVERVIEW
-
-
- This program is a small utility to generate new OpenPGP keys for
- new Mandos clients, and to generate sections for inclusion in
- clients.conf on the server.
-
-
-
-
- EXIT STATUS
-
- If the option is used, the exit
- status will be 0 only if the specified client is enabled.
-
-
-
-
-
-
-
-
-
-
- EXAMPLE
-
-
- To list all clients:
-
-
- &COMMANDNAME;
-
-
-
-
-
- To list all settings for the clients
- named foo1.example.org
and foo2.example.org
:
-
-
-
-
-&COMMANDNAME; --verbose foo1.example.org foo2.example.org
-
-
-
-
-
-
- To enable all clients:
-
-
- &COMMANDNAME; --enable --all
-
-
-
-
-
- To change timeout and interval value for the clients
- named foo1.example.org
and foo2.example.org
:
-
-
-
-
-&COMMANDNAME; --timeout="5m" --interval="1m" foo1.example.org foo2.example.org
-
-
-
-
-
-
- To approve all clients currently waiting for it:
-
-
- &COMMANDNAME; --approve --all
-
-
-
-
-
- SECURITY
-
- This program must be permitted to access the Mandos server via
- the D-Bus interface. This normally requires the root user, but
- could be configured otherwise by reconfiguring the D-Bus server.
-
-
-
-
- SEE ALSO
-
- mandos
- 8,
- mandos-clients.conf
- 5,
- mandos-monitor
- 8
-
-
-
-
-
-
-
-
-
=== modified file 'mandos-keygen'
--- mandos-keygen 2010-10-01 18:40:55 +0000
+++ mandos-keygen 2008-11-11 16:07:18 +0000
@@ -2,8 +2,8 @@
#
# Mandos key generator - create a new OpenPGP key for a Mandos client
#
-# Copyright © 2008-2010 Teddy Hogeborn
-# Copyright © 2008-2010 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
@@ -21,7 +21,7 @@
# Contact the authors at .
#
-VERSION="1.2"
+VERSION="1.0.2"
KEYDIR="/etc/keys/mandos"
KEYTYPE=DSA
@@ -147,7 +147,7 @@
echo "Invalid key length" >&2
exit 1
fi
-
+
if [ -z "$KEYEXPIRE" ]; then
echo "Empty key expiration" >&2
exit 1
@@ -172,7 +172,7 @@
if [ -n "$KEYEMAIL" ]; then
KEYEMAILLINE="Name-Email: $KEYEMAIL"
fi
-
+
# Create temporary gpg batch file
BATCHFILE="`mktemp -t mandos-keygen-batch.XXXXXXXXXX`"
fi
@@ -195,8 +195,6 @@
stty echo; \
" EXIT
-set -e
-
umask 077
if [ "$mode" = keygen ]; then
@@ -219,27 +217,12 @@
%commit
EOF
- if tty --quiet; then
- cat <<-EOF
- Note: Due to entropy requirements, key generation could take
- anything from a few minutes to SEVERAL HOURS. Please be
- patient and/or supply the system with more entropy if needed.
- EOF
- echo -n "Started: "
- date
- fi
-
# Generate a new key in the key rings
gpg --quiet --batch --no-tty --no-options --enable-dsa2 \
--homedir "$RINGDIR" --trust-model always \
--gen-key "$BATCHFILE"
rm --force "$BATCHFILE"
- if tty --quiet; then
- echo -n "Finished: "
- date
- fi
-
# Backup any old key files
if cp --backup=numbered --force "$SECKEYFILE" "$SECKEYFILE" \
2>/dev/null; then
@@ -295,14 +278,13 @@
stty -echo
echo -n "Enter passphrase: " >&2
first="$(head --lines=1 | tr --delete '\n')"
- echo >&2
- echo -n "Repeat passphrase: " >&2
+ echo -n -e "\nRepeat passphrase: " >&2
second="$(head --lines=1 | tr --delete '\n')"
echo >&2
stty echo
if [ "$first" != "$second" ]; then
- echo "Passphrase mismatch" >&2
- touch "$RINGDIR"/mismatch
+ echo -e "Passphrase mismatch" >&2
+ false
else
echo -n "$first"
fi
@@ -310,9 +292,9 @@
--homedir "$RINGDIR" --trust-model always --armor --encrypt \
--sign --recipient "$FINGERPRINT" --comment "$FILECOMMENT" \
> "$SECFILE"
- if [ -e "$RINGDIR"/mismatch ]; then
- rm --force "$RINGDIR"/mismatch
- exit 1
+ status="${PIPESTATUS[0]}"
+ if [ "$status" -ne 0 ]; then
+ exit "$status"
fi
cat <<-EOF
=== modified file 'mandos-keygen.xml'
--- mandos-keygen.xml 2009-01-04 21:54:55 +0000
+++ mandos-keygen.xml 2008-10-04 01:55:56 +0000
@@ -2,7 +2,7 @@
-
+
%common;
]>
@@ -32,7 +32,6 @@
2008
- 2009
Teddy Hogeborn
Björn Påhlsson
=== removed file 'mandos-monitor'
--- mandos-monitor 2010-09-28 18:57:31 +0000
+++ mandos-monitor 1970-01-01 00:00:00 +0000
@@ -1,733 +0,0 @@
-#!/usr/bin/python
-# -*- mode: python; coding: utf-8 -*-
-#
-# Mandos Monitor - Control and monitor the Mandos server
-#
-# Copyright © 2009,2010 Teddy Hogeborn
-# Copyright © 2009,2010 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 .
-#
-
-from __future__ import division, absolute_import, with_statement
-
-import sys
-import os
-import signal
-
-import datetime
-
-import urwid.curses_display
-import urwid
-
-from dbus.mainloop.glib import DBusGMainLoop
-import gobject
-
-import dbus
-
-import UserList
-
-import locale
-
-locale.setlocale(locale.LC_ALL, u'')
-
-import logging
-logging.getLogger('dbus.proxies').setLevel(logging.CRITICAL)
-
-# Some useful constants
-domain = 'se.bsnet.fukt'
-server_interface = domain + '.Mandos'
-client_interface = domain + '.Mandos.Client'
-version = "1.2"
-
-# Always run in monochrome mode
-urwid.curses_display.curses.has_colors = lambda : False
-
-# Urwid doesn't support blinking, but we want it. Since we have no
-# use for underline on its own, we make underline also always blink.
-urwid.curses_display.curses.A_UNDERLINE |= (
- urwid.curses_display.curses.A_BLINK)
-
-def isoformat_to_datetime(iso):
- "Parse an ISO 8601 date string to a datetime.datetime()"
- if not iso:
- return None
- d, t = iso.split(u"T", 1)
- year, month, day = d.split(u"-", 2)
- hour, minute, second = t.split(u":", 2)
- second, fraction = divmod(float(second), 1)
- return datetime.datetime(int(year),
- int(month),
- int(day),
- int(hour),
- int(minute),
- int(second), # Whole seconds
- int(fraction*1000000)) # Microseconds
-
-class MandosClientPropertyCache(object):
- """This wraps a Mandos Client D-Bus proxy object, caches the
- properties and calls a hook function when any of them are
- changed.
- """
- def __init__(self, proxy_object=None, *args, **kwargs):
- self.proxy = proxy_object # Mandos Client proxy object
-
- self.properties = dict()
- self.proxy.connect_to_signal(u"PropertyChanged",
- self.property_changed,
- client_interface,
- byte_arrays=True)
-
- self.properties.update(
- self.proxy.GetAll(client_interface,
- dbus_interface = dbus.PROPERTIES_IFACE))
-
- #XXX This break good super behaviour!
-# super(MandosClientPropertyCache, self).__init__(
-# *args, **kwargs)
-
- def property_changed(self, property=None, value=None):
- """This is called whenever we get a PropertyChanged signal
- It updates the changed property in the "properties" dict.
- """
- # Update properties dict with new value
- self.properties[property] = value
-
-
-class MandosClientWidget(urwid.FlowWidget, MandosClientPropertyCache):
- """A Mandos Client which is visible on the screen.
- """
-
- def __init__(self, server_proxy_object=None, update_hook=None,
- delete_hook=None, logger=None, *args, **kwargs):
- # Called on update
- self.update_hook = update_hook
- # Called on delete
- self.delete_hook = delete_hook
- # Mandos Server proxy object
- self.server_proxy_object = server_proxy_object
- # Logger
- self.logger = logger
-
- self._update_timer_callback_tag = None
- self._update_timer_callback_lock = 0
- self.last_checker_failed = False
-
- # The widget shown normally
- self._text_widget = urwid.Text(u"")
- # The widget shown when we have focus
- self._focus_text_widget = urwid.Text(u"")
- super(MandosClientWidget, self).__init__(
- update_hook=update_hook, delete_hook=delete_hook,
- *args, **kwargs)
- self.update()
- self.opened = False
-
- last_checked_ok = isoformat_to_datetime(self.properties
- [u"LastCheckedOK"])
- if last_checked_ok is None:
- self.last_checker_failed = True
- else:
- self.last_checker_failed = ((datetime.datetime.utcnow()
- - last_checked_ok)
- > datetime.timedelta
- (milliseconds=
- self.properties
- [u"Interval"]))
-
- if self.last_checker_failed:
- self.using_timer(True)
-
- if self.need_approval:
- self.using_timer(True)
-
- self.proxy.connect_to_signal(u"CheckerCompleted",
- self.checker_completed,
- client_interface,
- byte_arrays=True)
- self.proxy.connect_to_signal(u"CheckerStarted",
- self.checker_started,
- client_interface,
- byte_arrays=True)
- self.proxy.connect_to_signal(u"GotSecret",
- self.got_secret,
- client_interface,
- byte_arrays=True)
- self.proxy.connect_to_signal(u"NeedApproval",
- self.need_approval,
- client_interface,
- byte_arrays=True)
- self.proxy.connect_to_signal(u"Rejected",
- self.rejected,
- client_interface,
- byte_arrays=True)
-
- def property_changed(self, property=None, value=None):
- super(self, MandosClientWidget).property_changed(property,
- value)
- if property == u"ApprovalPending":
- using_timer(bool(value))
-
- def using_timer(self, flag):
- """Call this method with True or False when timer should be
- activated or deactivated.
- """
- old = self._update_timer_callback_lock
- if flag:
- self._update_timer_callback_lock += 1
- else:
- self._update_timer_callback_lock -= 1
- if old == 0 and self._update_timer_callback_lock:
- self._update_timer_callback_tag = (gobject.timeout_add
- (1000,
- self.update_timer))
- elif old and self._update_timer_callback_lock == 0:
- gobject.source_remove(self._update_timer_callback_tag)
- self._update_timer_callback_tag = None
-
- def checker_completed(self, exitstatus, condition, command):
- if exitstatus == 0:
- if self.last_checker_failed:
- self.last_checker_failed = False
- self.using_timer(False)
- #self.logger(u'Checker for client %s (command "%s")'
- # u' was successful'
- # % (self.properties[u"Name"], command))
- self.update()
- return
- # Checker failed
- if not self.last_checker_failed:
- self.last_checker_failed = True
- self.using_timer(True)
- if os.WIFEXITED(condition):
- self.logger(u'Checker for client %s (command "%s")'
- u' failed with exit code %s'
- % (self.properties[u"Name"], command,
- os.WEXITSTATUS(condition)))
- elif os.WIFSIGNALED(condition):
- self.logger(u'Checker for client %s (command "%s")'
- u' was killed by signal %s'
- % (self.properties[u"Name"], command,
- os.WTERMSIG(condition)))
- elif os.WCOREDUMP(condition):
- self.logger(u'Checker for client %s (command "%s")'
- u' dumped core'
- % (self.properties[u"Name"], command))
- else:
- self.logger(u'Checker for client %s completed'
- u' mysteriously')
- self.update()
-
- def checker_started(self, command):
- #self.logger(u'Client %s started checker "%s"'
- # % (self.properties[u"Name"], unicode(command)))
- pass
-
- def got_secret(self):
- self.last_checker_failed = False
- self.logger(u'Client %s received its secret'
- % self.properties[u"Name"])
-
- def need_approval(self, timeout, default):
- if not default:
- message = u'Client %s needs approval within %s seconds'
- else:
- message = u'Client %s will get its secret in %s seconds'
- self.logger(message
- % (self.properties[u"Name"], timeout/1000))
- self.using_timer(True)
-
- def rejected(self, reason):
- self.logger(u'Client %s was rejected; reason: %s'
- % (self.properties[u"Name"], reason))
-
- def selectable(self):
- """Make this a "selectable" widget.
- This overrides the method from urwid.FlowWidget."""
- return True
-
- def rows(self, (maxcol,), focus=False):
- """How many rows this widget will occupy might depend on
- whether we have focus or not.
- This overrides the method from urwid.FlowWidget"""
- return self.current_widget(focus).rows((maxcol,), focus=focus)
-
- def current_widget(self, focus=False):
- if focus or self.opened:
- return self._focus_widget
- return self._widget
-
- def update(self):
- "Called when what is visible on the screen should be updated."
- # How to add standout mode to a style
- with_standout = { u"normal": u"standout",
- u"bold": u"bold-standout",
- u"underline-blink":
- u"underline-blink-standout",
- u"bold-underline-blink":
- u"bold-underline-blink-standout",
- }
-
- # Rebuild focus and non-focus widgets using current properties
-
- # Base part of a client. Name!
- base = (u'%(name)s: '
- % {u"name": self.properties[u"Name"]})
- if not self.properties[u"Enabled"]:
- message = u"DISABLED"
- elif self.properties[u"ApprovalPending"]:
- timeout = datetime.timedelta(milliseconds
- = self.properties
- [u"ApprovalDelay"])
- last_approval_request = isoformat_to_datetime(
- self.properties[u"LastApprovalRequest"])
- if last_approval_request is not None:
- timer = timeout - (datetime.datetime.utcnow()
- - last_approval_request)
- else:
- timer = datetime.timedelta()
- if self.properties[u"ApprovedByDefault"]:
- message = u"Approval in %s. (d)eny?"
- else:
- message = u"Denial in %s. (a)pprove?"
- message = message % unicode(timer).rsplit(".", 1)[0]
- elif self.last_checker_failed:
- timeout = datetime.timedelta(milliseconds
- = self.properties
- [u"Timeout"])
- last_ok = isoformat_to_datetime(
- max((self.properties[u"LastCheckedOK"]
- or self.properties[u"Created"]),
- self.properties[u"LastEnabled"]))
- timer = timeout - (datetime.datetime.utcnow() - last_ok)
- message = (u'A checker has failed! Time until client'
- u' gets disabled: %s'
- % unicode(timer).rsplit(".", 1)[0])
- else:
- message = u"enabled"
- self._text = "%s%s" % (base, message)
-
- if not urwid.supports_unicode():
- self._text = self._text.encode("ascii", "replace")
- textlist = [(u"normal", self._text)]
- self._text_widget.set_text(textlist)
- self._focus_text_widget.set_text([(with_standout[text[0]],
- text[1])
- if isinstance(text, tuple)
- else text
- for text in textlist])
- self._widget = self._text_widget
- self._focus_widget = urwid.AttrWrap(self._focus_text_widget,
- "standout")
- # Run update hook, if any
- if self.update_hook is not None:
- self.update_hook()
-
- def update_timer(self):
- "called by gobject"
- self.update()
- return True # Keep calling this
-
- def delete(self):
- if self._update_timer_callback_tag is not None:
- gobject.source_remove(self._update_timer_callback_tag)
- self._update_timer_callback_tag = None
- if self.delete_hook is not None:
- self.delete_hook(self)
-
- def render(self, (maxcol,), focus=False):
- """Render differently if we have focus.
- This overrides the method from urwid.FlowWidget"""
- return self.current_widget(focus).render((maxcol,),
- focus=focus)
-
- def keypress(self, (maxcol,), key):
- """Handle keys.
- This overrides the method from urwid.FlowWidget"""
- if key == u"+":
- self.proxy.Enable(dbus_interface = client_interface)
- elif key == u"-":
- self.proxy.Disable(dbus_interface = client_interface)
- elif key == u"a":
- self.proxy.Approve(dbus.Boolean(True, variant_level=1),
- dbus_interface = client_interface)
- elif key == u"d":
- self.proxy.Approve(dbus.Boolean(False, variant_level=1),
- dbus_interface = client_interface)
- elif key == u"R" or key == u"_" or key == u"ctrl k":
- self.server_proxy_object.RemoveClient(self.proxy
- .object_path)
- elif key == u"s":
- self.proxy.StartChecker(dbus_interface = client_interface)
- elif key == u"S":
- self.proxy.StopChecker(dbus_interface = client_interface)
- elif key == u"C":
- self.proxy.CheckedOK(dbus_interface = client_interface)
- # xxx
-# elif key == u"p" or key == "=":
-# self.proxy.pause()
-# elif key == u"u" or key == ":":
-# self.proxy.unpause()
-# elif key == u"RET":
-# self.open()
- else:
- return key
-
- def property_changed(self, property=None, value=None,
- *args, **kwargs):
- """Call self.update() if old value is not new value.
- This overrides the method from MandosClientPropertyCache"""
- property_name = unicode(property)
- old_value = self.properties.get(property_name)
- super(MandosClientWidget, self).property_changed(
- property=property, value=value, *args, **kwargs)
- if self.properties.get(property_name) != old_value:
- self.update()
-
-
-class ConstrainedListBox(urwid.ListBox):
- """Like a normal urwid.ListBox, but will consume all "up" or
- "down" key presses, thus not allowing any containing widgets to
- use them as an excuse to shift focus away from this widget.
- """
- def keypress(self, (maxcol, maxrow), key):
- ret = super(ConstrainedListBox, self).keypress((maxcol,
- maxrow), key)
- if ret in (u"up", u"down"):
- return
- return ret
-
-
-class UserInterface(object):
- """This is the entire user interface - the whole screen
- with boxes, lists of client widgets, etc.
- """
- def __init__(self, max_log_length=1000):
- DBusGMainLoop(set_as_default=True)
-
- self.screen = urwid.curses_display.Screen()
-
- self.screen.register_palette((
- (u"normal",
- u"default", u"default", None),
- (u"bold",
- u"default", u"default", u"bold"),
- (u"underline-blink",
- u"default", u"default", u"underline"),
- (u"standout",
- u"default", u"default", u"standout"),
- (u"bold-underline-blink",
- u"default", u"default", (u"bold", u"underline")),
- (u"bold-standout",
- u"default", u"default", (u"bold", u"standout")),
- (u"underline-blink-standout",
- u"default", u"default", (u"underline", u"standout")),
- (u"bold-underline-blink-standout",
- u"default", u"default", (u"bold", u"underline",
- u"standout")),
- ))
-
- if urwid.supports_unicode():
- self.divider = u"─" # \u2500
- #self.divider = u"━" # \u2501
- else:
- #self.divider = u"-" # \u002d
- self.divider = u"_" # \u005f
-
- self.screen.start()
-
- self.size = self.screen.get_cols_rows()
-
- self.clients = urwid.SimpleListWalker([])
- self.clients_dict = {}
-
- # We will add Text widgets to this list
- self.log = []
- self.max_log_length = max_log_length
-
- # We keep a reference to the log widget so we can remove it
- # from the ListWalker without it getting destroyed
- self.logbox = ConstrainedListBox(self.log)
-
- # This keeps track of whether self.uilist currently has
- # self.logbox in it or not
- self.log_visible = True
- self.log_wrap = u"any"
-
- self.rebuild()
- self.log_message_raw((u"bold",
- u"Mandos Monitor version " + version))
- self.log_message_raw((u"bold",
- u"q: Quit ?: Help"))
-
- self.busname = domain + '.Mandos'
- self.main_loop = gobject.MainLoop()
- self.bus = dbus.SystemBus()
- mandos_dbus_objc = self.bus.get_object(
- self.busname, u"/", follow_name_owner_changes=True)
- self.mandos_serv = dbus.Interface(mandos_dbus_objc,
- dbus_interface
- = server_interface)
- try:
- mandos_clients = (self.mandos_serv
- .GetAllClientsWithProperties())
- except dbus.exceptions.DBusException:
- mandos_clients = dbus.Dictionary()
-
- (self.mandos_serv
- .connect_to_signal(u"ClientRemoved",
- self.find_and_remove_client,
- dbus_interface=server_interface,
- byte_arrays=True))
- (self.mandos_serv
- .connect_to_signal(u"ClientAdded",
- self.add_new_client,
- dbus_interface=server_interface,
- byte_arrays=True))
- (self.mandos_serv
- .connect_to_signal(u"ClientNotFound",
- self.client_not_found,
- dbus_interface=server_interface,
- byte_arrays=True))
- for path, client in mandos_clients.iteritems():
- client_proxy_object = self.bus.get_object(self.busname,
- path)
- self.add_client(MandosClientWidget(server_proxy_object
- =self.mandos_serv,
- proxy_object
- =client_proxy_object,
- properties=client,
- update_hook
- =self.refresh,
- delete_hook
- =self.remove_client,
- logger
- =self.log_message),
- path=path)
-
- def client_not_found(self, fingerprint, address):
- self.log_message((u"Client with address %s and fingerprint %s"
- u" could not be found" % (address,
- fingerprint)))
-
- def rebuild(self):
- """This rebuilds the User Interface.
- Call this when the widget layout needs to change"""
- self.uilist = []
- #self.uilist.append(urwid.ListBox(self.clients))
- self.uilist.append(urwid.Frame(ConstrainedListBox(self.
- clients),
- #header=urwid.Divider(),
- header=None,
- footer=
- urwid.Divider(div_char=
- self.divider)))
- if self.log_visible:
- self.uilist.append(self.logbox)
- pass
- self.topwidget = urwid.Pile(self.uilist)
-
- def log_message(self, message):
- timestamp = datetime.datetime.now().isoformat()
- self.log_message_raw(timestamp + u": " + message)
-
- def log_message_raw(self, markup):
- """Add a log message to the log buffer."""
- self.log.append(urwid.Text(markup, wrap=self.log_wrap))
- if (self.max_log_length
- and len(self.log) > self.max_log_length):
- del self.log[0:len(self.log)-self.max_log_length-1]
- self.logbox.set_focus(len(self.logbox.body.contents),
- coming_from=u"above")
- self.refresh()
-
- def toggle_log_display(self):
- """Toggle visibility of the log buffer."""
- self.log_visible = not self.log_visible
- self.rebuild()
- #self.log_message(u"Log visibility changed to: "
- # + unicode(self.log_visible))
-
- def change_log_display(self):
- """Change type of log display.
- Currently, this toggles wrapping of text lines."""
- if self.log_wrap == u"clip":
- self.log_wrap = u"any"
- else:
- self.log_wrap = u"clip"
- for textwidget in self.log:
- textwidget.set_wrap_mode(self.log_wrap)
- #self.log_message(u"Wrap mode: " + self.log_wrap)
-
- def find_and_remove_client(self, path, name):
- """Find an client from its object path and remove it.
-
- This is connected to the ClientRemoved signal from the
- Mandos server object."""
- try:
- client = self.clients_dict[path]
- except KeyError:
- # not found?
- return
- self.remove_client(client, path)
-
- def add_new_client(self, path):
- client_proxy_object = self.bus.get_object(self.busname, path)
- self.add_client(MandosClientWidget(server_proxy_object
- =self.mandos_serv,
- proxy_object
- =client_proxy_object,
- update_hook
- =self.refresh,
- delete_hook
- =self.remove_client,
- logger
- =self.log_message),
- path=path)
-
- def add_client(self, client, path=None):
- self.clients.append(client)
- if path is None:
- path = client.proxy.object_path
- self.clients_dict[path] = client
- self.clients.sort(None, lambda c: c.properties[u"Name"])
- self.refresh()
-
- def remove_client(self, client, path=None):
- self.clients.remove(client)
- if path is None:
- path = client.proxy.object_path
- del self.clients_dict[path]
- if not self.clients_dict:
- # Work around bug in Urwid 0.9.8.3 - if a SimpleListWalker
- # is completely emptied, we need to recreate it.
- self.clients = urwid.SimpleListWalker([])
- self.rebuild()
- self.refresh()
-
- def refresh(self):
- """Redraw the screen"""
- canvas = self.topwidget.render(self.size, focus=True)
- self.screen.draw_screen(self.size, canvas)
-
- def run(self):
- """Start the main loop and exit when it's done."""
- self.refresh()
- self._input_callback_tag = (gobject.io_add_watch
- (sys.stdin.fileno(),
- gobject.IO_IN,
- self.process_input))
- self.main_loop.run()
- # Main loop has finished, we should close everything now
- gobject.source_remove(self._input_callback_tag)
- self.screen.stop()
-
- def stop(self):
- self.main_loop.quit()
-
- def process_input(self, source, condition):
- keys = self.screen.get_input()
- translations = { u"ctrl n": u"down", # Emacs
- u"ctrl p": u"up", # Emacs
- u"ctrl v": u"page down", # Emacs
- u"meta v": u"page up", # Emacs
- u" ": u"page down", # less
- u"f": u"page down", # less
- u"b": u"page up", # less
- u"j": u"down", # vi
- u"k": u"up", # vi
- }
- for key in keys:
- try:
- key = translations[key]
- except KeyError: # :-)
- pass
-
- if key == u"q" or key == u"Q":
- self.stop()
- break
- elif key == u"window resize":
- self.size = self.screen.get_cols_rows()
- self.refresh()
- elif key == u"\f": # Ctrl-L
- self.refresh()
- elif key == u"l" or key == u"D":
- self.toggle_log_display()
- self.refresh()
- elif key == u"w" or key == u"i":
- self.change_log_display()
- self.refresh()
- elif key == u"?" or key == u"f1" or key == u"esc":
- if not self.log_visible:
- self.log_visible = True
- self.rebuild()
- self.log_message_raw((u"bold",
- u" ".
- join((u"q: Quit",
- u"?: Help",
- u"l: Log window toggle",
- u"TAB: Switch window",
- u"w: Wrap (log)"))))
- self.log_message_raw((u"bold",
- u" "
- .join((u"Clients:",
- u"+: Enable",
- u"-: Disable",
- u"R: Remove",
- u"s: Start new checker",
- u"S: Stop checker",
- u"C: Checker OK",
- u"a: Approve",
- u"d: Deny"))))
- self.refresh()
- elif key == u"tab":
- if self.topwidget.get_focus() is self.logbox:
- self.topwidget.set_focus(0)
- else:
- self.topwidget.set_focus(self.logbox)
- self.refresh()
- #elif (key == u"end" or key == u"meta >" or key == u"G"
- # or key == u">"):
- # pass # xxx end-of-buffer
- #elif (key == u"home" or key == u"meta <" or key == u"g"
- # or key == u"<"):
- # pass # xxx beginning-of-buffer
- #elif key == u"ctrl e" or key == u"$":
- # pass # xxx move-end-of-line
- #elif key == u"ctrl a" or key == u"^":
- # pass # xxx move-beginning-of-line
- #elif key == u"ctrl b" or key == u"meta (" or key == u"h":
- # pass # xxx left
- #elif key == u"ctrl f" or key == u"meta )" or key == u"l":
- # pass # xxx right
- #elif key == u"a":
- # pass # scroll up log
- #elif key == u"z":
- # pass # scroll down log
- elif self.topwidget.selectable():
- self.topwidget.keypress(self.size, key)
- self.refresh()
- return True
-
-ui = UserInterface()
-try:
- ui.run()
-except KeyboardInterrupt:
- ui.screen.stop()
-except Exception, e:
- ui.log_message(unicode(e))
- ui.screen.stop()
- raise
=== removed file 'mandos-monitor.xml'
--- mandos-monitor.xml 2010-09-30 06:24:20 +0000
+++ mandos-monitor.xml 1970-01-01 00:00:00 +0000
@@ -1,233 +0,0 @@
-
-
-
-
-%common;
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &version;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@fukt.bsnet.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@fukt.bsnet.se
-
-
-
-
- 2010
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &COMMANDNAME;
- 8
-
-
-
- &COMMANDNAME;
-
- Text-based GUI to control the Mandos server.
-
-
-
-
-
- &COMMANDNAME;
-
-
-
-
- DESCRIPTION
-
- &COMMANDNAME; is an interactive program to
- monitor and control the operations of the Mandos server (see
- mandos8).
-
-
-
-
- PURPOSE
-
- The purpose of this is to enable remote and unattended
- rebooting of client host computer with an
- encrypted root file system. See for details.
-
-
-
-
- OVERVIEW
-
-
- This program is used to monitor and control the Mandos server.
- In particular, it can be used to approve Mandos clients which
- have been configured to require approval. It also shows all
- significant events reported by the Mandos server.
-
-
-
-
- KEYS
-
- This program is used to monitor and control the Mandos server.
- In particular, it can be used to approve Mandos clients which
- have been configured to require approval. It also shows all
- significant events reported by the Mandos server.
-
-
- Global Keys
-
- Keys
- Function
-
-
-
- q, Q
- Quit
-
-
- Ctrl-L
- Redraw screen
-
-
- ?, F1
- Show help
-
-
- l, D
- Toggle log window
-
-
- TAB
- Switch window
-
-
- w, i
- Toggle log window line wrap
-
-
- Up, Ctrl-P, k
- Move up a line
-
-
- Down, Ctrl-N, j
- Move down a line
-
-
- PageUp, Meta-V, b
- Move up a page
-
-
- PageDown, Ctrl-V, SPACE, f
- Move down a page
-
-
-
- Client List Keys
-
- Keys
- Function
-
-
-
- +
- Enable client
-
-
- -
- Disable client
-
-
- a
- Approve client
-
-
- d
- Deny client
-
-
- R, _, Ctrl-K
- Remove client
-
-
- s
- Start checker for client
-
-
- S
- Stop checker for client
-
-
- C
- Force a successful check for this client.
-
-
-
-
-
- BUGS
-
- This program can currently only be used to monitor and control a
- Mandos server with the default D-Bus service name of
- Mandos
.
-
-
-
-
- EXAMPLE
-
-
- This program takes no options:
-
-
- &COMMANDNAME;
-
-
-
-
-
- SECURITY
-
- This program must be permitted to access the Mandos server via
- the D-Bus interface. This normally requires the root user, but
- could be configured otherwise by reconfiguring the D-Bus server.
-
-
-
-
- SEE ALSO
-
- mandos
- 8,
- mandos-ctl
- 8
-
-
-
-
-
-
-
-
-
=== modified file 'mandos-options.xml'
--- mandos-options.xml 2009-02-13 05:38:21 +0000
+++ mandos-options.xml 2008-09-30 03:19:39 +0000
@@ -26,12 +26,10 @@
specified IPv6 address. If a link-local address is specified, an
interface should be set, since a link-local address is only valid
on a single interface. By default, the server will listen to all
- available addresses. If set, this must normally be an IPv6
- address; an IPv4 address can only be specified using IPv4-mapped
- IPv6 address syntax: ::FFFF:192.0.2.3
. (Only if IPv6 usage is
- disabled (see below) must this be an IPv4
- address.)
+ available addresses. If set, this must be an IPv6 address; an
+ IPv4 address can only be specified using IPv4-mapped IPv6 address
+ syntax: ::FFFF:192.0.2.3
.
@@ -68,22 +66,4 @@
so on; therefore, this option is not needed in that case.
-
- This option controls whether the server will provide a D-Bus
- system bus interface. The default is to provide such an
- interface.
-
-
-
- This option controls whether the server will use IPv6 sockets and
- addresses. The default is to use IPv6. This option should
- never normally be turned off, even in
- IPv4-only environments. This is because
- mandos-client
- 8mandos will normally use
- IPv6 link-local addresses, and will not be able to find or connect
- to the server if this option is turned off. Only
- advanced users should consider changing this option.
-
-
=== modified file 'mandos.conf'
--- mandos.conf 2009-02-13 05:38:21 +0000
+++ mandos.conf 2008-08-18 23:55:28 +0000
@@ -36,9 +36,3 @@
# If there are name collisions on the same *network*, the server will
# rename itself to "Mandos #2", etc.
;servicename = Mandos
-
-# Whether to provide a D-Bus system bus interface or not
-;use_dbus = True
-
-# Whether to use IPv6. (Changing this is NOT recommended.)
-;use_ipv6 = True
=== modified file 'mandos.conf.xml'
--- mandos.conf.xml 2009-02-25 01:14:29 +0000
+++ mandos.conf.xml 2008-09-30 07:23:39 +0000
@@ -3,7 +3,7 @@
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
/etc/mandos/mandos.conf">
-
+
%common;
]>
@@ -33,7 +33,6 @@
2008
- 2009
Teddy Hogeborn
Björn Påhlsson
@@ -131,28 +130,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -190,13 +167,11 @@
[DEFAULT]
# A configuration example
interface = eth0
-address = fe80::aede:48ff:fe71:f6f2
+address = 2001:db8:f983:bd0b:30de:ae4a:71f2:f672
port = 1025
debug = true
priority = SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP
servicename = Daena
-use_dbus = False
-use_ipv6 = True
@@ -237,7 +212,7 @@
The clients use IPv6 link-local addresses, which are
immediately usable since a link-local addresses is
- automatically assigned to a network interface when it
+ automatically assigned to a network interfaces when it
is brought up.
=== modified file 'mandos.lsm'
--- mandos.lsm 2010-09-28 18:57:31 +0000
+++ mandos.lsm 2008-12-10 01:26:02 +0000
@@ -1,7 +1,7 @@
Begin4
Title: Mandos
-Version: 1.2
-Entered-date: 2010-09-28
+Version: 1.0.2
+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.
@@ -12,10 +12,10 @@
Maintained-by: teddy@fukt.bsnet.se (Teddy Hogeborn),
belorn@fukt.bsnet.se (Björn Påhlsson)
Primary-site: http://www.fukt.bsnet.se/mandos
- 132K mandos_1.2.orig.tar.gz
+ 89K mandos_1.0.2.orig.tar.gz
Alternate-site: ftp://ftp.fukt.bsnet.se/pub/mandos
- 132K mandos_1.2.orig.tar.gz
-Platforms: Requires GCC, GNU libC, Avahi, GnuPG, Python 2.5, and
+ 89K mandos_1.0.2.orig.tar.gz
+Platforms: Requires GCC, GNU libC, Avahi, GnuPG, Python 2.4, and
various other libraries. While made for Debian GNU/Linux, it is
probably portable to other distributions, but not other Unixes.
Copying-policy: GNU General Public License version 3.0 or later
=== modified file 'mandos.xml'
--- mandos.xml 2010-09-27 17:39:03 +0000
+++ mandos.xml 2008-10-04 01:55:56 +0000
@@ -2,7 +2,7 @@
-
+
%common;
]>
@@ -32,8 +32,6 @@
2008
- 2009
- 2010
Teddy Hogeborn
Björn Påhlsson
@@ -86,13 +84,6 @@
DIRECTORY
-
-
-
-
-
-
&COMMANDNAME;
@@ -198,24 +189,6 @@
-
-
-
- Set the debugging log level.
- LEVEL is a string, one of
- CRITICAL
,
- ERROR
,
- WARNING
,
- INFO
, or
- DEBUG
, in order of
- increasing verbosity. The default level is
- WARNING
.
-
-
-
-
-
@@ -255,23 +228,6 @@
-
-
-
-
-
-
- See also .
-
-
-
-
-
-
-
-
-
-
@@ -349,35 +305,12 @@
The server will, by default, continually check that the clients
are still up. If a client has not been confirmed as being up
for some time, the client is assumed to be compromised and is no
- longer eligible to receive the encrypted password. (Manual
- intervention is required to re-enable a client.) The timeout,
+ longer eligible to receive the encrypted password. The timeout,
checker program, and interval between checks can be configured
both globally and per client; see
mandos-clients.conf
- 5. A client successfully
- receiving its password will also be treated as a successful
- checker run.
-
-
-
-
- APPROVAL
-
- The server can be configured to require manual approval for a
- client before it is sent its secret. The delay to wait for such
- approval and the default action (approve or deny) can be
- configured both globally and per client; see
- mandos-clients.conf
- 5. By default all clients
- will be approved immediately without delay.
-
-
- This can be used to deny a client its secret if not manually
- approved within a specified time. It can also be used to make
- the server delay before giving a client its secret, allowing
- optional manual denying of this specific client.
-
-
+ 5.
+
@@ -390,16 +323,6 @@
-
- D-BUS INTERFACE
-
- The server will by default provide a D-Bus system bus interface.
- This interface will only be accessible by the root user or a
- Mandos-specific user, if such a user exists. For documentation
- of the D-Bus API, see the file DBUS-API.
-
-
-
EXIT STATUS
@@ -460,8 +383,8 @@
/var/run/mandos.pid
- The file containing the process id of the
- &COMMANDNAME; process started last.
+ The file containing the process id of
+ &COMMANDNAME;.
@@ -495,9 +418,15 @@
backtrace. This could be considered a feature.
- Currently, if a client is disabled due to having timed out, the
- server does not record this fact onto permanent storage. This
- has some security implications, see .
+ Currently, if a client is declared invalid
due to
+ having timed out, the server does not record this fact onto
+ permanent storage. This has some security implications, see
+ .
+
+
+ There is currently no way of querying the server of the current
+ status of clients, other than analyzing its syslog output.
There is no fine-grained control over logging and debug output.
@@ -506,7 +435,7 @@
Debug mode is conflated with running in the foreground.
- The console log messages do not show a time stamp.
+ The console log messages does not show a time stamp.
This server does not check the expire time of clients’ OpenPGP
@@ -585,18 +514,19 @@
If a client is compromised, its downtime should be duly noted
- by the server which would therefore disable the client. But
- if the server was ever restarted, it would re-read its client
- list from its configuration file and again regard all clients
- therein as enabled, and hence eligible to receive their
- passwords. Therefore, be careful when restarting servers if
- it is suspected that a client has, in fact, been compromised
- by parties who may now be running a fake Mandos client with
- the keys from the non-encrypted initial RAM
- image of the client host. What should be done in that case
- (if restarting the server program really is necessary) is to
- stop the server program, edit the configuration file to omit
- any suspect clients, and restart the server program.
+ by the server which would therefore declare the client
+ invalid. But if the server was ever restarted, it would
+ re-read its client list from its configuration file and again
+ regard all clients therein as valid, and hence eligible to
+ receive their passwords. Therefore, be careful when
+ restarting servers if it is suspected that a client has, in
+ fact, been compromised by parties who may now be running a
+ fake Mandos client with the keys from the non-encrypted
+ initial RAM image of the client host. What
+ should be done in that case (if restarting the server program
+ really is necessary) is to stop the server program, edit the
+ configuration file to omit any suspect clients, and restart
+ the server program.
For more details on client-side security, see
=== modified file 'plugin-runner.c'
--- plugin-runner.c 2010-09-26 21:27:28 +0000
+++ plugin-runner.c 2008-11-11 16:07:18 +0000
@@ -1,9 +1,9 @@
-/* -*- coding: utf-8; mode: c; mode: orgtbl -*- */
+/* -*- coding: utf-8 -*- */
/*
* Mandos plugin runner - Run Mandos plugins
*
- * Copyright © 2008-2010 Teddy Hogeborn
- * Copyright © 2008-2010 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
@@ -23,14 +23,14 @@
*/
#define _GNU_SOURCE /* TEMP_FAILURE_RETRY(), getline(),
- asprintf(), O_CLOEXEC */
+ asprintf() */
#include /* size_t, NULL */
-#include /* malloc(), exit(), EXIT_SUCCESS,
- realloc() */
+#include /* malloc(), exit(), EXIT_FAILURE,
+ EXIT_SUCCESS, realloc() */
#include /* bool, true, false */
-#include /* fileno(), fprintf(),
+#include /* perror, fileno(), fprintf(),
stderr, STDOUT_FILENO */
-#include /* DIR, fdopendir(), stat(), struct
+#include /* DIR, opendir(), stat(), struct
stat, waitpid(), WIFEXITED(),
WEXITSTATUS(), wait(), pid_t,
uid_t, gid_t, getuid(), getgid(),
@@ -38,11 +38,10 @@
#include /* fd_set, select(), FD_ZERO(),
FD_SET(), FD_ISSET(), FD_CLR */
#include /* wait(), waitpid(), WIFEXITED(),
- WEXITSTATUS(), WTERMSIG(),
- WCOREDUMP() */
+ WEXITSTATUS() */
#include /* struct stat, stat(), S_ISREG() */
#include /* and, or, not */
-#include /* DIR, struct dirent, fdopendir(),
+#include /* DIR, struct dirent, opendir(),
readdir(), closedir(), dirfd() */
#include /* struct stat, stat(), S_ISREG(),
fcntl(), setuid(), setgid(),
@@ -53,8 +52,7 @@
close() */
#include /* fcntl(), F_GETFD, F_SETFD,
FD_CLOEXEC */
-#include /* strsep, strlen(), asprintf(),
- strsignal(), strcmp(), strncmp() */
+#include /* strsep, strlen(), asprintf() */
#include /* errno */
#include /* struct argp_option, struct
argp_state, struct argp,
@@ -64,14 +62,8 @@
#include /* struct sigaction, sigemptyset(),
sigaddset(), sigaction(),
sigprocmask(), SIG_BLOCK, SIGCHLD,
- SIG_UNBLOCK, kill(), sig_atomic_t
- */
+ SIG_UNBLOCK, kill() */
#include /* errno, EBADF */
-#include /* intmax_t, PRIdMAX, strtoimax() */
-#include /* EX_OSERR, EX_USAGE, EX_IOERR,
- EX_CONFIG, EX_UNAVAILABLE, EX_OK */
-#include /* errno */
-#include /* error() */
#define BUFFER_SIZE 256
@@ -88,7 +80,7 @@
char **environ;
int envc;
bool disabled;
-
+
/* Variables used for running processes*/
pid_t pid;
int fd;
@@ -96,8 +88,8 @@
size_t buffer_size;
size_t buffer_length;
bool eof;
- volatile sig_atomic_t completed;
- int status;
+ volatile bool completed;
+ volatile int status;
struct plugin *next;
} plugin;
@@ -106,61 +98,45 @@
/* Gets an existing plugin based on name,
or if none is found, creates a new one */
static plugin *getplugin(char *name){
- /* Check for existing plugin with that name */
- for(plugin *p = plugin_list; p != NULL; p = p->next){
- if((p->name == name)
- or (p->name and name and (strcmp(p->name, name) == 0))){
+ /* Check for exiting plugin with that name */
+ for (plugin *p = plugin_list; p != NULL; p = p->next){
+ if ((p->name == name)
+ or (p->name and name and (strcmp(p->name, name) == 0))){
return p;
}
}
/* Create a new plugin */
- plugin *new_plugin = NULL;
- do {
- new_plugin = malloc(sizeof(plugin));
- } while(new_plugin == NULL and errno == EINTR);
- if(new_plugin == NULL){
+ plugin *new_plugin = malloc(sizeof(plugin));
+ if (new_plugin == NULL){
return NULL;
}
char *copy_name = NULL;
if(name != NULL){
- do {
- copy_name = strdup(name);
- } while(copy_name == NULL and errno == EINTR);
+ copy_name = strdup(name);
if(copy_name == NULL){
- int e = errno;
- free(new_plugin);
- errno = e;
return NULL;
}
}
- *new_plugin = (plugin){ .name = copy_name,
- .argc = 1,
- .disabled = false,
- .next = plugin_list };
+ *new_plugin = (plugin) { .name = copy_name,
+ .argc = 1,
+ .disabled = false,
+ .next = plugin_list };
- do {
- new_plugin->argv = malloc(sizeof(char *) * 2);
- } while(new_plugin->argv == NULL and errno == EINTR);
- if(new_plugin->argv == NULL){
- int e = errno;
+ new_plugin->argv = malloc(sizeof(char *) * 2);
+ if (new_plugin->argv == NULL){
free(copy_name);
free(new_plugin);
- errno = e;
return NULL;
}
new_plugin->argv[0] = copy_name;
new_plugin->argv[1] = NULL;
- do {
- new_plugin->environ = malloc(sizeof(char *));
- } while(new_plugin->environ == NULL and errno == EINTR);
+ new_plugin->environ = malloc(sizeof(char *));
if(new_plugin->environ == NULL){
- int e = errno;
free(copy_name);
free(new_plugin->argv);
free(new_plugin);
- errno = e;
return NULL;
}
new_plugin->environ[0] = NULL;
@@ -174,19 +150,14 @@
static bool add_to_char_array(const char *new, char ***array,
int *len){
/* Resize the pointed-to array to hold one more pointer */
- do {
- *array = realloc(*array, sizeof(char *)
- * (size_t) ((*len) + 2));
- } while(*array == NULL and errno == EINTR);
+ *array = realloc(*array, sizeof(char *)
+ * (size_t) ((*len) + 2));
/* Malloc check */
if(*array == NULL){
return false;
}
/* Make a copy of the new string */
- char *copy;
- do {
- copy = strdup(new);
- } while(copy == NULL and errno == EINTR);
+ char *copy = strdup(new);
if(copy == NULL){
return false;
}
@@ -218,10 +189,7 @@
if(strncmp(*e, def, namelen + 1) == 0){
/* It already exists */
if(replace){
- char *new;
- do {
- new = realloc(*e, strlen(def) + 1);
- } while(new == NULL and errno == EINTR);
+ char *new = realloc(*e, strlen(def) + 1);
if(new == NULL){
return false;
}
@@ -237,24 +205,22 @@
/*
* Based on the example in the GNU LibC manual chapter 13.13 "File
* Descriptor Flags".
- | [[info:libc:Descriptor%20Flags][File Descriptor Flags]] |
+ * *Note File Descriptor Flags:(libc)Descriptor Flags.
*/
static int set_cloexec_flag(int fd){
- int ret = (int)TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD, 0));
+ int ret = fcntl(fd, F_GETFD, 0);
/* If reading the flags failed, return error indication now. */
if(ret < 0){
return ret;
}
/* Store modified flag word in the descriptor. */
- return (int)TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD,
- ret | FD_CLOEXEC));
+ return fcntl(fd, F_SETFD, ret | FD_CLOEXEC);
}
/* Mark processes as completed when they exit, and save their exit
status. */
static void handle_sigchld(__attribute__((unused)) int sig){
- int old_errno = errno;
while(true){
plugin *proc = plugin_list;
int status;
@@ -264,11 +230,11 @@
break;
}
if(pid == -1){
- if(errno == ECHILD){
- /* No child processes */
- break;
+ if (errno != ECHILD){
+ perror("waitpid");
}
- error(0, errno, "waitpid");
+ /* No child processes */
+ break;
}
/* A child exited, find it in process_list */
@@ -280,9 +246,8 @@
continue;
}
proc->status = status;
- proc->completed = 1;
+ proc->completed = true;
}
- errno = old_errno;
}
/* Prints out a password to stdout */
@@ -310,7 +275,7 @@
}
free(plugin_node->environ);
free(plugin_node->buffer);
-
+
/* Removes the plugin from the singly-linked list */
if(plugin_node == plugin_list){
/* First one - simple */
@@ -344,7 +309,6 @@
struct stat st;
fd_set rfds_all;
int ret, maxfd = 0;
- ssize_t sret;
uid_t uid = 65534;
gid_t gid = 65534;
bool debug = false;
@@ -359,14 +323,14 @@
sigemptyset(&sigchld_action.sa_mask);
ret = sigaddset(&sigchld_action.sa_mask, SIGCHLD);
if(ret == -1){
- error(0, errno, "sigaddset");
- exitstatus = EX_OSERR;
+ perror("sigaddset");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
ret = sigaction(SIGCHLD, &sigchld_action, &old_sigchld_action);
if(ret == -1){
- error(0, errno, "sigaction");
- exitstatus = EX_OSERR;
+ perror("sigaction");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
@@ -404,161 +368,130 @@
.doc = "Group ID the plugins will run as", .group = 3 },
{ .name = "debug", .key = 132,
.doc = "Debug mode", .group = 4 },
- /*
- * These reproduce what we would get without ARGP_NO_HELP
- */
- { .name = "help", .key = '?',
- .doc = "Give this help list", .group = -1 },
- { .name = "usage", .key = -3,
- .doc = "Give a short usage message", .group = -1 },
- { .name = "version", .key = 'V',
- .doc = "Print program version", .group = -1 },
{ .name = NULL }
};
- error_t parse_opt(int key, char *arg, struct argp_state *state){
- errno = 0;
- switch(key){
- char *tmp;
- intmax_t tmpmax;
+ error_t parse_opt (int key, char *arg, __attribute__((unused))
+ struct argp_state *state) {
+ switch (key) {
case 'g': /* --global-options */
- {
- char *plugin_option;
- while((plugin_option = strsep(&arg, ",")) != NULL){
- if(not add_argument(getplugin(NULL), plugin_option)){
- break;
+ if (arg != NULL){
+ char *p;
+ while((p = strsep(&arg, ",")) != NULL){
+ if(p[0] == '\0'){
+ continue;
+ }
+ if(not add_argument(getplugin(NULL), p)){
+ perror("add_argument");
+ return ARGP_ERR_UNKNOWN;
}
}
}
break;
case 'G': /* --global-env */
- add_environment(getplugin(NULL), arg, true);
+ if(arg == NULL){
+ break;
+ }
+ if(not add_environment(getplugin(NULL), arg, true)){
+ perror("add_environment");
+ }
break;
case 'o': /* --options-for */
- {
- char *option_list = strchr(arg, ':');
- if(option_list == NULL){
- argp_error(state, "No colon in \"%s\"", arg);
- errno = EINVAL;
- break;
- }
- *option_list = '\0';
- option_list++;
- if(arg[0] == '\0'){
- argp_error(state, "Empty plugin name");
- errno = EINVAL;
- break;
- }
- char *option;
- while((option = strsep(&option_list, ",")) != NULL){
- if(not add_argument(getplugin(arg), option)){
- break;
+ if (arg != NULL){
+ char *p_name = strsep(&arg, ":");
+ if(p_name[0] == '\0' or arg == NULL){
+ break;
+ }
+ char *opt = strsep(&arg, ":");
+ if(opt[0] == '\0' or opt == NULL){
+ break;
+ }
+ char *p;
+ while((p = strsep(&opt, ",")) != NULL){
+ if(p[0] == '\0'){
+ continue;
+ }
+ if(not add_argument(getplugin(p_name), p)){
+ perror("add_argument");
+ return ARGP_ERR_UNKNOWN;
}
}
}
break;
case 'E': /* --env-for */
+ if(arg == NULL){
+ break;
+ }
{
char *envdef = strchr(arg, ':');
if(envdef == NULL){
- argp_error(state, "No colon in \"%s\"", arg);
- errno = EINVAL;
break;
}
*envdef = '\0';
- envdef++;
- if(arg[0] == '\0'){
- argp_error(state, "Empty plugin name");
- errno = EINVAL;
- break;
+ if(not add_environment(getplugin(arg), envdef+1, true)){
+ perror("add_environment");
}
- add_environment(getplugin(arg), envdef, true);
}
break;
case 'd': /* --disable */
- {
+ if (arg != NULL){
plugin *p = getplugin(arg);
- if(p != NULL){
- p->disabled = true;
+ if(p == NULL){
+ return ARGP_ERR_UNKNOWN;
}
+ p->disabled = true;
}
break;
case 'e': /* --enable */
- {
+ if (arg != NULL){
plugin *p = getplugin(arg);
- if(p != NULL){
- p->disabled = false;
+ if(p == NULL){
+ return ARGP_ERR_UNKNOWN;
}
+ p->disabled = false;
}
break;
case 128: /* --plugin-dir */
free(plugindir);
plugindir = strdup(arg);
+ if(plugindir == NULL){
+ perror("strdup");
+ }
break;
case 129: /* --config-file */
/* This is already done by parse_opt_config_file() */
break;
case 130: /* --userid */
- tmpmax = strtoimax(arg, &tmp, 10);
- if(errno != 0 or tmp == arg or *tmp != '\0'
- or tmpmax != (uid_t)tmpmax){
- argp_error(state, "Bad user ID number: \"%s\", using %"
- PRIdMAX, arg, (intmax_t)uid);
- break;
- }
- uid = (uid_t)tmpmax;
+ uid = (uid_t)strtol(arg, NULL, 10);
break;
case 131: /* --groupid */
- tmpmax = strtoimax(arg, &tmp, 10);
- if(errno != 0 or tmp == arg or *tmp != '\0'
- or tmpmax != (gid_t)tmpmax){
- argp_error(state, "Bad group ID number: \"%s\", using %"
- PRIdMAX, arg, (intmax_t)gid);
- break;
- }
- gid = (gid_t)tmpmax;
+ gid = (gid_t)strtol(arg, NULL, 10);
break;
case 132: /* --debug */
debug = true;
break;
- /*
- * These reproduce what we would get without ARGP_NO_HELP
- */
- case '?': /* --help */
- state->flags &= ~(unsigned int)ARGP_NO_EXIT; /* force exit */
- argp_state_help(state, state->out_stream, ARGP_HELP_STD_HELP);
- case -3: /* --usage */
- state->flags &= ~(unsigned int)ARGP_NO_EXIT; /* force exit */
- argp_state_help(state, state->out_stream,
- ARGP_HELP_USAGE | ARGP_HELP_EXIT_OK);
- case 'V': /* --version */
- fprintf(state->out_stream, "%s\n", argp_program_version);
- exit(EXIT_SUCCESS);
- break;
-/*
- * When adding more options before this line, remember to also add a
- * "case" to the "parse_opt_config_file" function below.
- */
case ARGP_KEY_ARG:
/* Cryptsetup always passes an argument, which is an empty
string if "none" was specified in /etc/crypttab. So if
argument was empty, we ignore it silently. */
- if(arg[0] == '\0'){
- break;
+ if(arg[0] != '\0'){
+ fprintf(stderr, "Ignoring unknown argument \"%s\"\n", arg);
}
+ break;
+ case ARGP_KEY_END:
+ break;
default:
return ARGP_ERR_UNKNOWN;
}
- return errno; /* Set to 0 at start */
+ return 0;
}
/* This option parser is the same as parse_opt() above, except it
ignores everything but the --config-file option. */
- error_t parse_opt_config_file(int key, char *arg,
- __attribute__((unused))
- struct argp_state *state){
- errno = 0;
- switch(key){
+ error_t parse_opt_config_file (int key, char *arg,
+ __attribute__((unused))
+ struct argp_state *state) {
+ switch (key) {
case 'g': /* --global-options */
case 'G': /* --global-env */
case 'o': /* --options-for */
@@ -570,19 +503,20 @@
case 129: /* --config-file */
free(argfile);
argfile = strdup(arg);
- break;
+ if(argfile == NULL){
+ perror("strdup");
+ }
+ break;
case 130: /* --userid */
case 131: /* --groupid */
case 132: /* --debug */
- case '?': /* --help */
- case -3: /* --usage */
- case 'V': /* --version */
case ARGP_KEY_ARG:
+ case ARGP_KEY_END:
break;
default:
return ARGP_ERR_UNKNOWN;
}
- return errno;
+ return 0;
}
struct argp argp = { .options = options,
@@ -590,22 +524,12 @@
.args_doc = "",
.doc = "Mandos plugin runner -- Run plugins" };
- /* Parse using parse_opt_config_file() in order to get the custom
+ /* Parse using the parse_opt_config_file in order to get the custom
config file location, if any. */
- ret = argp_parse(&argp, argc, argv,
- ARGP_IN_ORDER | ARGP_NO_EXIT | ARGP_NO_HELP,
- NULL, NULL);
- switch(ret){
- case 0:
- break;
- case ENOMEM:
- default:
- errno = ret;
- error(0, errno, "argp_parse");
- exitstatus = EX_OSERR;
- goto fallback;
- case EINVAL:
- exitstatus = EX_USAGE;
+ ret = argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, NULL);
+ if (ret == ARGP_ERR_UNKNOWN){
+ fprintf(stderr, "Unknown error while parsing arguments\n");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
@@ -613,28 +537,29 @@
argp.parser = parse_opt;
/* Open the configfile if available */
- if(argfile == NULL){
+ if (argfile == NULL){
conffp = fopen(AFILE, "r");
} else {
conffp = fopen(argfile, "r");
- }
+ }
if(conffp != NULL){
char *org_line = NULL;
char *p, *arg, *new_arg, *line;
size_t size = 0;
+ ssize_t sret;
const char whitespace_delims[] = " \r\t\f\v\n";
const char comment_delim[] = "#";
-
+
custom_argc = 1;
custom_argv = malloc(sizeof(char*) * 2);
if(custom_argv == NULL){
- error(0, errno, "malloc");
- exitstatus = EX_OSERR;
+ perror("malloc");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
custom_argv[0] = argv[0];
custom_argv[1] = NULL;
-
+
/* for each line in the config file, strip whitespace and ignore
commented text */
while(true){
@@ -642,7 +567,7 @@
if(sret == -1){
break;
}
-
+
line = org_line;
arg = strsep(&line, comment_delim);
while((p = strsep(&arg, whitespace_delims)) != NULL){
@@ -651,8 +576,8 @@
}
new_arg = strdup(p);
if(new_arg == NULL){
- error(0, errno, "strdup");
- exitstatus = EX_OSERR;
+ perror("strdup");
+ exitstatus = EXIT_FAILURE;
free(org_line);
goto fallback;
}
@@ -661,70 +586,43 @@
custom_argv = realloc(custom_argv, sizeof(char *)
* ((unsigned int) custom_argc + 1));
if(custom_argv == NULL){
- error(0, errno, "realloc");
- exitstatus = EX_OSERR;
+ perror("realloc");
+ exitstatus = EXIT_FAILURE;
free(org_line);
goto fallback;
}
custom_argv[custom_argc-1] = new_arg;
- custom_argv[custom_argc] = NULL;
+ custom_argv[custom_argc] = NULL;
}
}
- do {
- ret = fclose(conffp);
- } while(ret == EOF and errno == EINTR);
- if(ret == EOF){
- error(0, errno, "fclose");
- exitstatus = EX_IOERR;
- goto fallback;
- }
free(org_line);
} else {
/* Check for harmful errors and go to fallback. Other errors might
not affect opening plugins */
- if(errno == EMFILE or errno == ENFILE or errno == ENOMEM){
- error(0, errno, "fopen");
- exitstatus = EX_OSERR;
+ if (errno == EMFILE or errno == ENFILE or errno == ENOMEM){
+ perror("fopen");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
}
- /* If there were any arguments from the configuration file, pass
- them to parser as command line arguments */
+ /* If there was any arguments from configuration file,
+ pass them to parser as command arguments */
if(custom_argv != NULL){
- ret = argp_parse(&argp, custom_argc, custom_argv,
- ARGP_IN_ORDER | ARGP_NO_EXIT | ARGP_NO_HELP,
- NULL, NULL);
- switch(ret){
- case 0:
- break;
- case ENOMEM:
- default:
- errno = ret;
- error(0, errno, "argp_parse");
- exitstatus = EX_OSERR;
- goto fallback;
- case EINVAL:
- exitstatus = EX_CONFIG;
+ ret = argp_parse (&argp, custom_argc, custom_argv, ARGP_IN_ORDER,
+ 0, NULL);
+ if (ret == ARGP_ERR_UNKNOWN){
+ fprintf(stderr, "Unknown error while parsing arguments\n");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
}
/* Parse actual command line arguments, to let them override the
config file */
- ret = argp_parse(&argp, argc, argv,
- ARGP_IN_ORDER | ARGP_NO_EXIT | ARGP_NO_HELP,
- NULL, NULL);
- switch(ret){
- case 0:
- break;
- case ENOMEM:
- default:
- errno = ret;
- error(0, errno, "argp_parse");
- exitstatus = EX_OSERR;
- goto fallback;
- case EINVAL:
- exitstatus = EX_USAGE;
+ ret = argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, NULL);
+ if (ret == ARGP_ERR_UNKNOWN){
+ fprintf(stderr, "Unknown error while parsing arguments\n");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
@@ -735,7 +633,7 @@
for(char **a = p->argv; *a != NULL; a++){
fprintf(stderr, "\tArg: %s\n", *a);
}
- fprintf(stderr, "...and %d environment variables\n", p->envc);
+ fprintf(stderr, "...and %u environment variables\n", p->envc);
for(char **a = p->environ; *a != NULL; a++){
fprintf(stderr, "\t%s\n", *a);
}
@@ -743,58 +641,37 @@
}
/* Strip permissions down to nobody */
+ ret = setuid(uid);
+ if (ret == -1){
+ perror("setuid");
+ }
setgid(gid);
- if(ret == -1){
- error(0, errno, "setgid");
- }
- ret = setuid(uid);
- if(ret == -1){
- error(0, errno, "setuid");
- }
-
- /* Open plugin directory with close_on_exec flag */
+ if (ret == -1){
+ perror("setgid");
+ }
+
+ if (plugindir == NULL){
+ dir = opendir(PDIR);
+ } else {
+ dir = opendir(plugindir);
+ }
+
+ if(dir == NULL){
+ perror("Could not open plugin dir");
+ exitstatus = EXIT_FAILURE;
+ goto fallback;
+ }
+
+ /* Set the FD_CLOEXEC flag on the directory, if possible */
{
- int dir_fd = -1;
- if(plugindir == NULL){
- dir_fd = open(PDIR, O_RDONLY |
-#ifdef O_CLOEXEC
- O_CLOEXEC
-#else /* not O_CLOEXEC */
- 0
-#endif /* not O_CLOEXEC */
- );
- } else {
- dir_fd = open(plugindir, O_RDONLY |
-#ifdef O_CLOEXEC
- O_CLOEXEC
-#else /* not O_CLOEXEC */
- 0
-#endif /* not O_CLOEXEC */
- );
- }
- if(dir_fd == -1){
- error(0, errno, "Could not open plugin dir");
- exitstatus = EX_UNAVAILABLE;
- goto fallback;
- }
-
-#ifndef O_CLOEXEC
- /* Set the FD_CLOEXEC flag on the directory */
- ret = set_cloexec_flag(dir_fd);
- if(ret < 0){
- error(0, errno, "set_cloexec_flag");
- TEMP_FAILURE_RETRY(close(dir_fd));
- exitstatus = EX_OSERR;
- goto fallback;
- }
-#endif /* O_CLOEXEC */
-
- dir = fdopendir(dir_fd);
- if(dir == NULL){
- error(0, errno, "Could not open plugin dir");
- TEMP_FAILURE_RETRY(close(dir_fd));
- exitstatus = EX_OSERR;
- goto fallback;
+ int dir_fd = dirfd(dir);
+ if(dir_fd >= 0){
+ ret = set_cloexec_flag(dir_fd);
+ if(ret < 0){
+ perror("set_cloexec_flag");
+ exitstatus = EXIT_FAILURE;
+ goto fallback;
+ }
}
}
@@ -802,15 +679,13 @@
/* Read and execute any executable in the plugin directory*/
while(true){
- do {
- dirst = readdir(dir);
- } while(dirst == NULL and errno == EINTR);
+ dirst = readdir(dir);
/* All directory entries have been processed */
if(dirst == NULL){
- if(errno == EBADF){
- error(0, errno, "readdir");
- exitstatus = EX_IOERR;
+ if (errno == EBADF){
+ perror("readdir");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
break;
@@ -846,7 +721,7 @@
for(const char **suf = bad_suffixes; *suf != NULL; suf++){
size_t suf_len = strlen(*suf);
if((d_name_len >= suf_len)
- and (strcmp((dirst->d_name) + d_name_len-suf_len, *suf)
+ and (strcmp((dirst->d_name)+d_name_len-suf_len, *suf)
== 0)){
if(debug){
fprintf(stderr, "Ignoring plugin dir entry \"%s\""
@@ -861,31 +736,27 @@
continue;
}
}
-
+
char *filename;
if(plugindir == NULL){
- ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, PDIR "/%s",
- dirst->d_name));
+ ret = asprintf(&filename, PDIR "/%s", dirst->d_name);
} else {
- ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, "%s/%s",
- plugindir,
- dirst->d_name));
+ ret = asprintf(&filename, "%s/%s", plugindir, dirst->d_name);
}
if(ret < 0){
- error(0, errno, "asprintf");
+ perror("asprintf");
continue;
}
- ret = (int)TEMP_FAILURE_RETRY(stat(filename, &st));
- if(ret == -1){
- error(0, errno, "stat");
+ ret = stat(filename, &st);
+ if (ret == -1){
+ perror("stat");
free(filename);
continue;
}
-
+
/* Ignore non-executable files */
- if(not S_ISREG(st.st_mode)
- or (TEMP_FAILURE_RETRY(access(filename, X_OK)) != 0)){
+ if (not S_ISREG(st.st_mode) or (access(filename, X_OK) != 0)){
if(debug){
fprintf(stderr, "Ignoring plugin dir entry \"%s\""
" with bad type or mode\n", filename);
@@ -896,7 +767,7 @@
plugin *p = getplugin(dirst->d_name);
if(p == NULL){
- error(0, errno, "getplugin");
+ perror("getplugin");
free(filename);
continue;
}
@@ -914,13 +785,13 @@
if(g != NULL){
for(char **a = g->argv + 1; *a != NULL; a++){
if(not add_argument(p, *a)){
- error(0, errno, "add_argument");
+ perror("add_argument");
}
}
/* Add global environment variables */
for(char **e = g->environ; *e != NULL; e++){
if(not add_environment(p, *e, false)){
- error(0, errno, "add_environment");
+ perror("add_environment");
}
}
}
@@ -931,67 +802,62 @@
if(p->environ[0] != NULL){
for(char **e = environ; *e != NULL; e++){
if(not add_environment(p, *e, false)){
- error(0, errno, "add_environment");
+ perror("add_environment");
}
}
}
int pipefd[2];
- ret = (int)TEMP_FAILURE_RETRY(pipe(pipefd));
- if(ret == -1){
- error(0, errno, "pipe");
- exitstatus = EX_OSERR;
+ ret = pipe(pipefd);
+ if (ret == -1){
+ perror("pipe");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
/* Ask OS to automatic close the pipe on exec */
ret = set_cloexec_flag(pipefd[0]);
if(ret < 0){
- error(0, errno, "set_cloexec_flag");
- exitstatus = EX_OSERR;
+ perror("set_cloexec_flag");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
ret = set_cloexec_flag(pipefd[1]);
if(ret < 0){
- error(0, errno, "set_cloexec_flag");
- exitstatus = EX_OSERR;
+ perror("set_cloexec_flag");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
/* Block SIGCHLD until process is safely in process list */
- ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_BLOCK,
- &sigchld_action.sa_mask,
- NULL));
+ ret = sigprocmask (SIG_BLOCK, &sigchld_action.sa_mask, NULL);
if(ret < 0){
- error(0, errno, "sigprocmask");
- exitstatus = EX_OSERR;
+ perror("sigprocmask");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
/* Starting a new process to be watched */
- pid_t pid;
- do {
- pid = fork();
- } while(pid == -1 and errno == EINTR);
+ pid_t pid = fork();
if(pid == -1){
- error(0, errno, "fork");
- exitstatus = EX_OSERR;
+ perror("fork");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
if(pid == 0){
/* this is the child process */
ret = sigaction(SIGCHLD, &old_sigchld_action, NULL);
if(ret < 0){
- error(0, errno, "sigaction");
- _exit(EX_OSERR);
+ perror("sigaction");
+ _exit(EXIT_FAILURE);
}
ret = sigprocmask(SIG_UNBLOCK, &sigchld_action.sa_mask, NULL);
if(ret < 0){
- error(0, errno, "sigprocmask");
- _exit(EX_OSERR);
+ perror("sigprocmask");
+ _exit(EXIT_FAILURE);
}
ret = dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */
if(ret == -1){
- error(0, errno, "dup2");
- _exit(EX_OSERR);
+ perror("dup2");
+ _exit(EXIT_FAILURE);
}
if(dirfd(dir) < 0){
@@ -1001,31 +867,28 @@
}
if(p->environ[0] == NULL){
if(execv(filename, p->argv) < 0){
- error(0, errno, "execv for %s", filename);
- _exit(EX_OSERR);
+ perror("execv");
+ _exit(EXIT_FAILURE);
}
} else {
if(execve(filename, p->argv, p->environ) < 0){
- error(0, errno, "execve for %s", filename);
- _exit(EX_OSERR);
+ perror("execve");
+ _exit(EXIT_FAILURE);
}
}
/* no return */
}
/* Parent process */
- TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of
- pipe */
+ close(pipefd[1]); /* Close unused write end of pipe */
free(filename);
plugin *new_plugin = getplugin(dirst->d_name);
- if(new_plugin == NULL){
- error(0, errno, "getplugin");
- ret = (int)(TEMP_FAILURE_RETRY
- (sigprocmask(SIG_UNBLOCK, &sigchld_action.sa_mask,
- NULL)));
+ if (new_plugin == NULL){
+ perror("getplugin");
+ ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask, NULL);
if(ret < 0){
- error(0, errno, "sigprocmask");
+ perror("sigprocmask");
}
- exitstatus = EX_OSERR;
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
@@ -1034,26 +897,22 @@
/* Unblock SIGCHLD so signal handler can be run if this process
has already completed */
- ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK,
- &sigchld_action.sa_mask,
- NULL));
+ ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask, NULL);
if(ret < 0){
- error(0, errno, "sigprocmask");
- exitstatus = EX_OSERR;
+ perror("sigprocmask");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
- FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from
- -Wconversion */
+ FD_SET(new_plugin->fd, &rfds_all);
- if(maxfd < new_plugin->fd){
+ if (maxfd < new_plugin->fd){
maxfd = new_plugin->fd;
}
}
- TEMP_FAILURE_RETRY(closedir(dir));
+ closedir(dir);
dir = NULL;
- free_plugin(getplugin(NULL));
for(plugin *p = plugin_list; p != NULL; p = p->next){
if(p->pid != 0){
@@ -1070,51 +929,44 @@
while(plugin_list){
fd_set rfds = rfds_all;
int select_ret = select(maxfd+1, &rfds, NULL, NULL, NULL);
- if(select_ret == -1 and errno != EINTR){
- error(0, errno, "select");
- exitstatus = EX_OSERR;
+ if (select_ret == -1){
+ perror("select");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
/* OK, now either a process completed, or something can be read
from one of them */
for(plugin *proc = plugin_list; proc != NULL;){
/* Is this process completely done? */
- if(proc->completed and proc->eof){
+ if(proc->eof and proc->completed){
/* Only accept the plugin output if it exited cleanly */
if(not WIFEXITED(proc->status)
or WEXITSTATUS(proc->status) != 0){
/* Bad exit by plugin */
-
+
if(debug){
if(WIFEXITED(proc->status)){
- fprintf(stderr, "Plugin %s [%" PRIdMAX "] exited with"
- " status %d\n", proc->name,
- (intmax_t) (proc->pid),
+ fprintf(stderr, "Plugin %u exited with status %d\n",
+ (unsigned int) (proc->pid),
WEXITSTATUS(proc->status));
- } else if(WIFSIGNALED(proc->status)){
- fprintf(stderr, "Plugin %s [%" PRIdMAX "] killed by"
- " signal %d: %s\n", proc->name,
- (intmax_t) (proc->pid),
- WTERMSIG(proc->status),
- strsignal(WTERMSIG(proc->status)));
+ } else if(WIFSIGNALED(proc->status)) {
+ fprintf(stderr, "Plugin %u killed by signal %d\n",
+ (unsigned int) (proc->pid),
+ WTERMSIG(proc->status));
} else if(WCOREDUMP(proc->status)){
- fprintf(stderr, "Plugin %s [%" PRIdMAX "] dumped"
- " core\n", proc->name, (intmax_t) (proc->pid));
+ fprintf(stderr, "Plugin %d dumped core\n",
+ (unsigned int) (proc->pid));
}
}
/* Remove the plugin */
- FD_CLR(proc->fd, &rfds_all); /* Spurious warning from
- -Wconversion */
-
+ FD_CLR(proc->fd, &rfds_all);
+
/* Block signal while modifying process_list */
- ret = (int)TEMP_FAILURE_RETRY(sigprocmask
- (SIG_BLOCK,
- &sigchld_action.sa_mask,
- NULL));
+ ret = sigprocmask(SIG_BLOCK, &sigchld_action.sa_mask, NULL);
if(ret < 0){
- error(0, errno, "sigprocmask");
- exitstatus = EX_OSERR;
+ perror("sigprocmask");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
@@ -1123,12 +975,11 @@
proc = next_plugin;
/* We are done modifying process list, so unblock signal */
- ret = (int)(TEMP_FAILURE_RETRY
- (sigprocmask(SIG_UNBLOCK,
- &sigchld_action.sa_mask, NULL)));
+ ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask,
+ NULL);
if(ret < 0){
- error(0, errno, "sigprocmask");
- exitstatus = EX_OSERR;
+ perror("sigprocmask");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
@@ -1144,16 +995,14 @@
bool bret = print_out_password(proc->buffer,
proc->buffer_length);
if(not bret){
- error(0, errno, "print_out_password");
- exitstatus = EX_IOERR;
+ perror("print_out_password");
+ exitstatus = EXIT_FAILURE;
}
goto fallback;
}
/* This process has not completed. Does it have any output? */
- if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious
- warning from
- -Wconversion */
+ if(proc->eof or not FD_ISSET(proc->fd, &rfds)){
/* This process had nothing to say at this time */
proc = proc->next;
continue;
@@ -1162,37 +1011,34 @@
if(proc->buffer_length + BUFFER_SIZE > proc->buffer_size){
proc->buffer = realloc(proc->buffer, proc->buffer_size
+ (size_t) BUFFER_SIZE);
- if(proc->buffer == NULL){
- error(0, errno, "malloc");
- exitstatus = EX_OSERR;
+ if (proc->buffer == NULL){
+ perror("malloc");
+ exitstatus = EXIT_FAILURE;
goto fallback;
}
proc->buffer_size += BUFFER_SIZE;
}
/* Read from the process */
- sret = TEMP_FAILURE_RETRY(read(proc->fd,
- proc->buffer
- + proc->buffer_length,
- BUFFER_SIZE));
- if(sret < 0){
+ ret = read(proc->fd, proc->buffer + proc->buffer_length,
+ BUFFER_SIZE);
+ if(ret < 0){
/* Read error from this process; ignore the error */
proc = proc->next;
continue;
}
- if(sret == 0){
+ if(ret == 0){
/* got EOF */
proc->eof = true;
} else {
- proc->buffer_length += (size_t) sret;
+ proc->buffer_length += (size_t) ret;
}
}
}
-
-
+
+
fallback:
- if(plugin_list == NULL or (exitstatus != EXIT_SUCCESS
- and exitstatus != EX_OK)){
+ if(plugin_list == NULL or exitstatus != EXIT_SUCCESS){
/* Fallback if all plugins failed, none are found or an error
occured */
bool bret;
@@ -1206,16 +1052,16 @@
}
bret = print_out_password(passwordbuffer, len);
if(not bret){
- error(0, errno, "print_out_password");
- exitstatus = EX_IOERR;
+ perror("print_out_password");
+ exitstatus = EXIT_FAILURE;
}
}
/* Restore old signal handler */
ret = sigaction(SIGCHLD, &old_sigchld_action, NULL);
if(ret == -1){
- error(0, errno, "sigaction");
- exitstatus = EX_OSERR;
+ perror("sigaction");
+ exitstatus = EXIT_FAILURE;
}
if(custom_argv != NULL){
@@ -1236,17 +1082,17 @@
ret = kill(p->pid, SIGTERM);
if(ret == -1 and errno != ESRCH){
/* Set-uid proccesses might not get closed */
- error(0, errno, "kill");
+ perror("kill");
}
}
}
/* Wait for any remaining child processes to terminate */
- do {
+ do{
ret = wait(NULL);
} while(ret >= 0);
if(errno != ECHILD){
- error(0, errno, "wait");
+ perror("wait");
}
free_plugin_list();
=== modified file 'plugin-runner.conf'
--- plugin-runner.conf 2009-04-17 08:26:17 +0000
+++ plugin-runner.conf 2008-10-05 17:38:31 +0000
@@ -1,10 +1,11 @@
-## This is the configuration file for plugin-runner(8mandos). This
-## file should be installed as "/etc/mandos/plugin-runner.conf", and
-## will be copied to "/conf/conf.d/mandos/plugin-runner.conf" in the
-## initrd.img file.
+## This is the configuration file for plugin-runner. It should be
+## installed as "/etc/mandos/plugin-runner.conf", which will be copied
+## to "/conf/conf.d/mandos/plugin-runner.conf" in the initrd.img file.
##
## After editing this file, the initrd image file must be updated for
## the changes to take effect!
-
-## Example:
-#--options-for=mandos-client:--debug
+##
+## The default network interface for mandos-client(8mandos) is
+## "eth0". Uncomment this line and change it if necessary.
+##
+#--options-for=mandos-client:--interface=eth0
=== modified file 'plugin-runner.xml'
--- plugin-runner.xml 2009-01-18 06:41:57 +0000
+++ plugin-runner.xml 2008-09-30 07:23:39 +0000
@@ -2,7 +2,7 @@
-
+
%common;
]>
@@ -32,7 +32,6 @@
2008
- 2009
Teddy Hogeborn
Björn Påhlsson
@@ -579,7 +578,7 @@
-cd /etc/keys/mandos; &COMMANDNAME; --config-file=/etc/mandos/plugin-runner.conf --plugin-dir /usr/lib/mandos/plugins.d --options-for=mandos-client:--pubkey=pubkey.txt,--seckey=seckey.txt
+&COMMANDNAME; --config-file=/etc/mandos/plugin-runner.conf --plugin-dir /usr/lib/mandos/plugins.d --options-for=mandos-client:--pubkey=/etc/keys/mandos/pubkey.txt,--seckey=/etc/keys/mandos/seckey.txt
=== modified file 'plugins.d/askpass-fifo.c'
--- plugins.d/askpass-fifo.c 2010-09-26 18:32:58 +0000
+++ plugins.d/askpass-fifo.c 2008-11-11 16:07:18 +0000
@@ -1,9 +1,9 @@
/* -*- coding: utf-8 -*- */
/*
- * Askpass-FIFO - Read a password from a FIFO and output it
+ * Passprompt - Read a password from a FIFO and output it
*
- * Copyright © 2008-2010 Teddy Hogeborn
- * Copyright © 2008-2010 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
@@ -19,26 +19,21 @@
* along with this program. If not, see
* .
*
- * Contact the authors at .
+ * Contact the authors at and
+ * .
*/
#define _GNU_SOURCE /* TEMP_FAILURE_RETRY() */
#include /* ssize_t */
#include /* mkfifo(), S_IRUSR, S_IWUSR */
#include /* and */
-#include /* errno, EACCES, ENOTDIR, ELOOP,
- ENAMETOOLONG, ENOSPC, EROFS,
- ENOENT, EEXIST, EFAULT, EMFILE,
- ENFILE, ENOMEM, EBADF, EINVAL, EIO,
- EISDIR, EFBIG */
-#include /* error() */
-#include /* EXIT_FAILURE, NULL, size_t, free(),
+#include /* errno, EEXIST */
+#include /* perror() */
+#include /* EXIT_FAILURE, NULL, size_t, free(),
realloc(), EXIT_SUCCESS */
#include /* open(), O_RDONLY */
#include /* read(), close(), write(),
STDOUT_FILENO */
-#include /* EX_OSERR, EX_OSFILE,
- EX_UNAVAILABLE, EX_IOERR */
int main(__attribute__((unused))int argc,
@@ -48,47 +43,17 @@
/* Create FIFO */
const char passfifo[] = "/lib/cryptsetup/passfifo";
- ret = mkfifo(passfifo, S_IRUSR | S_IWUSR);
- if(ret == -1){
- int e = errno;
- error(0, errno, "mkfifo");
- switch(e){
- case EACCES:
- case ENOTDIR:
- case ELOOP:
- return EX_OSFILE;
- case ENAMETOOLONG:
- case ENOSPC:
- case EROFS:
- default:
- return EX_OSERR;
- case ENOENT:
- return EX_UNAVAILABLE; /* no "/lib/cryptsetup"? */
- case EEXIST:
- break; /* not an error */
- }
+ ret = TEMP_FAILURE_RETRY(mkfifo(passfifo, S_IRUSR | S_IWUSR));
+ if(ret == -1 and errno != EEXIST){
+ perror("mkfifo");
+ return EXIT_FAILURE;
}
/* Open FIFO */
- int fifo_fd = open(passfifo, O_RDONLY);
+ int fifo_fd = TEMP_FAILURE_RETRY(open(passfifo, O_RDONLY));
if(fifo_fd == -1){
- int e = errno;
- error(0, errno, "open");
- switch(e){
- case EACCES:
- case ENOENT:
- case EFAULT:
- return EX_UNAVAILABLE;
- case ENAMETOOLONG:
- case EMFILE:
- case ENFILE:
- case ENOMEM:
- default:
- return EX_OSERR;
- case ENOTDIR:
- case ELOOP:
- return EX_OSFILE;
- }
+ perror("open");
+ return EXIT_FAILURE;
}
/* Read from FIFO */
@@ -97,78 +62,44 @@
{
size_t buf_allocated = 0;
const size_t blocksize = 1024;
- do {
+ do{
if(buf_len + blocksize > buf_allocated){
char *tmp = realloc(buf, buf_allocated + blocksize);
if(tmp == NULL){
- error(0, errno, "realloc");
+ perror("realloc");
free(buf);
- return EX_OSERR;
+ return EXIT_FAILURE;
}
buf = tmp;
buf_allocated += blocksize;
}
- sret = read(fifo_fd, buf + buf_len, buf_allocated - buf_len);
+ sret = TEMP_FAILURE_RETRY(read(fifo_fd, buf + buf_len,
+ buf_allocated - buf_len));
if(sret == -1){
- int e = errno;
+ perror("read");
free(buf);
- errno = e;
- error(0, errno, "read");
- switch(e){
- case EBADF:
- case EFAULT:
- case EINVAL:
- default:
- return EX_OSERR;
- case EIO:
- return EX_IOERR;
- case EISDIR:
- return EX_UNAVAILABLE;
- }
+ return EXIT_FAILURE;
}
buf_len += (size_t)sret;
- } while(sret != 0);
+ }while(sret != 0);
}
/* Close FIFO */
- close(fifo_fd);
+ TEMP_FAILURE_RETRY(close(fifo_fd));
/* Print password to stdout */
size_t written = 0;
while(written < buf_len){
- sret = write(STDOUT_FILENO, buf + written, buf_len - written);
+ sret = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buf + written,
+ buf_len - written));
if(sret == -1){
- int e = errno;
+ perror("write");
free(buf);
- errno = e;
- error(0, errno, "write");
- switch(e){
- case EBADF:
- case EFAULT:
- case EINVAL:
- return EX_OSFILE;
- case EFBIG:
- case EIO:
- case ENOSPC:
- default:
- return EX_IOERR;
- }
+ return EXIT_FAILURE;
}
written += (size_t)sret;
}
free(buf);
- ret = close(STDOUT_FILENO);
- if(ret == -1){
- int e = errno;
- error(0, errno, "close");
- switch(e){
- case EBADF:
- return EX_OSFILE;
- case EIO:
- default:
- return EX_IOERR;
- }
- }
return EXIT_SUCCESS;
}
=== modified file 'plugins.d/askpass-fifo.xml'
--- plugins.d/askpass-fifo.xml 2009-01-04 21:54:55 +0000
+++ plugins.d/askpass-fifo.xml 2008-10-04 20:09:53 +0000
@@ -2,7 +2,7 @@
-
+
%common;
]>
@@ -32,7 +32,6 @@
2008
- 2009
Teddy Hogeborn
Björn Påhlsson
=== modified file 'plugins.d/mandos-client.c'
--- plugins.d/mandos-client.c 2010-09-26 21:27:28 +0000
+++ plugins.d/mandos-client.c 2008-11-11 16:07:18 +0000
@@ -1,6 +1,6 @@
/* -*- coding: utf-8 -*- */
/*
- * Mandos-client - get and decrypt data from a Mandos server
+ * Mandos client - get and decrypt data from a Mandos server
*
* This program is partly derived from an example program for an Avahi
* service browser, downloaded from
@@ -9,8 +9,8 @@
* "browse_callback", and parts of "main".
*
* Everything else is
- * Copyright © 2008-2010 Teddy Hogeborn
- * Copyright © 2008-2010 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
@@ -30,64 +30,48 @@
*/
/* Needed by GPGME, specifically gpgme_data_seek() */
-#ifndef _LARGEFILE_SOURCE
#define _LARGEFILE_SOURCE
-#endif
-#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
-#endif
#define _GNU_SOURCE /* TEMP_FAILURE_RETRY(), asprintf() */
#include /* fprintf(), stderr, fwrite(),
- stdout, ferror(), remove() */
+ stdout, ferror() */
#include /* uint16_t, uint32_t */
#include /* NULL, size_t, ssize_t */
-#include /* free(), EXIT_SUCCESS, srand(),
- strtof(), abort() */
-#include /* bool, false, true */
+#include /* free(), EXIT_SUCCESS, EXIT_FAILURE,
+ srand() */
+#include /* bool, true */
#include /* memset(), strcmp(), strlen(),
strerror(), asprintf(), strcpy() */
-#include /* ioctl */
+#include /* ioctl */
#include /* socket(), inet_pton(), sockaddr,
sockaddr_in6, PF_INET6,
- SOCK_STREAM, uid_t, gid_t, open(),
- opendir(), DIR */
+ SOCK_STREAM, INET6_ADDRSTRLEN,
+ uid_t, gid_t, open(), opendir(), DIR */
#include /* open() */
#include /* socket(), struct sockaddr_in6,
- inet_pton(), connect() */
+ struct in6_addr, inet_pton(),
+ connect() */
#include /* open() */
-#include /* opendir(), struct dirent, readdir()
- */
-#include /* PRIu16, PRIdMAX, intmax_t,
- strtoimax() */
+#include /* opendir(), struct dirent, readdir() */
+#include /* PRIu16 */
#include /* assert() */
#include /* perror(), errno */
-#include /* nanosleep(), time(), sleep() */
+#include /* time() */
#include /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
SIOCSIFFLAGS, if_indextoname(),
if_nametoindex(), IF_NAMESIZE */
-#include /* IN6_IS_ADDR_LINKLOCAL,
- INET_ADDRSTRLEN, INET6_ADDRSTRLEN
- */
+#include
#include /* close(), SEEK_SET, off_t, write(),
- getuid(), getgid(), seteuid(),
- setgid(), pause() */
+ getuid(), getgid(), setuid(),
+ setgid() */
#include /* inet_pton(), htons */
-#include /* not, or, and */
+#include /* not, and */
#include /* struct argp_option, error_t, struct
argp_state, struct argp,
argp_parse(), ARGP_KEY_ARG,
ARGP_KEY_END, ARGP_ERR_UNKNOWN */
-#include /* sigemptyset(), sigaddset(),
- sigaction(), SIGTERM, sig_atomic_t,
- raise() */
-#include /* EX_OSERR, EX_USAGE, EX_UNAVAILABLE,
- EX_NOHOST, EX_IOERR, EX_PROTOCOL */
-
-#ifdef __linux__
-#include /* klogctl() */
-#endif /* __linux__ */
/* Avahi */
/* All Avahi types, constants and functions
@@ -106,8 +90,7 @@
gnutls_*
init_gnutls_session(),
GNUTLS_* */
-#include
- /* gnutls_certificate_set_openpgp_key_file(),
+#include /* gnutls_certificate_set_openpgp_key_file(),
GNUTLS_OPENPGP_FMT_BASE64 */
/* GPGME */
@@ -127,8 +110,6 @@
static const char mandos_protocol_version[] = "1";
const char *argp_program_version = "mandos-client " VERSION;
const char *argp_program_bug_address = "";
-static const char sys_class_net[] = "/sys/class/net";
-char *connect_to = NULL;
/* Used for passing in values through the Avahi callback functions */
typedef struct {
@@ -141,24 +122,16 @@
gpgme_ctx_t ctx;
} mandos_context;
-/* global context so signal handler can reach it*/
-mandos_context mc = { .simple_poll = NULL, .server = NULL,
- .dh_bits = 1024, .priority = "SECURE256"
- ":!CTYPE-X.509:+CTYPE-OPENPGP" };
-
-sig_atomic_t quit_now = 0;
-int signal_received = 0;
-
/*
- * Make additional room in "buffer" for at least BUFFER_SIZE more
- * bytes. "buffer_capacity" is how much is currently allocated,
+ * Make room in "buffer" for at least BUFFER_SIZE additional bytes.
+ * "buffer_capacity" is how much is currently allocated,
* "buffer_length" is how much is already used.
*/
-size_t incbuffer(char **buffer, size_t buffer_length,
+size_t adjustbuffer(char **buffer, size_t buffer_length,
size_t buffer_capacity){
- if(buffer_length + BUFFER_SIZE > buffer_capacity){
+ if (buffer_length + BUFFER_SIZE > buffer_capacity){
*buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
- if(buffer == NULL){
+ if (buffer == NULL){
return 0;
}
buffer_capacity += BUFFER_SIZE;
@@ -169,41 +142,41 @@
/*
* Initialize GPGME.
*/
-static bool init_gpgme(const char *seckey,
+static bool init_gpgme(mandos_context *mc, const char *seckey,
const char *pubkey, const char *tempdir){
+ int ret;
gpgme_error_t rc;
gpgme_engine_info_t engine_info;
/*
- * Helper function to insert pub and seckey to the engine keyring.
+ * Helper function to insert pub and seckey to the enigne keyring.
*/
bool import_key(const char *filename){
- int ret;
int fd;
gpgme_data_t pgp_data;
- fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
+ fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
if(fd == -1){
perror("open");
return false;
}
rc = gpgme_data_new_from_fd(&pgp_data, fd);
- if(rc != GPG_ERR_NO_ERROR){
+ if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
return false;
}
- rc = gpgme_op_import(mc.ctx, pgp_data);
- if(rc != GPG_ERR_NO_ERROR){
+ rc = gpgme_op_import(mc->ctx, pgp_data);
+ if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
return false;
}
- ret = (int)TEMP_FAILURE_RETRY(close(fd));
+ ret = TEMP_FAILURE_RETRY(close(fd));
if(ret == -1){
perror("close");
}
@@ -211,22 +184,22 @@
return true;
}
- if(debug){
- fprintf(stderr, "Initializing GPGME\n");
+ if (debug){
+ fprintf(stderr, "Initialize gpgme\n");
}
/* Init GPGME */
gpgme_check_version(NULL);
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
- if(rc != GPG_ERR_NO_ERROR){
+ if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
return false;
}
/* Set GPGME home directory for the OpenPGP engine only */
- rc = gpgme_get_engine_info(&engine_info);
- if(rc != GPG_ERR_NO_ERROR){
+ rc = gpgme_get_engine_info (&engine_info);
+ if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
return false;
@@ -245,41 +218,42 @@
}
/* Create new GPGME "context" */
- rc = gpgme_new(&(mc.ctx));
- if(rc != GPG_ERR_NO_ERROR){
+ rc = gpgme_new(&(mc->ctx));
+ if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_new: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
return false;
}
- if(not import_key(pubkey) or not import_key(seckey)){
+ if (not import_key(pubkey) or not import_key(seckey)){
return false;
}
- return true;
+ return true;
}
/*
* Decrypt OpenPGP data.
* Returns -1 on error
*/
-static ssize_t pgp_packet_decrypt(const char *cryptotext,
- size_t crypto_size,
- char **plaintext){
+static ssize_t pgp_packet_decrypt (const mandos_context *mc,
+ const char *cryptotext,
+ size_t crypto_size,
+ char **plaintext){
gpgme_data_t dh_crypto, dh_plain;
gpgme_error_t rc;
ssize_t ret;
size_t plaintext_capacity = 0;
ssize_t plaintext_length = 0;
- if(debug){
+ if (debug){
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
}
/* Create new GPGME data buffer from memory cryptotext */
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
0);
- if(rc != GPG_ERR_NO_ERROR){
+ if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
return -1;
@@ -287,7 +261,7 @@
/* Create new empty GPGME data buffer for the plaintext */
rc = gpgme_data_new(&dh_plain);
- if(rc != GPG_ERR_NO_ERROR){
+ if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
gpgme_data_release(dh_crypto);
@@ -296,15 +270,15 @@
/* Decrypt data from the cryptotext data buffer to the plaintext
data buffer */
- rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
- if(rc != GPG_ERR_NO_ERROR){
+ rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
+ if (rc != GPG_ERR_NO_ERROR){
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
gpgme_strsource(rc), gpgme_strerror(rc));
plaintext_length = -1;
- if(debug){
+ if (debug){
gpgme_decrypt_result_t result;
- result = gpgme_op_decrypt_result(mc.ctx);
- if(result == NULL){
+ result = gpgme_op_decrypt_result(mc->ctx);
+ if (result == NULL){
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
} else {
fprintf(stderr, "Unsupported algorithm: %s\n",
@@ -316,14 +290,16 @@
}
gpgme_recipient_t recipient;
recipient = result->recipients;
- while(recipient != NULL){
- fprintf(stderr, "Public key algorithm: %s\n",
- gpgme_pubkey_algo_name(recipient->pubkey_algo));
- fprintf(stderr, "Key ID: %s\n", recipient->keyid);
- fprintf(stderr, "Secret key available: %s\n",
- recipient->status == GPG_ERR_NO_SECKEY
- ? "No" : "Yes");
- recipient = recipient->next;
+ if(recipient){
+ while(recipient != NULL){
+ fprintf(stderr, "Public key algorithm: %s\n",
+ gpgme_pubkey_algo_name(recipient->pubkey_algo));
+ fprintf(stderr, "Key ID: %s\n", recipient->keyid);
+ fprintf(stderr, "Secret key available: %s\n",
+ recipient->status == GPG_ERR_NO_SECKEY
+ ? "No" : "Yes");
+ recipient = recipient->next;
+ }
}
}
}
@@ -335,7 +311,7 @@
}
/* Seek back to the beginning of the GPGME plaintext data buffer */
- if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
+ if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
perror("gpgme_data_seek");
plaintext_length = -1;
goto decrypt_end;
@@ -343,11 +319,11 @@
*plaintext = NULL;
while(true){
- plaintext_capacity = incbuffer(plaintext,
+ plaintext_capacity = adjustbuffer(plaintext,
(size_t)plaintext_length,
plaintext_capacity);
- if(plaintext_capacity == 0){
- perror("incbuffer");
+ if (plaintext_capacity == 0){
+ perror("adjustbuffer");
plaintext_length = -1;
goto decrypt_end;
}
@@ -355,7 +331,7 @@
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
BUFFER_SIZE);
/* Print the data, if any */
- if(ret == 0){
+ if (ret == 0){
/* EOF */
break;
}
@@ -385,10 +361,9 @@
return plaintext_length;
}
-static const char * safer_gnutls_strerror(int value){
- const char *ret = gnutls_strerror(value); /* Spurious warning from
- -Wunreachable-code */
- if(ret == NULL)
+static const char * safer_gnutls_strerror (int value) {
+ const char *ret = gnutls_strerror (value); /* Spurious warning */
+ if (ret == NULL)
ret = "(unknown)";
return ret;
}
@@ -399,7 +374,8 @@
fprintf(stderr, "GnuTLS: %s", string);
}
-static int init_gnutls_global(const char *pubkeyfilename,
+static int init_gnutls_global(mandos_context *mc,
+ const char *pubkeyfilename,
const char *seckeyfilename){
int ret;
@@ -408,13 +384,13 @@
}
ret = gnutls_global_init();
- if(ret != GNUTLS_E_SUCCESS){
- fprintf(stderr, "GnuTLS global_init: %s\n",
- safer_gnutls_strerror(ret));
+ if (ret != GNUTLS_E_SUCCESS) {
+ fprintf (stderr, "GnuTLS global_init: %s\n",
+ safer_gnutls_strerror(ret));
return -1;
}
- if(debug){
+ if (debug){
/* "Use a log level over 10 to enable all debugging options."
* - GnuTLS manual
*/
@@ -423,14 +399,12 @@
}
/* OpenPGP credentials */
- gnutls_certificate_allocate_credentials(&mc.cred);
- if(ret != GNUTLS_E_SUCCESS){
- fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
- from
- -Wunreachable-code
- */
- safer_gnutls_strerror(ret));
- gnutls_global_deinit();
+ gnutls_certificate_allocate_credentials(&mc->cred);
+ if (ret != GNUTLS_E_SUCCESS){
+ fprintf (stderr, "GnuTLS memory error: %s\n", /* Spurious
+ warning */
+ safer_gnutls_strerror(ret));
+ gnutls_global_deinit ();
return -1;
}
@@ -441,9 +415,9 @@
}
ret = gnutls_certificate_set_openpgp_key_file
- (mc.cred, pubkeyfilename, seckeyfilename,
+ (mc->cred, pubkeyfilename, seckeyfilename,
GNUTLS_OPENPGP_FMT_BASE64);
- if(ret != GNUTLS_E_SUCCESS){
+ if (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr,
"Error[%d] while reading the OpenPGP key pair ('%s',"
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
@@ -453,82 +427,67 @@
}
/* GnuTLS server initialization */
- ret = gnutls_dh_params_init(&mc.dh_params);
- if(ret != GNUTLS_E_SUCCESS){
- fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
- " %s\n", safer_gnutls_strerror(ret));
+ ret = gnutls_dh_params_init(&mc->dh_params);
+ if (ret != GNUTLS_E_SUCCESS) {
+ fprintf (stderr, "Error in GnuTLS DH parameter initialization:"
+ " %s\n", safer_gnutls_strerror(ret));
goto globalfail;
}
- ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
- if(ret != GNUTLS_E_SUCCESS){
- fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
- safer_gnutls_strerror(ret));
+ ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
+ if (ret != GNUTLS_E_SUCCESS) {
+ fprintf (stderr, "Error in GnuTLS prime generation: %s\n",
+ safer_gnutls_strerror(ret));
goto globalfail;
}
- gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
+ gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
return 0;
globalfail:
- gnutls_certificate_free_credentials(mc.cred);
+ gnutls_certificate_free_credentials(mc->cred);
gnutls_global_deinit();
- gnutls_dh_params_deinit(mc.dh_params);
+ gnutls_dh_params_deinit(mc->dh_params);
return -1;
}
-static int init_gnutls_session(gnutls_session_t *session){
+static int init_gnutls_session(mandos_context *mc,
+ gnutls_session_t *session){
int ret;
/* GnuTLS session creation */
- do {
- ret = gnutls_init(session, GNUTLS_SERVER);
- if(quit_now){
- return -1;
- }
- } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
- if(ret != GNUTLS_E_SUCCESS){
+ ret = gnutls_init(session, GNUTLS_SERVER);
+ if (ret != GNUTLS_E_SUCCESS){
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
safer_gnutls_strerror(ret));
}
{
const char *err;
- do {
- ret = gnutls_priority_set_direct(*session, mc.priority, &err);
- if(quit_now){
- gnutls_deinit(*session);
- return -1;
- }
- } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
- if(ret != GNUTLS_E_SUCCESS){
+ ret = gnutls_priority_set_direct(*session, mc->priority, &err);
+ if (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, "Syntax error at: %s\n", err);
fprintf(stderr, "GnuTLS error: %s\n",
safer_gnutls_strerror(ret));
- gnutls_deinit(*session);
+ gnutls_deinit (*session);
return -1;
}
}
- do {
- ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
- mc.cred);
- if(quit_now){
- gnutls_deinit(*session);
- return -1;
- }
- } while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
- if(ret != GNUTLS_E_SUCCESS){
+ ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
+ mc->cred);
+ if (ret != GNUTLS_E_SUCCESS) {
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
safer_gnutls_strerror(ret));
- gnutls_deinit(*session);
+ gnutls_deinit (*session);
return -1;
}
/* ignore client certificate if any. */
- gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
+ gnutls_certificate_server_set_request (*session,
+ GNUTLS_CERT_IGNORE);
- gnutls_dh_set_prime_bits(*session, mc.dh_bits);
+ gnutls_dh_set_prime_bits (*session, mc->dh_bits);
return 0;
}
@@ -540,137 +499,66 @@
/* Called when a Mandos server is found */
static int start_mandos_communication(const char *ip, uint16_t port,
AvahiIfIndex if_index,
- int af){
- int ret, tcp_sd = -1;
- ssize_t sret;
- union {
- struct sockaddr_in in;
- struct sockaddr_in6 in6;
- } to;
+ mandos_context *mc){
+ int ret, tcp_sd;
+ union { struct sockaddr in; struct sockaddr_in6 in6; } to;
char *buffer = NULL;
- char *decrypted_buffer = NULL;
+ char *decrypted_buffer;
size_t buffer_length = 0;
size_t buffer_capacity = 0;
+ ssize_t decrypted_buffer_size;
size_t written;
- int retval = -1;
+ int retval = 0;
+ char interface[IF_NAMESIZE];
gnutls_session_t session;
- int pf; /* Protocol family */
-
- errno = 0;
-
- if(quit_now){
- errno = EINTR;
- return -1;
- }
-
- switch(af){
- case AF_INET6:
- pf = PF_INET6;
- break;
- case AF_INET:
- pf = PF_INET;
- break;
- default:
- fprintf(stderr, "Bad address family: %d\n", af);
- errno = EINVAL;
- return -1;
- }
-
- ret = init_gnutls_session(&session);
- if(ret != 0){
+
+ ret = init_gnutls_session (mc, &session);
+ if (ret != 0){
return -1;
}
if(debug){
- fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
+ fprintf(stderr, "Setting up a tcp connection to %s, port %" PRIu16
"\n", ip, port);
}
- tcp_sd = socket(pf, SOCK_STREAM, 0);
- if(tcp_sd < 0){
- int e = errno;
+ tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
+ if(tcp_sd < 0) {
perror("socket");
- errno = e;
- goto mandos_end;
+ return -1;
}
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
+ if(debug){
+ if(if_indextoname((unsigned int)if_index, interface) == NULL){
+ perror("if_indextoname");
+ return -1;
+ }
+ fprintf(stderr, "Binding to interface %s\n", interface);
}
memset(&to, 0, sizeof(to));
- if(af == AF_INET6){
- to.in6.sin6_family = (sa_family_t)af;
- ret = inet_pton(af, ip, &to.in6.sin6_addr);
- } else { /* IPv4 */
- to.in.sin_family = (sa_family_t)af;
- ret = inet_pton(af, ip, &to.in.sin_addr);
- }
- if(ret < 0 ){
- int e = errno;
+ to.in6.sin6_family = AF_INET6;
+ /* It would be nice to have a way to detect if we were passed an
+ IPv4 address here. Now we assume an IPv6 address. */
+ ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr);
+ if (ret < 0 ){
perror("inet_pton");
- errno = e;
- goto mandos_end;
+ return -1;
}
if(ret == 0){
- int e = errno;
fprintf(stderr, "Bad address: %s\n", ip);
- errno = e;
- goto mandos_end;
- }
- if(af == AF_INET6){
- to.in6.sin6_port = htons(port); /* Spurious warnings from
- -Wconversion and
- -Wunreachable-code */
-
- if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
- (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
- -Wunreachable-code*/
- if(if_index == AVAHI_IF_UNSPEC){
- fprintf(stderr, "An IPv6 link-local address is incomplete"
- " without a network interface\n");
- errno = EINVAL;
- goto mandos_end;
- }
- /* Set the network interface number as scope */
- to.in6.sin6_scope_id = (uint32_t)if_index;
- }
- } else {
- to.in.sin_port = htons(port); /* Spurious warnings from
- -Wconversion and
- -Wunreachable-code */
- }
+ return -1;
+ }
+ to.in6.sin6_port = htons(port); /* Spurious warning */
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
- }
+ to.in6.sin6_scope_id = (uint32_t)if_index;
if(debug){
- if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
- char interface[IF_NAMESIZE];
- if(if_indextoname((unsigned int)if_index, interface) == NULL){
- perror("if_indextoname");
- } else {
- fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
- ip, interface, port);
- }
- } else {
- fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
- port);
- }
- char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
- INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
- const char *pcret;
- if(af == AF_INET6){
- pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
- sizeof(addrstr));
- } else {
- pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
- sizeof(addrstr));
- }
- if(pcret == NULL){
+ fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
+ port);
+ char addrstr[INET6_ADDRSTRLEN] = "";
+ if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
+ sizeof(addrstr)) == NULL){
perror("inet_ntop");
} else {
if(strcmp(addrstr, ip) != 0){
@@ -679,156 +567,101 @@
}
}
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
- }
-
- if(af == AF_INET6){
- ret = connect(tcp_sd, &to.in6, sizeof(to));
- } else {
- ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
- }
- if(ret < 0){
- if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
- int e = errno;
- perror("connect");
- errno = e;
- }
- goto mandos_end;
- }
-
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
+ ret = connect(tcp_sd, &to.in, sizeof(to));
+ if (ret < 0){
+ perror("connect");
+ return -1;
}
const char *out = mandos_protocol_version;
written = 0;
- while(true){
+ while (true){
size_t out_size = strlen(out);
- ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
+ ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
out_size - written));
- if(ret == -1){
- int e = errno;
+ if (ret == -1){
perror("write");
- errno = e;
+ retval = -1;
goto mandos_end;
}
written += (size_t)ret;
if(written < out_size){
continue;
} else {
- if(out == mandos_protocol_version){
+ if (out == mandos_protocol_version){
written = 0;
out = "\r\n";
} else {
break;
}
}
-
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
- }
}
if(debug){
fprintf(stderr, "Establishing TLS session with %s\n", ip);
}
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
- }
-
- gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
-
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
- }
-
- do {
- ret = gnutls_handshake(session);
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
- }
+ gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
+
+ do{
+ ret = gnutls_handshake (session);
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
- if(ret != GNUTLS_E_SUCCESS){
+ if (ret != GNUTLS_E_SUCCESS){
if(debug){
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
- gnutls_perror(ret);
+ gnutls_perror (ret);
}
- errno = EPROTO;
+ retval = -1;
goto mandos_end;
}
/* Read OpenPGP packet that contains the wanted password */
if(debug){
- fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
+ fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
ip);
}
while(true){
-
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
- }
-
- buffer_capacity = incbuffer(&buffer, buffer_length,
+ buffer_capacity = adjustbuffer(&buffer, buffer_length,
buffer_capacity);
- if(buffer_capacity == 0){
- int e = errno;
- perror("incbuffer");
- errno = e;
- goto mandos_end;
- }
-
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
- }
-
- sret = gnutls_record_recv(session, buffer+buffer_length,
- BUFFER_SIZE);
- if(sret == 0){
+ if (buffer_capacity == 0){
+ perror("adjustbuffer");
+ retval = -1;
+ goto mandos_end;
+ }
+
+ ret = gnutls_record_recv(session, buffer+buffer_length,
+ BUFFER_SIZE);
+ if (ret == 0){
break;
}
- if(sret < 0){
- switch(sret){
+ if (ret < 0){
+ switch(ret){
case GNUTLS_E_INTERRUPTED:
case GNUTLS_E_AGAIN:
break;
case GNUTLS_E_REHANDSHAKE:
- do {
- ret = gnutls_handshake(session);
-
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
- }
+ do{
+ ret = gnutls_handshake (session);
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
- if(ret < 0){
+ if (ret < 0){
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
- gnutls_perror(ret);
- errno = EPROTO;
+ gnutls_perror (ret);
+ retval = -1;
goto mandos_end;
}
break;
default:
fprintf(stderr, "Unknown error while reading data from"
" encrypted session with Mandos server\n");
- gnutls_bye(session, GNUTLS_SHUT_RDWR);
- errno = EIO;
+ retval = -1;
+ gnutls_bye (session, GNUTLS_SHUT_RDWR);
goto mandos_end;
}
} else {
- buffer_length += (size_t) sret;
+ buffer_length += (size_t) ret;
}
}
@@ -836,80 +669,51 @@
fprintf(stderr, "Closing TLS session\n");
}
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
- }
-
- do {
- ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
- }
- } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
-
- if(buffer_length > 0){
- ssize_t decrypted_buffer_size;
- decrypted_buffer_size = pgp_packet_decrypt(buffer,
+ gnutls_bye (session, GNUTLS_SHUT_RDWR);
+
+ if (buffer_length > 0){
+ decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
buffer_length,
&decrypted_buffer);
- if(decrypted_buffer_size >= 0){
-
+ if (decrypted_buffer_size >= 0){
written = 0;
while(written < (size_t) decrypted_buffer_size){
- if(quit_now){
- errno = EINTR;
- goto mandos_end;
- }
-
- ret = (int)fwrite(decrypted_buffer + written, 1,
- (size_t)decrypted_buffer_size - written,
- stdout);
+ ret = (int)fwrite (decrypted_buffer + written, 1,
+ (size_t)decrypted_buffer_size - written,
+ stdout);
if(ret == 0 and ferror(stdout)){
- int e = errno;
if(debug){
fprintf(stderr, "Error writing encrypted data: %s\n",
strerror(errno));
}
- errno = e;
- goto mandos_end;
+ retval = -1;
+ break;
}
written += (size_t)ret;
}
- retval = 0;
+ free(decrypted_buffer);
+ } else {
+ retval = -1;
}
+ } else {
+ retval = -1;
}
/* Shutdown procedure */
mandos_end:
- {
- int e = errno;
- free(decrypted_buffer);
- free(buffer);
- if(tcp_sd >= 0){
- ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
- }
- if(ret == -1){
- if(e == 0){
- e = errno;
- }
- perror("close");
- }
- gnutls_deinit(session);
- if(quit_now){
- e = EINTR;
- retval = -1;
- }
- errno = e;
+ free(buffer);
+ ret = TEMP_FAILURE_RETRY(close(tcp_sd));
+ if(ret == -1){
+ perror("close");
}
+ gnutls_deinit (session);
return retval;
}
static void resolve_callback(AvahiSServiceResolver *r,
AvahiIfIndex interface,
- AvahiProtocol proto,
+ AVAHI_GCC_UNUSED AvahiProtocol protocol,
AvahiResolverEvent event,
const char *name,
const char *type,
@@ -920,22 +724,19 @@
AVAHI_GCC_UNUSED AvahiStringList *txt,
AVAHI_GCC_UNUSED AvahiLookupResultFlags
flags,
- AVAHI_GCC_UNUSED void* userdata){
+ void* userdata) {
+ mandos_context *mc = userdata;
assert(r);
/* Called whenever a service has been resolved successfully or
timed out */
- if(quit_now){
- return;
- }
-
- switch(event){
+ switch (event) {
default:
case AVAHI_RESOLVER_FAILURE:
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
" of type '%s' in domain '%s': %s\n", name, type, domain,
- avahi_strerror(avahi_server_errno(mc.server)));
+ avahi_strerror(avahi_server_errno(mc->server)));
break;
case AVAHI_RESOLVER_FOUND:
@@ -944,45 +745,41 @@
avahi_address_snprint(ip, sizeof(ip), address);
if(debug){
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
- PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
- ip, (intmax_t)interface, port);
+ PRIu16 ") on port %d\n", name, host_name, ip,
+ interface, port);
}
- int ret = start_mandos_communication(ip, port, interface,
- avahi_proto_to_af(proto));
- if(ret == 0){
- avahi_simple_poll_quit(mc.simple_poll);
+ int ret = start_mandos_communication(ip, port, interface, mc);
+ if (ret == 0){
+ avahi_simple_poll_quit(mc->simple_poll);
}
}
}
avahi_s_service_resolver_free(r);
}
-static void browse_callback(AvahiSServiceBrowser *b,
- AvahiIfIndex interface,
- AvahiProtocol protocol,
- AvahiBrowserEvent event,
- const char *name,
- const char *type,
- const char *domain,
- AVAHI_GCC_UNUSED AvahiLookupResultFlags
- flags,
- AVAHI_GCC_UNUSED void* userdata){
+static void browse_callback( AvahiSServiceBrowser *b,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ AvahiBrowserEvent event,
+ const char *name,
+ const char *type,
+ const char *domain,
+ AVAHI_GCC_UNUSED AvahiLookupResultFlags
+ flags,
+ void* userdata) {
+ mandos_context *mc = userdata;
assert(b);
/* Called whenever a new services becomes available on the LAN or
is removed from the LAN */
- if(quit_now){
- return;
- }
-
- switch(event){
+ switch (event) {
default:
case AVAHI_BROWSER_FAILURE:
fprintf(stderr, "(Avahi browser) %s\n",
- avahi_strerror(avahi_server_errno(mc.server)));
- avahi_simple_poll_quit(mc.simple_poll);
+ avahi_strerror(avahi_server_errno(mc->server)));
+ avahi_simple_poll_quit(mc->simple_poll);
return;
case AVAHI_BROWSER_NEW:
@@ -991,11 +788,12 @@
the callback function is called the Avahi server will free the
resolver for us. */
- if(avahi_s_service_resolver_new(mc.server, interface, protocol,
- name, type, domain, protocol, 0,
- resolve_callback, NULL) == NULL)
+ if (!(avahi_s_service_resolver_new(mc->server, interface,
+ protocol, name, type, domain,
+ AVAHI_PROTO_INET6, 0,
+ resolve_callback, mc)))
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
- name, avahi_strerror(avahi_server_errno(mc.server)));
+ name, avahi_strerror(avahi_server_errno(mc->server)));
break;
case AVAHI_BROWSER_REMOVE:
@@ -1010,809 +808,337 @@
}
}
-/* stop main loop after sigterm has been called */
-static void handle_sigterm(int sig){
- if(quit_now){
- return;
- }
- quit_now = 1;
- signal_received = sig;
- int old_errno = errno;
- if(mc.simple_poll != NULL){
- avahi_simple_poll_quit(mc.simple_poll);
- }
- errno = old_errno;
-}
-
-/*
- * This function determines if a directory entry in /sys/class/net
- * corresponds to an acceptable network device.
- * (This function is passed to scandir(3) as a filter function.)
- */
-int good_interface(const struct dirent *if_entry){
- ssize_t ssret;
- char *flagname = NULL;
- int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
- if_entry->d_name);
- if(ret < 0){
- perror("asprintf");
- return 0;
- }
- if(if_entry->d_name[0] == '.'){
- return 0;
- }
- int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
- if(flags_fd == -1){
- perror("open");
- return 0;
- }
- typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
- /* read line from flags_fd */
- ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
- char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
- flagstring[(size_t)to_read] = '\0';
- if(flagstring == NULL){
- perror("malloc");
- close(flags_fd);
- return 0;
- }
- while(to_read > 0){
- ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
- (size_t)to_read));
- if(ssret == -1){
- perror("read");
- free(flagstring);
- close(flags_fd);
- return 0;
- }
- to_read -= ssret;
- if(ssret == 0){
- break;
- }
- }
- close(flags_fd);
- intmax_t tmpmax;
- char *tmp;
- errno = 0;
- tmpmax = strtoimax(flagstring, &tmp, 0);
- if(errno != 0 or tmp == flagstring or (*tmp != '\0'
- and not (isspace(*tmp)))
- or tmpmax != (ifreq_flags)tmpmax){
- if(debug){
- fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
- flagstring, if_entry->d_name);
- }
- free(flagstring);
- return 0;
- }
- free(flagstring);
- ifreq_flags flags = (ifreq_flags)tmpmax;
- /* Reject the loopback device */
- if(flags & IFF_LOOPBACK){
- if(debug){
- fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
- if_entry->d_name);
- }
- return 0;
- }
- /* Accept point-to-point devices only if connect_to is specified */
- if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
- if(debug){
- fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
- if_entry->d_name);
- }
- return 1;
- }
- /* Otherwise, reject non-broadcast-capable devices */
- if(not (flags & IFF_BROADCAST)){
- if(debug){
- fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
- if_entry->d_name);
- }
- return 0;
- }
- /* Accept this device */
- if(debug){
- fprintf(stderr, "Interface \"%s\" is acceptable\n",
- if_entry->d_name);
- }
- return 1;
-}
-
int main(int argc, char *argv[]){
- AvahiSServiceBrowser *sb = NULL;
- int error;
- int ret;
- intmax_t tmpmax;
- char *tmp;
- int exitcode = EXIT_SUCCESS;
- const char *interface = "";
- struct ifreq network;
- int sd = -1;
- bool take_down_interface = false;
- uid_t uid;
- gid_t gid;
- char tempdir[] = "/tmp/mandosXXXXXX";
- bool tempdir_created = false;
- AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
- const char *seckey = PATHDIR "/" SECKEY;
- const char *pubkey = PATHDIR "/" PUBKEY;
-
- bool gnutls_initialized = false;
- bool gpgme_initialized = false;
- float delay = 2.5f;
-
- struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
- struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
-
- uid = getuid();
- gid = getgid();
-
- /* Lower any group privileges we might have, just to be safe */
- errno = 0;
- ret = setgid(gid);
- if(ret == -1){
- perror("setgid");
- }
-
- /* Lower user privileges (temporarily) */
- errno = 0;
- ret = seteuid(uid);
- if(ret == -1){
- perror("seteuid");
- }
-
- if(quit_now){
- goto end;
- }
-
- {
- struct argp_option options[] = {
- { .name = "debug", .key = 128,
- .doc = "Debug mode", .group = 3 },
- { .name = "connect", .key = 'c',
- .arg = "ADDRESS:PORT",
- .doc = "Connect directly to a specific Mandos server",
- .group = 1 },
- { .name = "interface", .key = 'i',
- .arg = "NAME",
- .doc = "Network interface that will be used to search for"
- " Mandos servers",
- .group = 1 },
- { .name = "seckey", .key = 's',
- .arg = "FILE",
- .doc = "OpenPGP secret key file base name",
- .group = 1 },
- { .name = "pubkey", .key = 'p',
- .arg = "FILE",
- .doc = "OpenPGP public key file base name",
- .group = 2 },
- { .name = "dh-bits", .key = 129,
- .arg = "BITS",
- .doc = "Bit length of the prime number used in the"
- " Diffie-Hellman key exchange",
- .group = 2 },
- { .name = "priority", .key = 130,
- .arg = "STRING",
- .doc = "GnuTLS priority string for the TLS handshake",
- .group = 1 },
- { .name = "delay", .key = 131,
- .arg = "SECONDS",
- .doc = "Maximum delay to wait for interface startup",
- .group = 2 },
- /*
- * These reproduce what we would get without ARGP_NO_HELP
- */
- { .name = "help", .key = '?',
- .doc = "Give this help list", .group = -1 },
- { .name = "usage", .key = -3,
- .doc = "Give a short usage message", .group = -1 },
- { .name = "version", .key = 'V',
- .doc = "Print program version", .group = -1 },
- { .name = NULL }
- };
-
- error_t parse_opt(int key, char *arg,
- struct argp_state *state){
- errno = 0;
- switch(key){
- case 128: /* --debug */
- debug = true;
- break;
- case 'c': /* --connect */
- connect_to = arg;
- break;
- case 'i': /* --interface */
- interface = arg;
- break;
- case 's': /* --seckey */
- seckey = arg;
- break;
- case 'p': /* --pubkey */
- pubkey = arg;
- break;
- case 129: /* --dh-bits */
- errno = 0;
- tmpmax = strtoimax(arg, &tmp, 10);
- if(errno != 0 or tmp == arg or *tmp != '\0'
- or tmpmax != (typeof(mc.dh_bits))tmpmax){
- argp_error(state, "Bad number of DH bits");
- }
- mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
- break;
- case 130: /* --priority */
- mc.priority = arg;
- break;
- case 131: /* --delay */
- errno = 0;
- delay = strtof(arg, &tmp);
- if(errno != 0 or tmp == arg or *tmp != '\0'){
- argp_error(state, "Bad delay");
- }
- break;
- /*
- * These reproduce what we would get without ARGP_NO_HELP
- */
- case '?': /* --help */
- argp_state_help(state, state->out_stream,
- (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
- & ~(unsigned int)ARGP_HELP_EXIT_OK);
- case -3: /* --usage */
- argp_state_help(state, state->out_stream,
- ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
- case 'V': /* --version */
- fprintf(state->out_stream, "%s\n", argp_program_version);
- exit(argp_err_exit_status);
- break;
- default:
- return ARGP_ERR_UNKNOWN;
- }
- return errno;
- }
-
- struct argp argp = { .options = options, .parser = parse_opt,
- .args_doc = "",
- .doc = "Mandos client -- Get and decrypt"
- " passwords from a Mandos server" };
- ret = argp_parse(&argp, argc, argv,
- ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
- switch(ret){
- case 0:
- break;
- case ENOMEM:
- default:
- errno = ret;
- perror("argp_parse");
- exitcode = EX_OSERR;
- goto end;
- case EINVAL:
- exitcode = EX_USAGE;
- goto end;
- }
- }
-
- if(not debug){
- avahi_set_log_function(empty_log);
- }
-
- if(interface[0] == '\0'){
- struct dirent **direntries;
- ret = scandir(sys_class_net, &direntries, good_interface,
- alphasort);
- if(ret >= 1){
- /* Pick the first good interface */
- interface = strdup(direntries[0]->d_name);
- if(debug){
- fprintf(stderr, "Using interface \"%s\"\n", interface);
- }
- if(interface == NULL){
- perror("malloc");
- free(direntries);
- exitcode = EXIT_FAILURE;
- goto end;
- }
- free(direntries);
- } else {
- free(direntries);
- fprintf(stderr, "Could not find a network interface\n");
- exitcode = EXIT_FAILURE;
- goto end;
- }
- }
-
- /* Initialize Avahi early so avahi_simple_poll_quit() can be called
- from the signal handler */
- /* Initialize the pseudo-RNG for Avahi */
- srand((unsigned int) time(NULL));
- mc.simple_poll = avahi_simple_poll_new();
- if(mc.simple_poll == NULL){
- fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
- exitcode = EX_UNAVAILABLE;
- goto end;
- }
-
- sigemptyset(&sigterm_action.sa_mask);
- ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
- if(ret == -1){
- perror("sigaddset");
- exitcode = EX_OSERR;
- goto end;
- }
- ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
- if(ret == -1){
- perror("sigaddset");
- exitcode = EX_OSERR;
- goto end;
- }
- ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
- if(ret == -1){
- perror("sigaddset");
- exitcode = EX_OSERR;
- goto end;
- }
- /* Need to check if the handler is SIG_IGN before handling:
- | [[info:libc:Initial Signal Actions]] |
- | [[info:libc:Basic Signal Handling]] |
- */
- ret = sigaction(SIGINT, NULL, &old_sigterm_action);
- if(ret == -1){
- perror("sigaction");
- return EX_OSERR;
- }
- if(old_sigterm_action.sa_handler != SIG_IGN){
- ret = sigaction(SIGINT, &sigterm_action, NULL);
- if(ret == -1){
- perror("sigaction");
- exitcode = EX_OSERR;
- goto end;
- }
- }
- ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
- if(ret == -1){
- perror("sigaction");
- return EX_OSERR;
- }
- if(old_sigterm_action.sa_handler != SIG_IGN){
- ret = sigaction(SIGHUP, &sigterm_action, NULL);
- if(ret == -1){
- perror("sigaction");
- exitcode = EX_OSERR;
- goto end;
- }
- }
- ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
- if(ret == -1){
- perror("sigaction");
- return EX_OSERR;
- }
- if(old_sigterm_action.sa_handler != SIG_IGN){
- ret = sigaction(SIGTERM, &sigterm_action, NULL);
- if(ret == -1){
- perror("sigaction");
- exitcode = EX_OSERR;
- goto end;
- }
- }
-
- /* If the interface is down, bring it up */
- if(strcmp(interface, "none") != 0){
+ AvahiSServiceBrowser *sb = NULL;
+ int error;
+ int ret;
+ int exitcode = EXIT_SUCCESS;
+ const char *interface = "eth0";
+ struct ifreq network;
+ int sd;
+ uid_t uid;
+ gid_t gid;
+ char *connect_to = NULL;
+ char tempdir[] = "/tmp/mandosXXXXXX";
+ AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
+ const char *seckey = PATHDIR "/" SECKEY;
+ const char *pubkey = PATHDIR "/" PUBKEY;
+
+ mandos_context mc = { .simple_poll = NULL, .server = NULL,
+ .dh_bits = 1024, .priority = "SECURE256"
+ ":!CTYPE-X.509:+CTYPE-OPENPGP" };
+ bool gnutls_initalized = false;
+ bool gpgme_initalized = false;
+
+ {
+ struct argp_option options[] = {
+ { .name = "debug", .key = 128,
+ .doc = "Debug mode", .group = 3 },
+ { .name = "connect", .key = 'c',
+ .arg = "ADDRESS:PORT",
+ .doc = "Connect directly to a specific Mandos server",
+ .group = 1 },
+ { .name = "interface", .key = 'i',
+ .arg = "NAME",
+ .doc = "Interface that will be used to search for Mandos"
+ " servers",
+ .group = 1 },
+ { .name = "seckey", .key = 's',
+ .arg = "FILE",
+ .doc = "OpenPGP secret key file base name",
+ .group = 1 },
+ { .name = "pubkey", .key = 'p',
+ .arg = "FILE",
+ .doc = "OpenPGP public key file base name",
+ .group = 2 },
+ { .name = "dh-bits", .key = 129,
+ .arg = "BITS",
+ .doc = "Bit length of the prime number used in the"
+ " Diffie-Hellman key exchange",
+ .group = 2 },
+ { .name = "priority", .key = 130,
+ .arg = "STRING",
+ .doc = "GnuTLS priority string for the TLS handshake",
+ .group = 1 },
+ { .name = NULL }
+ };
+
+ error_t parse_opt (int key, char *arg,
+ struct argp_state *state) {
+ /* Get the INPUT argument from `argp_parse', which we know is
+ a pointer to our plugin list pointer. */
+ switch (key) {
+ case 128: /* --debug */
+ debug = true;
+ break;
+ case 'c': /* --connect */
+ connect_to = arg;
+ break;
+ case 'i': /* --interface */
+ interface = arg;
+ break;
+ case 's': /* --seckey */
+ seckey = arg;
+ break;
+ case 'p': /* --pubkey */
+ pubkey = arg;
+ break;
+ case 129: /* --dh-bits */
+ errno = 0;
+ mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
+ if (errno){
+ perror("strtol");
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case 130: /* --priority */
+ mc.priority = arg;
+ break;
+ case ARGP_KEY_ARG:
+ argp_usage (state);
+ case ARGP_KEY_END:
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+ }
+
+ struct argp argp = { .options = options, .parser = parse_opt,
+ .args_doc = "",
+ .doc = "Mandos client -- Get and decrypt"
+ " passwords from a Mandos server" };
+ ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
+ if (ret == ARGP_ERR_UNKNOWN){
+ fprintf(stderr, "Unknown error while parsing arguments\n");
+ exitcode = EXIT_FAILURE;
+ goto end;
+ }
+ }
+
+ /* If the interface is down, bring it up */
+ {
+ sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
+ if(sd < 0) {
+ perror("socket");
+ exitcode = EXIT_FAILURE;
+ goto end;
+ }
+ strcpy(network.ifr_name, interface);
+ ret = ioctl(sd, SIOCGIFFLAGS, &network);
+ if(ret == -1){
+ perror("ioctl SIOCGIFFLAGS");
+ exitcode = EXIT_FAILURE;
+ goto end;
+ }
+ if((network.ifr_flags & IFF_UP) == 0){
+ network.ifr_flags |= IFF_UP;
+ ret = ioctl(sd, SIOCSIFFLAGS, &network);
+ if(ret == -1){
+ perror("ioctl SIOCSIFFLAGS");
+ exitcode = EXIT_FAILURE;
+ goto end;
+ }
+ }
+ ret = TEMP_FAILURE_RETRY(close(sd));
+ if(ret == -1){
+ perror("close");
+ }
+ }
+
+ uid = getuid();
+ gid = getgid();
+
+ ret = setuid(uid);
+ if (ret == -1){
+ perror("setuid");
+ }
+
+ setgid(gid);
+ if (ret == -1){
+ perror("setgid");
+ }
+
+ ret = init_gnutls_global(&mc, pubkey, seckey);
+ if (ret == -1){
+ fprintf(stderr, "init_gnutls_global failed\n");
+ exitcode = EXIT_FAILURE;
+ goto end;
+ } else {
+ gnutls_initalized = true;
+ }
+
+ if(mkdtemp(tempdir) == NULL){
+ perror("mkdtemp");
+ tempdir[0] = '\0';
+ goto end;
+ }
+
+ if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
+ fprintf(stderr, "gpgme_initalized failed\n");
+ exitcode = EXIT_FAILURE;
+ goto end;
+ } else {
+ gpgme_initalized = true;
+ }
+
if_index = (AvahiIfIndex) if_nametoindex(interface);
if(if_index == 0){
fprintf(stderr, "No such interface: \"%s\"\n", interface);
- exitcode = EX_UNAVAILABLE;
- goto end;
- }
-
- if(quit_now){
- goto end;
- }
-
- /* Re-raise priviliges */
- errno = 0;
- ret = seteuid(0);
- if(ret == -1){
- perror("seteuid");
- }
-
-#ifdef __linux__
- /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
- messages about the network interface to mess up the prompt */
- ret = klogctl(8, NULL, 5);
- bool restore_loglevel = true;
- if(ret == -1){
- restore_loglevel = false;
- perror("klogctl");
- }
-#endif /* __linux__ */
-
- sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
- if(sd < 0){
- perror("socket");
- exitcode = EX_OSERR;
-#ifdef __linux__
- if(restore_loglevel){
- ret = klogctl(7, NULL, 0);
- if(ret == -1){
- perror("klogctl");
- }
- }
-#endif /* __linux__ */
- /* Lower privileges */
- errno = 0;
- ret = seteuid(uid);
- if(ret == -1){
- perror("seteuid");
- }
- goto end;
- }
- strcpy(network.ifr_name, interface);
- ret = ioctl(sd, SIOCGIFFLAGS, &network);
- if(ret == -1){
- perror("ioctl SIOCGIFFLAGS");
-#ifdef __linux__
- if(restore_loglevel){
- ret = klogctl(7, NULL, 0);
- if(ret == -1){
- perror("klogctl");
- }
- }
-#endif /* __linux__ */
- exitcode = EX_OSERR;
- /* Lower privileges */
- errno = 0;
- ret = seteuid(uid);
- if(ret == -1){
- perror("seteuid");
- }
- goto end;
- }
- if((network.ifr_flags & IFF_UP) == 0){
- network.ifr_flags |= IFF_UP;
- take_down_interface = true;
- ret = ioctl(sd, SIOCSIFFLAGS, &network);
- if(ret == -1){
- take_down_interface = false;
- perror("ioctl SIOCSIFFLAGS +IFF_UP");
- exitcode = EX_OSERR;
-#ifdef __linux__
- if(restore_loglevel){
- ret = klogctl(7, NULL, 0);
- if(ret == -1){
- perror("klogctl");
- }
- }
-#endif /* __linux__ */
- /* Lower privileges */
- errno = 0;
- ret = seteuid(uid);
- if(ret == -1){
- perror("seteuid");
- }
- goto end;
- }
- }
- /* sleep checking until interface is running */
- for(int i=0; i < delay * 4; i++){
- ret = ioctl(sd, SIOCGIFFLAGS, &network);
- if(ret == -1){
- perror("ioctl SIOCGIFFLAGS");
- } else if(network.ifr_flags & IFF_RUNNING){
- break;
- }
- struct timespec sleeptime = { .tv_nsec = 250000000 };
- ret = nanosleep(&sleeptime, NULL);
- if(ret == -1 and errno != EINTR){
- perror("nanosleep");
- }
- }
- if(not take_down_interface){
- /* We won't need the socket anymore */
- ret = (int)TEMP_FAILURE_RETRY(close(sd));
- if(ret == -1){
- perror("close");
- }
- }
-#ifdef __linux__
- if(restore_loglevel){
- /* Restores kernel loglevel to default */
- ret = klogctl(7, NULL, 0);
- if(ret == -1){
- perror("klogctl");
- }
- }
-#endif /* __linux__ */
- /* Lower privileges */
- errno = 0;
- if(take_down_interface){
- /* Lower privileges */
- ret = seteuid(uid);
- if(ret == -1){
- perror("seteuid");
- }
- } else {
- /* Lower privileges permanently */
- ret = setuid(uid);
- if(ret == -1){
- perror("setuid");
- }
- }
- }
-
- if(quit_now){
- goto end;
- }
-
- ret = init_gnutls_global(pubkey, seckey);
- if(ret == -1){
- fprintf(stderr, "init_gnutls_global failed\n");
- exitcode = EX_UNAVAILABLE;
- goto end;
- } else {
- gnutls_initialized = true;
- }
-
- if(quit_now){
- goto end;
- }
-
- tempdir_created = true;
- if(mkdtemp(tempdir) == NULL){
- tempdir_created = false;
- perror("mkdtemp");
- goto end;
- }
-
- if(quit_now){
- goto end;
- }
-
- if(not init_gpgme(pubkey, seckey, tempdir)){
- fprintf(stderr, "init_gpgme failed\n");
- exitcode = EX_UNAVAILABLE;
- goto end;
- } else {
- gpgme_initialized = true;
- }
-
- if(quit_now){
- goto end;
- }
-
- if(connect_to != NULL){
- /* Connect directly, do not use Zeroconf */
- /* (Mainly meant for debugging) */
- char *address = strrchr(connect_to, ':');
- if(address == NULL){
- fprintf(stderr, "No colon in address\n");
- exitcode = EX_USAGE;
- goto end;
- }
-
- if(quit_now){
- goto end;
- }
-
- uint16_t port;
- errno = 0;
- tmpmax = strtoimax(address+1, &tmp, 10);
- if(errno != 0 or tmp == address+1 or *tmp != '\0'
- or tmpmax != (uint16_t)tmpmax){
- fprintf(stderr, "Bad port number\n");
- exitcode = EX_USAGE;
- goto end;
- }
-
- if(quit_now){
- goto end;
- }
-
- port = (uint16_t)tmpmax;
- *address = '\0';
- address = connect_to;
- /* Colon in address indicates IPv6 */
- int af;
- if(strchr(address, ':') != NULL){
- af = AF_INET6;
- } else {
- af = AF_INET;
- }
-
- 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(15);
- };
-
- if (not quit_now){
- exitcode = EXIT_SUCCESS;
- }
-
- goto end;
- }
-
- if(quit_now){
- goto end;
- }
-
- {
- AvahiServerConfig config;
- /* Do not publish any local Zeroconf records */
- avahi_server_config_init(&config);
- config.publish_hinfo = 0;
- config.publish_addresses = 0;
- config.publish_workstation = 0;
- config.publish_domain = 0;
-
- /* Allocate a new server */
- mc.server = avahi_server_new(avahi_simple_poll_get
- (mc.simple_poll), &config, NULL,
- NULL, &error);
-
- /* Free the Avahi configuration data */
- avahi_server_config_free(&config);
- }
-
- /* Check if creating the Avahi server object succeeded */
- if(mc.server == NULL){
- fprintf(stderr, "Failed to create Avahi server: %s\n",
- avahi_strerror(error));
- exitcode = EX_UNAVAILABLE;
- goto end;
- }
-
- if(quit_now){
- goto end;
- }
-
- /* Create the Avahi service browser */
- sb = avahi_s_service_browser_new(mc.server, if_index,
- AVAHI_PROTO_UNSPEC, "_mandos._tcp",
- NULL, 0, browse_callback, NULL);
- if(sb == NULL){
- fprintf(stderr, "Failed to create service browser: %s\n",
- avahi_strerror(avahi_server_errno(mc.server)));
- exitcode = EX_UNAVAILABLE;
- goto end;
- }
-
- if(quit_now){
- goto end;
- }
-
- /* Run the main loop */
-
- if(debug){
- fprintf(stderr, "Starting Avahi loop search\n");
- }
-
- avahi_simple_poll_loop(mc.simple_poll);
-
+ exit(EXIT_FAILURE);
+ }
+
+ if(connect_to != NULL){
+ /* Connect directly, do not use Zeroconf */
+ /* (Mainly meant for debugging) */
+ char *address = strrchr(connect_to, ':');
+ if(address == NULL){
+ fprintf(stderr, "No colon in address\n");
+ exitcode = EXIT_FAILURE;
+ goto end;
+ }
+ errno = 0;
+ uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
+ if(errno){
+ perror("Bad port number");
+ exitcode = EXIT_FAILURE;
+ goto end;
+ }
+ *address = '\0';
+ address = connect_to;
+ ret = start_mandos_communication(address, port, if_index, &mc);
+ if(ret < 0){
+ exitcode = EXIT_FAILURE;
+ } else {
+ exitcode = EXIT_SUCCESS;
+ }
+ goto end;
+ }
+
+ if (not debug){
+ avahi_set_log_function(empty_log);
+ }
+
+ /* Initialize the pseudo-RNG for Avahi */
+ srand((unsigned int) time(NULL));
+
+ /* Allocate main Avahi loop object */
+ mc.simple_poll = avahi_simple_poll_new();
+ if (mc.simple_poll == NULL) {
+ fprintf(stderr, "Avahi: Failed to create simple poll"
+ " object.\n");
+ exitcode = EXIT_FAILURE;
+ goto end;
+ }
+
+ {
+ AvahiServerConfig config;
+ /* Do not publish any local Zeroconf records */
+ avahi_server_config_init(&config);
+ config.publish_hinfo = 0;
+ config.publish_addresses = 0;
+ config.publish_workstation = 0;
+ config.publish_domain = 0;
+
+ /* Allocate a new server */
+ mc.server = avahi_server_new(avahi_simple_poll_get
+ (mc.simple_poll), &config, NULL,
+ NULL, &error);
+
+ /* Free the Avahi configuration data */
+ avahi_server_config_free(&config);
+ }
+
+ /* Check if creating the Avahi server object succeeded */
+ if (mc.server == NULL) {
+ fprintf(stderr, "Failed to create Avahi server: %s\n",
+ avahi_strerror(error));
+ exitcode = EXIT_FAILURE;
+ goto end;
+ }
+
+ /* Create the Avahi service browser */
+ sb = avahi_s_service_browser_new(mc.server, if_index,
+ AVAHI_PROTO_INET6,
+ "_mandos._tcp", NULL, 0,
+ browse_callback, &mc);
+ if (sb == NULL) {
+ fprintf(stderr, "Failed to create service browser: %s\n",
+ avahi_strerror(avahi_server_errno(mc.server)));
+ exitcode = EXIT_FAILURE;
+ goto end;
+ }
+
+ /* Run the main loop */
+
+ if (debug){
+ fprintf(stderr, "Starting Avahi loop search\n");
+ }
+
+ avahi_simple_poll_loop(mc.simple_poll);
+
end:
-
- if(debug){
- fprintf(stderr, "%s exiting\n", argv[0]);
- }
-
- /* Cleanup things */
- if(sb != NULL)
- avahi_s_service_browser_free(sb);
-
- if(mc.server != NULL)
- avahi_server_free(mc.server);
-
- if(mc.simple_poll != NULL)
- avahi_simple_poll_free(mc.simple_poll);
-
- if(gnutls_initialized){
- gnutls_certificate_free_credentials(mc.cred);
- gnutls_global_deinit();
- gnutls_dh_params_deinit(mc.dh_params);
- }
-
- if(gpgme_initialized){
- gpgme_release(mc.ctx);
- }
-
- /* Take down the network interface */
- if(take_down_interface){
- /* Re-raise priviliges */
- errno = 0;
- ret = seteuid(0);
- if(ret == -1){
- perror("seteuid");
- }
- if(geteuid() == 0){
- ret = ioctl(sd, SIOCGIFFLAGS, &network);
- if(ret == -1){
- perror("ioctl SIOCGIFFLAGS");
- } else if(network.ifr_flags & IFF_UP) {
- network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
- ret = ioctl(sd, SIOCSIFFLAGS, &network);
- if(ret == -1){
- perror("ioctl SIOCSIFFLAGS -IFF_UP");
- }
- }
- ret = (int)TEMP_FAILURE_RETRY(close(sd));
- if(ret == -1){
- perror("close");
- }
- /* Lower privileges permanently */
- errno = 0;
- ret = setuid(uid);
- if(ret == -1){
- perror("setuid");
- }
- }
- }
-
- /* Removes the temp directory used by GPGME */
- if(tempdir_created){
- DIR *d;
- struct dirent *direntry;
- d = opendir(tempdir);
- if(d == NULL){
- if(errno != ENOENT){
+
+ if (debug){
+ fprintf(stderr, "%s exiting\n", argv[0]);
+ }
+
+ /* Cleanup things */
+ if (sb != NULL)
+ avahi_s_service_browser_free(sb);
+
+ if (mc.server != NULL)
+ avahi_server_free(mc.server);
+
+ if (mc.simple_poll != NULL)
+ avahi_simple_poll_free(mc.simple_poll);
+
+ if (gnutls_initalized){
+ gnutls_certificate_free_credentials(mc.cred);
+ gnutls_global_deinit ();
+ gnutls_dh_params_deinit(mc.dh_params);
+ }
+
+ if(gpgme_initalized){
+ gpgme_release(mc.ctx);
+ }
+
+ /* Removes the temp directory used by GPGME */
+ if(tempdir[0] != '\0'){
+ DIR *d;
+ struct dirent *direntry;
+ d = opendir(tempdir);
+ if(d == NULL){
perror("opendir");
- }
- } else {
- while(true){
- direntry = readdir(d);
- if(direntry == NULL){
- break;
- }
- /* Skip "." and ".." */
- if(direntry->d_name[0] == '.'
- and (direntry->d_name[1] == '\0'
- or (direntry->d_name[1] == '.'
- and direntry->d_name[2] == '\0'))){
- continue;
- }
- char *fullname = NULL;
- ret = asprintf(&fullname, "%s/%s", tempdir,
- direntry->d_name);
- if(ret < 0){
- perror("asprintf");
- continue;
- }
- ret = remove(fullname);
- if(ret == -1){
- fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
- strerror(errno));
- }
- free(fullname);
- }
- closedir(d);
- }
- ret = rmdir(tempdir);
- if(ret == -1 and errno != ENOENT){
- perror("rmdir");
- }
- }
-
- if(quit_now){
- sigemptyset(&old_sigterm_action.sa_mask);
- old_sigterm_action.sa_handler = SIG_DFL;
- ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
- &old_sigterm_action,
- NULL));
- if(ret == -1){
- perror("sigaction");
- }
- do {
- ret = raise(signal_received);
- } while(ret != 0 and errno == EINTR);
- if(ret != 0){
- perror("raise");
- abort();
- }
- TEMP_FAILURE_RETRY(pause());
- }
-
- return exitcode;
+ } else {
+ while(true){
+ direntry = readdir(d);
+ if(direntry == NULL){
+ break;
+ }
+ if (direntry->d_type == DT_REG){
+ char *fullname = NULL;
+ ret = asprintf(&fullname, "%s/%s", tempdir,
+ direntry->d_name);
+ if(ret < 0){
+ perror("asprintf");
+ continue;
+ }
+ ret = unlink(fullname);
+ if(ret == -1){
+ fprintf(stderr, "unlink(\"%s\"): %s",
+ fullname, strerror(errno));
+ }
+ free(fullname);
+ }
+ }
+ closedir(d);
+ }
+ ret = rmdir(tempdir);
+ if(ret == -1){
+ perror("rmdir");
+ }
+ }
+
+ return exitcode;
}
=== modified file 'plugins.d/mandos-client.xml'
--- plugins.d/mandos-client.xml 2010-09-26 18:32:58 +0000
+++ plugins.d/mandos-client.xml 2008-10-04 01:55:56 +0000
@@ -2,7 +2,7 @@
-
+
%common;
]>
@@ -32,7 +32,6 @@
2008
- 2009
Teddy Hogeborn
Björn Påhlsson
@@ -93,10 +92,6 @@
-
-
-
-
@@ -126,16 +121,11 @@
&COMMANDNAME; is a client program that
communicates with mandos8
- to get a password. In slightly more detail, this client program
- brings up a network interface, uses the interface’s IPv6
- link-local address to get network connectivity, uses Zeroconf to
- find servers on the local network, and communicates with servers
- 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.
+ to get a password. It uses IPv6 link-local addresses to get
+ network connectivity, Zeroconf to find servers, and TLS with an
+ OpenPGP key to ensure authenticity and confidentiality. It
+ keeps running, trying all servers on the network, until it
+ receives a satisfactory reply or a TERM signal is received.
This program is not meant to be run directly; it is really meant
@@ -195,38 +185,21 @@
-
+
Network interface that will be brought up and scanned for
- Mandos servers to connect to. The default is the empty
- string, which will automatically choose an appropriate
- interface.
+ Mandos servers to connect to. The default it
+ eth0
.
If the option is used, this
specifies the interface to use to connect to the address
given.
-
- Note that since this program will normally run in the
- initial RAM disk environment, the interface must be an
- interface which exists at that stage. Thus, the interface
- can not be a pseudo-interface such as br0
- or tun0
; such interfaces will not exist
- until much later in the boot process, and can not be used
- by this program.
-
-
- NAME can be the string
- none
; this will not use
- any specific interface, and will not bring up an interface
- on startup. This is not recommended, and only meant for
- advanced users.
-
@@ -277,22 +250,6 @@
-
-
-
-
-
- After bringing the network interface up, the program waits
- for the interface to arrive in a running
- state before proceeding. During this time, the kernel log
- level will be lowered to reduce clutter on the system
- console, alleviating any other plugins which might be
- using the system console. This option sets the upper
- limit of seconds to wait. The default is 2.5 seconds.
-
-
-
@@ -454,15 +411,15 @@
Run in debug mode, with a custom key, and do not use Zeroconf
- to locate a server; connect directly to the IPv6 link-local
- address fe80::aede:48ff:fe71:f6f2
, port 4711,
- using interface eth2:
+ to locate a server; connect directly to the IPv6 address
+ 2001:db8:f983:bd0b:30de:ae4a:71f2:f672
,
+ port 4711, using interface eth2:
-&COMMANDNAME; --debug --pubkey keydir/pubkey.txt --seckey keydir/seckey.txt --connect fe80::aede:48ff:fe71:f6f2:4711 --interface eth2
+&COMMANDNAME; --debug --pubkey keydir/pubkey.txt --seckey keydir/seckey.txt --connect 2001:db8:f983:bd0b:30de:ae4a:71f2:f672:4711 --interface eth2
=== modified file 'plugins.d/password-prompt.c'
--- plugins.d/password-prompt.c 2010-09-26 18:32:58 +0000
+++ plugins.d/password-prompt.c 2008-11-11 16:07:18 +0000
@@ -1,9 +1,9 @@
-/* -*- coding: utf-8; mode: c; mode: orgtbl -*- */
+/* -*- coding: utf-8 -*- */
/*
- * Password-prompt - Read a password from the terminal and print it
+ * Passprompt - Read a password from the terminal and print it
*
- * Copyright © 2008-2010 Teddy Hogeborn
- * Copyright © 2008-2010 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
@@ -19,7 +19,8 @@
* along with this program. If not, see
* .
*
- * Contact the authors at .
+ * Contact the authors at and
+ * .
*/
#define _GNU_SOURCE /* getline() */
@@ -32,47 +33,35 @@
#include /* sig_atomic_t, raise(), struct
sigaction, sigemptyset(),
sigaction(), sigaddset(), SIGINT,
- SIGQUIT, SIGHUP, SIGTERM,
- raise() */
+ SIGQUIT, SIGHUP, SIGTERM */
#include /* NULL, size_t, ssize_t */
#include /* ssize_t */
#include /* EXIT_SUCCESS, EXIT_FAILURE,
- getenv() */
+ getopt_long, getenv() */
#include /* fprintf(), stderr, getline(),
- stdin, feof(), fputc()
- */
-#include /* errno, EBADF, ENOTTY, EINVAL,
- EFAULT, EFBIG, EIO, ENOSPC, EINTR
- */
-#include /* error() */
+ stdin, feof(), perror(), fputc(),
+ stdout, getopt_long */
+#include /* errno, EINVAL */
#include /* or, not */
#include /* bool, false, true */
-#include /* strlen, rindex */
+#include /* strlen, rindex, strncmp, strcmp */
#include /* struct argp_option, struct
argp_state, struct argp,
argp_parse(), error_t,
ARGP_KEY_ARG, ARGP_KEY_END,
ARGP_ERR_UNKNOWN */
-#include /* EX_SOFTWARE, EX_OSERR,
- EX_UNAVAILABLE, EX_IOERR, EX_OK */
-volatile sig_atomic_t quit_now = 0;
-int signal_received;
+volatile bool quit_now = false;
bool debug = false;
const char *argp_program_version = "password-prompt " VERSION;
const char *argp_program_bug_address = "";
-static void termination_handler(int signum){
- if(quit_now){
- return;
- }
- quit_now = 1;
- signal_received = signum;
+static void termination_handler(__attribute__((unused))int signum){
+ quit_now = true;
}
int main(int argc, char **argv){
- ssize_t sret;
- int ret;
+ ssize_t ret;
size_t n;
struct termios t_new, t_old;
char *buffer = NULL;
@@ -88,167 +77,111 @@
.doc = "Prefix shown before the prompt", .group = 2 },
{ .name = "debug", .key = 128,
.doc = "Debug mode", .group = 3 },
- /*
- * These reproduce what we would get without ARGP_NO_HELP
- */
- { .name = "help", .key = '?',
- .doc = "Give this help list", .group = -1 },
- { .name = "usage", .key = -3,
- .doc = "Give a short usage message", .group = -1 },
- { .name = "version", .key = 'V',
- .doc = "Print program version", .group = -1 },
{ .name = NULL }
};
-
- error_t parse_opt (int key, char *arg, struct argp_state *state){
- errno = 0;
- switch (key){
+
+ error_t parse_opt (int key, char *arg, struct argp_state *state) {
+ /* Get the INPUT argument from `argp_parse', which we know is a
+ pointer to our plugin list pointer. */
+ switch (key) {
case 'p':
prefix = arg;
break;
case 128:
debug = true;
break;
- /*
- * These reproduce what we would get without ARGP_NO_HELP
- */
- case '?': /* --help */
- argp_state_help(state, state->out_stream,
- (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
- & ~(unsigned int)ARGP_HELP_EXIT_OK);
- case -3: /* --usage */
- argp_state_help(state, state->out_stream,
- ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
- case 'V': /* --version */
- fprintf(state->out_stream, "%s\n", argp_program_version);
- exit(argp_err_exit_status);
+ case ARGP_KEY_ARG:
+ argp_usage (state);
+ break;
+ case ARGP_KEY_END:
break;
default:
return ARGP_ERR_UNKNOWN;
}
- return errno;
+ return 0;
}
-
+
struct argp argp = { .options = options, .parser = parse_opt,
.args_doc = "",
.doc = "Mandos password-prompt -- Read and"
" output a password" };
- ret = argp_parse(&argp, argc, argv,
- ARGP_IN_ORDER | ARGP_NO_HELP, NULL, NULL);
- switch(ret){
- case 0:
- break;
- case ENOMEM:
- default:
- errno = ret;
- error(0, errno, "argp_parse");
- return EX_OSERR;
- case EINVAL:
- return EX_USAGE;
+ ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
+ if (ret == ARGP_ERR_UNKNOWN){
+ fprintf(stderr, "Unknown error while parsing arguments\n");
+ return EXIT_FAILURE;
}
}
-
- if(debug){
+
+ if (debug){
fprintf(stderr, "Starting %s\n", argv[0]);
}
- if(debug){
+ if (debug){
fprintf(stderr, "Storing current terminal attributes\n");
}
- if(tcgetattr(STDIN_FILENO, &t_old) != 0){
- int e = errno;
- error(0, errno, "tcgetattr");
- switch(e){
- case EBADF:
- case ENOTTY:
- return EX_UNAVAILABLE;
- default:
- return EX_OSERR;
- }
+ if (tcgetattr(STDIN_FILENO, &t_old) != 0){
+ perror("tcgetattr");
+ return EXIT_FAILURE;
}
sigemptyset(&new_action.sa_mask);
- ret = sigaddset(&new_action.sa_mask, SIGINT);
- if(ret == -1){
- error(0, errno, "sigaddset");
- return EX_OSERR;
- }
- ret = sigaddset(&new_action.sa_mask, SIGHUP);
- if(ret == -1){
- error(0, errno, "sigaddset");
- return EX_OSERR;
- }
- ret = sigaddset(&new_action.sa_mask, SIGTERM);
- if(ret == -1){
- error(0, errno, "sigaddset");
- return EX_OSERR;
- }
- /* Need to check if the handler is SIG_IGN before handling:
- | [[info:libc:Initial Signal Actions]] |
- | [[info:libc:Basic Signal Handling]] |
- */
+ sigaddset(&new_action.sa_mask, SIGINT);
+ sigaddset(&new_action.sa_mask, SIGHUP);
+ sigaddset(&new_action.sa_mask, SIGTERM);
ret = sigaction(SIGINT, NULL, &old_action);
if(ret == -1){
- error(0, errno, "sigaction");
- return EX_OSERR;
+ perror("sigaction");
+ return EXIT_FAILURE;
}
- if(old_action.sa_handler != SIG_IGN){
+ if (old_action.sa_handler != SIG_IGN){
ret = sigaction(SIGINT, &new_action, NULL);
if(ret == -1){
- error(0, errno, "sigaction");
- return EX_OSERR;
+ perror("sigaction");
+ return EXIT_FAILURE;
}
}
ret = sigaction(SIGHUP, NULL, &old_action);
if(ret == -1){
- error(0, errno, "sigaction");
- return EX_OSERR;
+ perror("sigaction");
+ return EXIT_FAILURE;
}
- if(old_action.sa_handler != SIG_IGN){
+ if (old_action.sa_handler != SIG_IGN){
ret = sigaction(SIGHUP, &new_action, NULL);
if(ret == -1){
- error(0, errno, "sigaction");
- return EX_OSERR;
+ perror("sigaction");
+ return EXIT_FAILURE;
}
}
ret = sigaction(SIGTERM, NULL, &old_action);
if(ret == -1){
- error(0, errno, "sigaction");
- return EX_OSERR;
+ perror("sigaction");
+ return EXIT_FAILURE;
}
- if(old_action.sa_handler != SIG_IGN){
+ if (old_action.sa_handler != SIG_IGN){
ret = sigaction(SIGTERM, &new_action, NULL);
if(ret == -1){
- error(0, errno, "sigaction");
- return EX_OSERR;
+ perror("sigaction");
+ return EXIT_FAILURE;
}
}
- if(debug){
+ if (debug){
fprintf(stderr, "Removing echo flag from terminal attributes\n");
}
t_new = t_old;
- t_new.c_lflag &= ~(tcflag_t)ECHO;
- if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
- int e = errno;
- error(0, errno, "tcsetattr-echo");
- switch(e){
- case EBADF:
- case ENOTTY:
- return EX_UNAVAILABLE;
- case EINVAL:
- default:
- return EX_OSERR;
- }
+ t_new.c_lflag &= ~ECHO;
+ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){
+ perror("tcsetattr-echo");
+ return EXIT_FAILURE;
}
-
- if(debug){
+
+ if (debug){
fprintf(stderr, "Waiting for input from stdin \n");
}
while(true){
- if(quit_now){
+ if (quit_now){
if(debug){
fprintf(stderr, "Interrupted by signal, exiting.\n");
}
@@ -260,134 +193,78 @@
fprintf(stderr, "%s ", prefix);
}
{
- const char *cryptsource = getenv("CRYPTTAB_SOURCE");
- const char *crypttarget = getenv("CRYPTTAB_NAME");
- /* Before cryptsetup 1.1.0~rc2 */
- if(cryptsource == NULL){
- cryptsource = getenv("cryptsource");
- }
- if(crypttarget == NULL){
- crypttarget = getenv("crypttarget");
- }
- const char *const prompt1 = "Unlocking the disk";
- const char *const prompt2 = "Enter passphrase";
+ const char *cryptsource = getenv("cryptsource");
+ const char *crypttarget = getenv("crypttarget");
+ const char *const prompt
+ = "Enter passphrase to unlock the disk";
if(cryptsource == NULL){
if(crypttarget == NULL){
- fprintf(stderr, "%s to unlock the disk: ", prompt2);
+ fprintf(stderr, "%s: ", prompt);
} else {
- fprintf(stderr, "%s (%s)\n%s: ", prompt1, crypttarget,
- prompt2);
+ fprintf(stderr, "%s (%s): ", prompt, crypttarget);
}
} else {
if(crypttarget == NULL){
- fprintf(stderr, "%s %s\n%s: ", prompt1, cryptsource,
- prompt2);
+ fprintf(stderr, "%s %s: ", prompt, cryptsource);
} else {
- fprintf(stderr, "%s %s (%s)\n%s: ", prompt1, cryptsource,
- crypttarget, prompt2);
+ fprintf(stderr, "%s %s (%s): ", prompt, cryptsource,
+ crypttarget);
}
}
}
- sret = getline(&buffer, &n, stdin);
- if(sret > 0){
+ ret = getline(&buffer, &n, stdin);
+ if (ret > 0){
status = EXIT_SUCCESS;
/* Make n = data size instead of allocated buffer size */
- n = (size_t)sret;
+ n = (size_t)ret;
/* Strip final newline */
- if(n > 0 and buffer[n-1] == '\n'){
+ if(n>0 and buffer[n-1] == '\n'){
buffer[n-1] = '\0'; /* not strictly necessary */
n--;
}
size_t written = 0;
while(written < n){
- sret = write(STDOUT_FILENO, buffer + written, n - written);
- if(sret < 0){
- int e = errno;
- error(0, errno, "write");
- switch(e){
- case EBADF:
- case EFAULT:
- case EINVAL:
- case EFBIG:
- case EIO:
- case ENOSPC:
- default:
- status = EX_IOERR;
- break;
- case EINTR:
- status = EXIT_FAILURE;
- break;
- }
- break;
- }
- written += (size_t)sret;
- }
- sret = close(STDOUT_FILENO);
- if(sret == -1){
- int e = errno;
- error(0, errno, "close");
- switch(e){
- case EBADF:
- status = EX_OSFILE;
- break;
- case EIO:
- default:
- status = EX_IOERR;
- break;
- }
+ ret = write(STDOUT_FILENO, buffer + written, n - written);
+ if(ret < 0){
+ perror("write");
+ status = EXIT_FAILURE;
+ break;
+ }
+ written += (size_t)ret;
}
break;
}
- if(sret < 0){
- int e = errno;
- if(errno != EINTR and not feof(stdin)){
- error(0, errno, "getline");
- switch(e){
- case EBADF:
- status = EX_UNAVAILABLE;
- case EIO:
- case EINVAL:
- default:
- status = EX_IOERR;
- break;
- }
+ if (ret < 0){
+ if (errno != EINTR and not feof(stdin)){
+ perror("getline");
+ status = EXIT_FAILURE;
break;
}
}
- /* if(sret == 0), then the only sensible thing to do is to retry to
+ /* if(ret == 0), then the only sensible thing to do is to retry to
read from stdin */
fputc('\n', stderr);
if(debug and not quit_now){
- /* If quit_now is nonzero, we were interrupted by a signal, and
+ /* If quit_now is true, we were interrupted by a signal, and
will print that later, so no need to show this too. */
fprintf(stderr, "getline() returned 0, retrying.\n");
}
}
-
+
free(buffer);
- if(debug){
+ if (debug){
fprintf(stderr, "Restoring terminal attributes\n");
}
- if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
- error(0, errno, "tcsetattr+echo");
- }
-
- if(quit_now){
- sigemptyset(&old_action.sa_mask);
- old_action.sa_handler = SIG_DFL;
- ret = sigaction(signal_received, &old_action, NULL);
- if(ret == -1){
- error(0, errno, "sigaction");
- }
- raise(signal_received);
- }
-
- if(debug){
+ if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){
+ perror("tcsetattr+echo");
+ }
+
+ if (debug){
fprintf(stderr, "%s is exiting with status %d\n", argv[0],
status);
}
- if(status == EXIT_SUCCESS or status == EX_OK){
+ if(status == EXIT_SUCCESS){
fputc('\n', stderr);
}
=== modified file 'plugins.d/password-prompt.xml'
--- plugins.d/password-prompt.xml 2009-10-30 16:23:43 +0000
+++ plugins.d/password-prompt.xml 2008-10-04 01:55:56 +0000
@@ -2,7 +2,7 @@
-
+
%common;
]>
@@ -32,7 +32,6 @@
2008
- 2009
Teddy Hogeborn
Björn Påhlsson
@@ -183,8 +182,8 @@
ENVIRONMENT
- CRYPTTAB_SOURCE
- CRYPTTAB_NAME
+ cryptsource
+ crypttarget
If set, these environment variables will be assumed to
=== removed file 'plugins.d/plymouth.c'
--- plugins.d/plymouth.c 2010-09-26 18:32:58 +0000
+++ plugins.d/plymouth.c 1970-01-01 00:00:00 +0000
@@ -1,431 +0,0 @@
-/* -*- coding: utf-8 -*- */
-/*
- * Usplash - Read a password from usplash and output it
- *
- * Copyright © 2010 Teddy Hogeborn
- * Copyright © 2010 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 .
- */
-
-#define _GNU_SOURCE /* asprintf(), TEMP_FAILURE_RETRY() */
-#include /* sig_atomic_t, struct sigaction,
- sigemptyset(), sigaddset(), SIGINT,
- SIGHUP, SIGTERM, sigaction(),
- kill(), SIG_IGN */
-#include /* bool, false, true */
-#include /* open(), O_RDONLY */
-#include /* and, or, not*/
-#include /* size_t, ssize_t, pid_t, struct
- dirent, waitpid() */
-#include /* waitpid() */
-#include /* NULL */
-#include /* strchr(), memcmp() */
-#include /* asprintf(), perror(), fopen(),
- fscanf() */
-#include /* close(), readlink(), read(),
- fork(), setsid(), chdir(), dup2(),
- STDERR_FILENO, execv(), access() */
-#include /* free(), EXIT_FAILURE, realloc(),
- EXIT_SUCCESS, malloc(), _exit(),
- getenv() */
-#include /* scandir(), alphasort() */
-#include /* intmax_t, strtoumax(), SCNuMAX */
-#include /* struct stat, lstat() */
-#include /* EX_OSERR, EX_UNAVAILABLE */
-#include /* error() */
-#include /* TEMP_FAILURE_RETRY */
-#include /* argz_count(), argz_extract() */
-
-sig_atomic_t interrupted_by_signal = 0;
-const char plymouth_pid[] = "/dev/.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){
- if(interrupted_by_signal){
- return;
- }
- interrupted_by_signal = 1;
-}
-
-/* Create prompt string */
-char *makeprompt(void){
- int ret = 0;
- char *prompt;
- const char *const cryptsource = getenv("cryptsource");
- const char *const crypttarget = getenv("crypttarget");
- const char prompt_start[] = "Enter passphrase to unlock the disk";
-
- if(cryptsource == NULL){
- if(crypttarget == NULL){
- ret = asprintf(&prompt, "%s: ", prompt_start);
- } else {
- ret = asprintf(&prompt, "%s (%s): ", prompt_start,
- crypttarget);
- }
- } else {
- if(crypttarget == NULL){
- ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
- } else {
- ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
- cryptsource, crypttarget);
- }
- }
- if(ret == -1){
- return NULL;
- }
- return prompt;
-}
-
-void kill_and_wait(pid_t pid){
- TEMP_FAILURE_RETRY(kill(pid, SIGTERM));
- TEMP_FAILURE_RETRY(waitpid(pid, NULL, 0));
-}
-
-bool become_a_daemon(void){
- int ret = setuid(geteuid());
- if(ret == -1){
- error(0, errno, "setuid");
- }
-
- setsid();
- ret = chdir("/");
- if(ret == -1){
- error(0, errno, "chdir");
- return false;
- }
- ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
- if(ret == -1){
- error(0, errno, "dup2");
- return false;
- }
- return true;
-}
-
-bool exec_and_wait(pid_t *pid_return, const char *path,
- const char **argv, bool interruptable,
- bool daemonize){
- int status;
- int ret;
- pid_t pid;
- pid = fork();
- if(pid == -1){
- error(0, errno, "fork");
- return false;
- }
- if(pid == 0){
- /* Child */
- if(daemonize){
- if(not become_a_daemon()){
- _exit(EX_OSERR);
- }
- }
-
- char **new_argv = NULL;
- char *tmp;
- int i = 0;
- for (; argv[i]!=(char *)NULL; i++){
- tmp = realloc(new_argv, sizeof(const char *) * ((size_t)i + 1));
- if (tmp == NULL){
- error(0, errno, "realloc");
- free(new_argv);
- _exit(EX_OSERR);
- }
- new_argv = (char **)tmp;
- new_argv[i] = strdup(argv[i]);
- }
- new_argv[i] = (char *) NULL;
-
- execv(path, (char *const *)new_argv);
- error(0, errno, "execv");
- _exit(EXIT_FAILURE);
- }
- if(pid_return != NULL){
- *pid_return = pid;
- }
- do {
- ret = waitpid(pid, &status, 0);
- } while(ret == -1 and errno == EINTR
- and ((not interrupted_by_signal)
- or (not interruptable)));
- if(interrupted_by_signal and interruptable){
- return false;
- }
- if(ret == -1){
- error(0, errno, "waitpid");
- return false;
- }
- if(WIFEXITED(status) and (WEXITSTATUS(status) == 0)){
- return true;
- }
- return false;
-}
-
-int is_plymouth(const struct dirent *proc_entry){
- int ret;
- {
- uintmax_t maxvalue;
- char *tmp;
- errno = 0;
- maxvalue = strtoumax(proc_entry->d_name, &tmp, 10);
-
- if(errno != 0 or *tmp != '\0'
- or maxvalue != (uintmax_t)((pid_t)maxvalue)){
- return 0;
- }
- }
- char exe_target[sizeof(plymouth_path)];
- char *exe_link;
- ret = asprintf(&exe_link, "/proc/%s/exe", proc_entry->d_name);
- if(ret == -1){
- error(0, errno, "asprintf");
- return 0;
- }
-
- struct stat exe_stat;
- ret = lstat(exe_link, &exe_stat);
- if(ret == -1){
- free(exe_link);
- if(errno != ENOENT){
- error(0, errno, "lstat");
- }
- return 0;
- }
-
- if(not S_ISLNK(exe_stat.st_mode)
- or exe_stat.st_uid != 0
- or exe_stat.st_gid != 0){
- free(exe_link);
- return 0;
- }
-
- ssize_t sret = readlink(exe_link, exe_target, sizeof(exe_target));
- free(exe_link);
- if((sret != (ssize_t)sizeof(plymouth_path)-1) or
- (memcmp(plymouth_path, exe_target,
- sizeof(plymouth_path)-1) != 0)){
- return 0;
- }
- return 1;
-}
-
-pid_t get_pid(void){
- int ret;
- FILE *pidfile = fopen(plymouth_pid, "r");
- uintmax_t maxvalue = 0;
- if(pidfile != NULL){
- ret = fscanf(pidfile, "%" SCNuMAX, &maxvalue);
- if(ret != 1){
- maxvalue = 0;
- }
- fclose(pidfile);
- }
- if(maxvalue == 0){
- struct dirent **direntries;
- ret = scandir("/proc", &direntries, is_plymouth, alphasort);
- sscanf(direntries[0]->d_name, "%" SCNuMAX, &maxvalue);
- }
- pid_t pid;
- pid = (pid_t)maxvalue;
- if((uintmax_t)pid == maxvalue){
- return pid;
- }
-
- return 0;
-}
-
-const char **getargv(pid_t pid){
- int cl_fd;
- char *cmdline_filename;
- ssize_t sret;
- int ret;
-
- ret = asprintf(&cmdline_filename, "/proc/%" PRIuMAX "/cmdline",
- (uintmax_t)pid);
- if(ret == -1){
- error(0, errno, "asprintf");
- return NULL;
- }
-
- /* Open /proc//cmdline */
- cl_fd = open(cmdline_filename, O_RDONLY);
- free(cmdline_filename);
- if(cl_fd == -1){
- error(0, errno, "open");
- return NULL;
- }
-
- size_t cmdline_allocated = 0;
- size_t cmdline_len = 0;
- char *cmdline = NULL;
- char *tmp;
- const size_t blocksize = 1024;
- do {
- /* Allocate more space? */
- if(cmdline_len + blocksize > cmdline_allocated){
- tmp = realloc(cmdline, cmdline_allocated + blocksize);
- if(tmp == NULL){
- error(0, errno, "realloc");
- free(cmdline);
- close(cl_fd);
- return NULL;
- }
- cmdline = tmp;
- cmdline_allocated += blocksize;
- }
-
- /* Read data */
- sret = read(cl_fd, cmdline + cmdline_len,
- cmdline_allocated - cmdline_len);
- if(sret == -1){
- error(0, errno, "read");
- free(cmdline);
- close(cl_fd);
- return NULL;
- }
- cmdline_len += (size_t)sret;
- } while(sret != 0);
- ret = close(cl_fd);
- if(ret == -1){
- error(0, errno, "close");
- free(cmdline);
- return NULL;
- }
-
- /* we got cmdline and cmdline_len, ignore rest... */
- char **argv = malloc((argz_count(cmdline, cmdline_len) + 1)
- * sizeof(char *)); /* Get number of args */
- if(argv == NULL){
- error(0, errno, "argv = malloc()");
- free(cmdline);
- return NULL;
- }
- argz_extract(cmdline, cmdline_len, argv); /* Create argv */
- return (const char **)argv;
-}
-
-int main(__attribute__((unused))int argc,
- __attribute__((unused))char **argv){
- char *prompt;
- char *prompt_arg;
- pid_t plymouth_command_pid;
- int ret;
- bool bret;
-
- /* test -x /bin/plymouth */
- ret = access(plymouth_path, X_OK);
- if(ret == -1){
- /* Plymouth is probably not installed. Don't print an error
- message, just exit. */
- exit(EX_UNAVAILABLE);
- }
-
- { /* Add signal handlers */
- struct sigaction old_action,
- new_action = { .sa_handler = termination_handler,
- .sa_flags = 0 };
- sigemptyset(&new_action.sa_mask);
- for(int *sig = (int[]){ SIGINT, SIGHUP, SIGTERM, 0 };
- *sig != 0; sig++){
- ret = sigaddset(&new_action.sa_mask, *sig);
- if(ret == -1){
- error(EX_OSERR, errno, "sigaddset");
- }
- ret = sigaction(*sig, NULL, &old_action);
- if(ret == -1){
- error(EX_OSERR, errno, "sigaction");
- }
- if(old_action.sa_handler != SIG_IGN){
- ret = sigaction(*sig, &new_action, NULL);
- if(ret == -1){
- error(EX_OSERR, errno, "sigaction");
- }
- }
- }
- }
-
- /* plymouth --ping */
- bret = exec_and_wait(&plymouth_command_pid, plymouth_path,
- (const char *[])
- { plymouth_path, "--ping", NULL },
- true, false);
- if(not bret){
- if(interrupted_by_signal){
- kill_and_wait(plymouth_command_pid);
- exit(EXIT_FAILURE);
- }
- /* Plymouth is probably not running. Don't print an error
- message, just exit. */
- exit(EX_UNAVAILABLE);
- }
-
- prompt = makeprompt();
- ret = asprintf(&prompt_arg, "--prompt=%s", prompt);
- free(prompt);
- if(ret == -1){
- error(EX_OSERR, errno, "asprintf");
- }
-
- /* plymouth ask-for-password --prompt="$prompt" */
- bret = exec_and_wait(&plymouth_command_pid,
- plymouth_path, (const char *[])
- { plymouth_path, "ask-for-password",
- prompt_arg, NULL },
- true, false);
- free(prompt_arg);
- if(bret){
- exit(EXIT_SUCCESS);
- }
- if(not interrupted_by_signal){
- /* exec_and_wait failed for some other reason */
- exit(EXIT_FAILURE);
- }
- kill_and_wait(plymouth_command_pid);
-
- const char **plymouthd_argv;
- pid_t pid = get_pid();
- if(pid == 0){
- error(0, 0, "plymouthd pid not found");
- plymouthd_argv = plymouthd_default_argv;
- } else {
- plymouthd_argv = getargv(pid);
- }
-
- bret = exec_and_wait(NULL, plymouth_path, (const char *[])
- { plymouth_path, "quit", NULL },
- false, false);
- if(not bret){
- exit(EXIT_FAILURE);
- }
- bret = exec_and_wait(NULL, plymouthd_path, plymouthd_argv,
- false, true);
- if(not bret){
- exit(EXIT_FAILURE);
- }
- exec_and_wait(NULL, plymouth_path, (const char *[])
- { plymouth_path, "show-splash", NULL },
- false, false);
- exit(EXIT_FAILURE);
-}
=== removed file 'plugins.d/plymouth.xml'
--- plugins.d/plymouth.xml 2010-09-26 18:32:58 +0000
+++ plugins.d/plymouth.xml 1970-01-01 00:00:00 +0000
@@ -1,278 +0,0 @@
-
-
-
-
-%common;
-]>
-
-
-
- Mandos Manual
-
- Mandos
- &version;
- &TIMESTAMP;
-
-
- Björn
- Påhlsson
-
- belorn@fukt.bsnet.se
-
-
-
- Teddy
- Hogeborn
-
- teddy@fukt.bsnet.se
-
-
-
-
- 2010
- Teddy Hogeborn
- Björn Påhlsson
-
-
-
-
-
- &COMMANDNAME;
- 8mandos
-
-
-
- &COMMANDNAME;
- Mandos plugin to use plymouth to get a
- password.
-
-
-
-
- &COMMANDNAME;
-
-
-
-
- DESCRIPTION
-
- This program prompts for a password using
- plymouth8
- and outputs any given password to standard
- output. If no plymouth8
- process can be found, this program will immediately exit with an
- exit code indicating failure.
-
-
- This program is not very useful on its own. This program is
- really meant to run as a plugin in the Mandos client-side system, where it is used as a
- fallback and alternative to retrieving passwords from a
- Mandos server.
-
-
- If this program is killed (presumably by
- plugin-runner
- 8mandos because some other
- plugin provided the password), it cannot tell
- plymouth8
- to abort requesting a password, because
- plymouth
- 8 does not support this.
- Therefore, this program will then kill the
- running plymouth
- 8 process and start a
- new one using the same command line
- arguments as the old one was using.
-
-
-
-
- OPTIONS
-
- This program takes no options.
-
-
-
-
- EXIT STATUS
-
- If exit status is 0, the output from the program is the password
- as it was read. Otherwise, if exit status is other than 0, the
- program was interrupted or encountered an error, and any output
- so far could be corrupt and/or truncated, and should therefore
- be ignored.
-
-
-
-
- ENVIRONMENT
-
-
- cryptsource
- crypttarget
-
-
- If set, these environment variables will be assumed to
- contain the source device name and the target device
- mapper name, respectively, and will be shown as part of
- the prompt.
-
-
- These variables will normally be inherited from
- plugin-runner
- 8mandos, which will
- normally have inherited them from
- /scripts/local-top/cryptroot in the
- initial RAM disk environment, which will
- have set them from parsing kernel arguments and
- /conf/conf.d/cryptroot (also in the
- initial RAM disk environment), which in turn will have been
- created when the initial RAM disk image was created by
- /usr/share/initramfs-tools/hooks/cryptroot, by
- extracting the information of the root file system from
- /etc/crypttab.
-
-
- This behavior is meant to exactly mirror the behavior of
- askpass, the default password prompter.
-
-
-
-
-
-
-
- FILES
-
-
- /bin/plymouth
-
-
- This is the command run to retrieve a password from
- plymouth
- 8.
-
-
-
-
- /proc
-
-
- To find the running plymouth8
- , this directory will be searched for
- numeric entries which will be assumed to be directories.
- In all those directories, the exe and
- cmdline entries will be used to
- determine the name of the running binary, effective user
- and group ID, and the command line
- arguments. See proc5
- .
-
-
-
-
- /sbin/plymouthd
-
-
- This is the name of the binary which will be searched for
- in the process list. See plymouth8
- .
-
-
-
-
-
-
-
- BUGS
-
- Killing the plymouth8
- daemon and starting a new one is ugly, but necessary as long as
- it does not support aborting a password request.
-
-
-
-
- EXAMPLE
-
- Note that normally, this program will not be invoked directly,
- but instead started by the Mandos plugin-runner8mandos
- .
-
-
-
- This program takes no options.
-
-
- &COMMANDNAME;
-
-
-
-
-
- SECURITY
-
- If this program is killed by a signal, it will kill the process
- ID which at the start of this program was
- determined to run plymouth8
- as root (see also ). There is a very
- slight risk that, in the time between those events, that process
- ID was freed and then taken up by another
- process; the wrong process would then be killed. Now, this
- program can only be killed by the user who started it; see
- plugin-runner
- 8mandos. This program
- should therefore be started by a completely separate
- non-privileged user, and no other programs should be allowed to
- run as that special user. This means that it is not recommended
- to use the user "nobody" to start this program, as other
- possibly less trusted programs could be running as "nobody", and
- they would then be able to kill this program, triggering the
- killing of the process ID which may or may not
- be plymouth
- 8.
-
-
- The only other thing that could be considered worthy of note is
- this: This program is meant to be run by
- plugin-runner8mandos, and will, when run
- standalone, outside, in a normal environment, immediately output
- on its standard output any presumably secret password it just
- received. Therefore, when running this program standalone
- (which should never normally be done), take care not to type in
- any real secret password by force of habit, since it would then
- immediately be shown as output.
-
-
-
-
- SEE ALSO
-
- crypttab
- 5,
- plugin-runner
- 8mandos,
- proc
- 5,
- plymouth
- 8
-
-
-
-
-
-
-
-
=== modified file 'plugins.d/splashy.c'
--- plugins.d/splashy.c 2010-09-26 18:32:58 +0000
+++ plugins.d/splashy.c 2008-11-11 16:07:18 +0000
@@ -1,9 +1,9 @@
/* -*- coding: utf-8 -*- */
/*
- * Splashy - Read a password from splashy and output it
+ * Passprompt - Read a password from splashy and output it
*
- * Copyright © 2008-2010 Teddy Hogeborn
- * Copyright © 2008-2010 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
@@ -19,63 +19,45 @@
* along with this program. If not, see
* .
*
- * Contact the authors at .
+ * Contact the authors at and
+ * .
*/
-#define _GNU_SOURCE /* TEMP_FAILURE_RETRY(), asprintf() */
+#define _GNU_SOURCE /* asprintf() */
#include /* sig_atomic_t, struct sigaction,
sigemptyset(), sigaddset(), SIGINT,
SIGHUP, SIGTERM, sigaction,
SIG_IGN, kill(), SIGKILL */
#include /* NULL */
#include /* getenv() */
-#include /* asprintf() */
-#include /* EXIT_FAILURE, free(),
+#include /* asprintf(), perror() */
+#include /* EXIT_FAILURE, free(), strtoul(),
EXIT_SUCCESS */
#include /* pid_t, DIR, struct dirent,
ssize_t */
#include /* opendir(), readdir(), closedir() */
-#include /* intmax_t, strtoimax() */
#include /* struct stat, lstat(), S_ISLNK */
#include /* not, or, and */
#include /* readlink(), fork(), execl(),
sleep(), dup2() STDERR_FILENO,
- STDOUT_FILENO, _exit(),
- pause() */
+ STDOUT_FILENO, _exit() */
#include /* memcmp() */
-#include /* errno, EACCES, ENOTDIR, ELOOP,
- ENOENT, ENAMETOOLONG, EMFILE,
- ENFILE, ENOMEM, ENOEXEC, EINVAL,
- E2BIG, EFAULT, EIO, ETXTBSY,
- EISDIR, ELIBBAD, EPERM, EINTR,
- ECHILD */
-#include /* error() */
+#include /* errno */
#include /* waitpid(), WIFEXITED(),
WEXITSTATUS() */
-#include /* EX_OSERR, EX_OSFILE,
- EX_UNAVAILABLE */
sig_atomic_t interrupted_by_signal = 0;
-int signal_received;
-static void termination_handler(int signum){
- if(interrupted_by_signal){
- return;
- }
+static void termination_handler(__attribute__((unused))int signum){
interrupted_by_signal = 1;
- signal_received = signum;
}
int main(__attribute__((unused))int argc,
__attribute__((unused))char **argv){
int ret = 0;
+
+ /* Create prompt string */
char *prompt = NULL;
- DIR *proc_dir = NULL;
- pid_t splashy_pid = 0;
- pid_t splashy_command_pid = 0;
- int exitstatus = EXIT_FAILURE;
-
- /* Create prompt string */
{
const char *const cryptsource = getenv("cryptsource");
const char *const crypttarget = getenv("crypttarget");
@@ -98,51 +80,27 @@
}
}
if(ret == -1){
- prompt = NULL;
- exitstatus = EX_OSERR;
- goto failure;
+ return EXIT_FAILURE;
}
}
/* Find splashy process */
+ pid_t splashy_pid = 0;
{
const char splashy_name[] = "/sbin/splashy";
- proc_dir = opendir("/proc");
+ DIR *proc_dir = opendir("/proc");
if(proc_dir == NULL){
- int e = errno;
- error(0, errno, "opendir");
- switch(e){
- case EACCES:
- case ENOTDIR:
- case ELOOP:
- case ENOENT:
- default:
- exitstatus = EX_OSFILE;
- break;
- case ENAMETOOLONG:
- case EMFILE:
- case ENFILE:
- case ENOMEM:
- exitstatus = EX_OSERR;
- break;
- }
- goto failure;
+ free(prompt);
+ perror("opendir");
+ return EXIT_FAILURE;
}
for(struct dirent *proc_ent = readdir(proc_dir);
proc_ent != NULL;
proc_ent = readdir(proc_dir)){
- pid_t pid;
- {
- intmax_t tmpmax;
- char *tmp;
- errno = 0;
- tmpmax = strtoimax(proc_ent->d_name, &tmp, 10);
- if(errno != 0 or tmp == proc_ent->d_name or *tmp != '\0'
- or tmpmax != (pid_t)tmpmax){
- /* Not a process */
- continue;
- }
- pid = (pid_t)tmpmax;
+ pid_t pid = (pid_t) strtoul(proc_ent->d_name, NULL, 10);
+ if(pid == 0){
+ /* Not a process */
+ continue;
}
/* Find the executable name by doing readlink() on the
/proc//exe link */
@@ -152,34 +110,21 @@
char *exe_link;
ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
if(ret == -1){
- error(0, errno, "asprintf");
- exitstatus = EX_OSERR;
- goto failure;
+ perror("asprintf");
+ free(prompt);
+ closedir(proc_dir);
+ return EXIT_FAILURE;
}
/* Check that it refers to a symlink owned by root:root */
struct stat exe_stat;
ret = lstat(exe_link, &exe_stat);
if(ret == -1){
- if(errno == ENOENT){
- free(exe_link);
- continue;
- }
- int e = errno;
- error(0, errno, "lstat");
+ perror("lstat");
free(exe_link);
- switch(e){
- case EACCES:
- case ENOTDIR:
- case ELOOP:
- default:
- exitstatus = EX_OSFILE;
- break;
- case ENAMETOOLONG:
- exitstatus = EX_OSERR;
- break;
- }
- goto failure;
+ free(prompt);
+ closedir(proc_dir);
+ return EXIT_FAILURE;
}
if(not S_ISLNK(exe_stat.st_mode)
or exe_stat.st_uid != 0
@@ -199,11 +144,10 @@
}
}
closedir(proc_dir);
- proc_dir = NULL;
}
if(splashy_pid == 0){
- exitstatus = EX_UNAVAILABLE;
- goto failure;
+ free(prompt);
+ return EXIT_FAILURE;
}
/* Set up the signal handler */
@@ -212,231 +156,136 @@
new_action = { .sa_handler = termination_handler,
.sa_flags = 0 };
sigemptyset(&new_action.sa_mask);
- ret = sigaddset(&new_action.sa_mask, SIGINT);
- if(ret == -1){
- error(0, errno, "sigaddset");
- exitstatus = EX_OSERR;
- goto failure;
- }
- ret = sigaddset(&new_action.sa_mask, SIGHUP);
- if(ret == -1){
- error(0, errno, "sigaddset");
- exitstatus = EX_OSERR;
- goto failure;
- }
- ret = sigaddset(&new_action.sa_mask, SIGTERM);
- if(ret == -1){
- error(0, errno, "sigaddset");
- exitstatus = EX_OSERR;
- goto failure;
- }
+ sigaddset(&new_action.sa_mask, SIGINT);
+ sigaddset(&new_action.sa_mask, SIGHUP);
+ sigaddset(&new_action.sa_mask, SIGTERM);
ret = sigaction(SIGINT, NULL, &old_action);
if(ret == -1){
- error(0, errno, "sigaction");
- exitstatus = EX_OSERR;
- goto failure;
+ perror("sigaction");
+ free(prompt);
+ return EXIT_FAILURE;
}
if(old_action.sa_handler != SIG_IGN){
ret = sigaction(SIGINT, &new_action, NULL);
if(ret == -1){
- error(0, errno, "sigaction");
- exitstatus = EX_OSERR;
- goto failure;
+ perror("sigaction");
+ free(prompt);
+ return EXIT_FAILURE;
}
}
ret = sigaction(SIGHUP, NULL, &old_action);
if(ret == -1){
- error(0, errno, "sigaction");
- exitstatus = EX_OSERR;
- goto failure;
+ perror("sigaction");
+ free(prompt);
+ return EXIT_FAILURE;
}
if(old_action.sa_handler != SIG_IGN){
ret = sigaction(SIGHUP, &new_action, NULL);
if(ret == -1){
- error(0, errno, "sigaction");
- exitstatus = EX_OSERR;
- goto failure;
+ perror("sigaction");
+ free(prompt);
+ return EXIT_FAILURE;
}
}
ret = sigaction(SIGTERM, NULL, &old_action);
if(ret == -1){
- error(0, errno, "sigaction");
- exitstatus = EX_OSERR;
- goto failure;
+ perror("sigaction");
+ free(prompt);
+ return EXIT_FAILURE;
}
if(old_action.sa_handler != SIG_IGN){
ret = sigaction(SIGTERM, &new_action, NULL);
if(ret == -1){
- error(0, errno, "sigaction");
- exitstatus = EX_OSERR;
- goto failure;
+ perror("sigaction");
+ free(prompt);
+ return EXIT_FAILURE;
}
}
}
- if(interrupted_by_signal){
- goto failure;
- }
-
/* Fork off the splashy command to prompt for password */
- splashy_command_pid = fork();
- if(splashy_command_pid != 0 and interrupted_by_signal){
- goto failure;
- }
- if(splashy_command_pid == -1){
- error(0, errno, "fork");
- exitstatus = EX_OSERR;
- goto failure;
- }
- /* Child */
- if(splashy_command_pid == 0){
- if(not interrupted_by_signal){
+ pid_t splashy_command_pid = 0;
+ if(not interrupted_by_signal){
+ splashy_command_pid = fork();
+ if(splashy_command_pid == -1){
+ if(not interrupted_by_signal){
+ perror("fork");
+ }
+ return EXIT_FAILURE;
+ }
+ /* Child */
+ if(splashy_command_pid == 0){
const char splashy_command[] = "/sbin/splashy_update";
- execl(splashy_command, splashy_command, prompt, (char *)NULL);
- int e = errno;
- error(0, errno, "execl");
- switch(e){
- case EACCES:
- case ENOENT:
- case ENOEXEC:
- case EINVAL:
- _exit(EX_UNAVAILABLE);
- case ENAMETOOLONG:
- case E2BIG:
- case ENOMEM:
- case EFAULT:
- case EIO:
- case EMFILE:
- case ENFILE:
- case ETXTBSY:
- default:
- _exit(EX_OSERR);
- case ENOTDIR:
- case ELOOP:
- case EISDIR:
- case ELIBBAD:
- case EPERM:
- _exit(EX_OSFILE);
+ ret = execl(splashy_command, splashy_command, prompt,
+ (char *)NULL);
+ if(not interrupted_by_signal){
+ perror("execl");
}
+ free(prompt);
+ _exit(EXIT_FAILURE);
}
- free(prompt);
- _exit(EXIT_FAILURE);
}
/* Parent */
free(prompt);
- prompt = NULL;
-
- if(interrupted_by_signal){
- goto failure;
- }
/* Wait for command to complete */
- {
+ if(not interrupted_by_signal and splashy_command_pid != 0){
int status;
- do {
- ret = waitpid(splashy_command_pid, &status, 0);
- } while(ret == -1 and errno == EINTR
- and not interrupted_by_signal);
- if(interrupted_by_signal){
- goto failure;
- }
+ ret = waitpid(splashy_command_pid, &status, 0);
if(ret == -1){
- error(0, errno, "waitpid");
+ if(errno != EINTR){
+ perror("waitpid");
+ }
if(errno == ECHILD){
splashy_command_pid = 0;
}
} else {
/* The child process has exited */
splashy_command_pid = 0;
- if(WIFEXITED(status) and WEXITSTATUS(status) == 0){
+ if(not interrupted_by_signal and WIFEXITED(status)
+ and WEXITSTATUS(status)==0){
return EXIT_SUCCESS;
}
}
}
-
- failure:
-
- free(prompt);
-
- if(proc_dir != NULL){
- TEMP_FAILURE_RETRY(closedir(proc_dir));
- }
-
- if(splashy_command_pid != 0){
- TEMP_FAILURE_RETRY(kill(splashy_command_pid, SIGTERM));
-
- TEMP_FAILURE_RETRY(kill(splashy_pid, SIGTERM));
- sleep(2);
- while(TEMP_FAILURE_RETRY(kill(splashy_pid, 0)) == 0){
- TEMP_FAILURE_RETRY(kill(splashy_pid, SIGKILL));
- sleep(1);
- }
- pid_t new_splashy_pid = (pid_t)TEMP_FAILURE_RETRY(fork());
- if(new_splashy_pid == 0){
- /* Child; will become new splashy process */
-
- /* Make the effective user ID (root) the only user ID instead of
- the real user ID (_mandos) */
- ret = setuid(geteuid());
- if(ret == -1){
- error(0, errno, "setuid");
- }
-
- setsid();
- ret = chdir("/");
- if(ret == -1){
- error(0, errno, "chdir");
- }
-/* if(fork() != 0){ */
-/* _exit(EXIT_SUCCESS); */
-/* } */
- ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace stdout */
- if(ret == -1){
- error(0, errno, "dup2");
- _exit(EX_OSERR);
- }
-
- execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
- {
- int e = errno;
- error(0, errno, "execl");
- switch(e){
- case EACCES:
- case ENOENT:
- case ENOEXEC:
- default:
- _exit(EX_UNAVAILABLE);
- case ENAMETOOLONG:
- case E2BIG:
- case ENOMEM:
- _exit(EX_OSERR);
- case ENOTDIR:
- case ELOOP:
- _exit(EX_OSFILE);
- }
- }
- }
- }
-
- if(interrupted_by_signal){
- struct sigaction signal_action;
- sigemptyset(&signal_action.sa_mask);
- signal_action.sa_handler = SIG_DFL;
- ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
- &signal_action, NULL));
- if(ret == -1){
- error(0, errno, "sigaction");
- }
- do {
- ret = raise(signal_received);
- } while(ret != 0 and errno == EINTR);
- if(ret != 0){
- error(0, errno, "raise");
- abort();
- }
- TEMP_FAILURE_RETRY(pause());
- }
-
- return exitstatus;
+ kill(splashy_pid, SIGTERM);
+ if(interrupted_by_signal and splashy_command_pid != 0){
+ kill(splashy_command_pid, SIGTERM);
+ }
+ sleep(2);
+ while(kill(splashy_pid, 0) == 0){
+ kill(splashy_pid, SIGKILL);
+ sleep(1);
+ }
+ pid_t new_splashy_pid = fork();
+ if(new_splashy_pid == 0){
+ /* Child; will become new splashy process */
+
+ /* Make the effective user ID (root) the only user ID instead of
+ the real user ID (mandos) */
+ ret = setuid(geteuid());
+ if(ret == -1){
+ perror("setuid");
+ }
+
+ setsid();
+ ret = chdir("/");
+/* if(fork() != 0){ */
+/* _exit(EXIT_SUCCESS); */
+/* } */
+ ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
+ if(ret == -1){
+ perror("dup2");
+ _exit(EXIT_FAILURE);
+ }
+
+ execl("/sbin/splashy", "/sbin/splashy", "boot", (char *)NULL);
+ if(not interrupted_by_signal){
+ perror("execl");
+ }
+ _exit(EXIT_FAILURE);
+ }
+
+ return EXIT_FAILURE;
}
=== modified file 'plugins.d/splashy.xml'
--- plugins.d/splashy.xml 2009-01-04 21:54:55 +0000
+++ plugins.d/splashy.xml 2008-10-04 03:11:39 +0000
@@ -2,7 +2,7 @@
-
+
%common;
]>
@@ -32,7 +32,6 @@
2008
- 2009
Teddy Hogeborn
Björn Påhlsson
=== modified file 'plugins.d/usplash.c'
--- plugins.d/usplash.c 2010-09-26 18:32:58 +0000
+++ plugins.d/usplash.c 2008-11-11 16:07:18 +0000
@@ -1,9 +1,9 @@
/* -*- coding: utf-8 -*- */
/*
- * Usplash - Read a password from usplash and output it
+ * Passprompt - Read a password from usplash and output it
*
- * Copyright © 2008-2010 Teddy Hogeborn
- * Copyright © 2008-2010 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
@@ -19,10 +19,11 @@
* along with this program. If not, see
* .
*
- * Contact the authors at .
+ * Contact the authors at and
+ * .
*/
-#define _GNU_SOURCE /* asprintf(), TEMP_FAILURE_RETRY() */
+#define _GNU_SOURCE /* asprintf() */
#include /* sig_atomic_t, struct sigaction,
sigemptyset(), sigaddset(), SIGINT,
SIGHUP, SIGTERM, sigaction(),
@@ -31,290 +32,250 @@
#include /* open(), O_WRONLY, O_RDONLY */
#include /* and, or, not*/
#include /* errno, EINTR */
-#include
#include /* size_t, ssize_t, pid_t, DIR, struct
dirent */
#include /* NULL */
#include /* strlen(), memcmp() */
-#include /* asprintf()*/
+#include /* asprintf(), perror() */
#include /* close(), write(), readlink(),
read(), STDOUT_FILENO, sleep(),
fork(), setuid(), geteuid(),
setsid(), chdir(), dup2(),
STDERR_FILENO, execv() */
-#include /* free(), EXIT_FAILURE, realloc(),
- EXIT_SUCCESS, malloc(), _exit(),
- getenv() */
+#include /* free(), EXIT_FAILURE, strtoul(),
+ realloc(), EXIT_SUCCESS, malloc(),
+ _exit() */
+#include /* getenv() */
#include /* opendir(), readdir(), closedir() */
-#include /* intmax_t, strtoimax() */
#include /* struct stat, lstat(), S_ISLNK */
-#include /* EX_OSERR, EX_UNAVAILABLE */
-#include /* argz_count(), argz_extract() */
sig_atomic_t interrupted_by_signal = 0;
-int signal_received;
-const char usplash_name[] = "/sbin/usplash";
-static void termination_handler(int signum){
- if(interrupted_by_signal){
- return;
- }
+static void termination_handler(__attribute__((unused))int signum){
interrupted_by_signal = 1;
- signal_received = signum;
}
-static bool usplash_write(int *fifo_fd_r,
- const char *cmd, const char *arg){
+static bool usplash_write(const char *cmd, const char *arg){
/*
- * usplash_write(&fd, "TIMEOUT", "15") will write "TIMEOUT 15\0"
- * usplash_write(&fd, "PULSATE", NULL) will write "PULSATE\0"
+ * usplash_write("TIMEOUT", "15") will write "TIMEOUT 15\0"
+ * usplash_write("PULSATE", NULL) will write "PULSATE\0"
* SEE ALSO
* usplash_write(8)
*/
int ret;
- if(*fifo_fd_r == -1){
- ret = open("/dev/.initramfs/usplash_fifo", O_WRONLY);
- if(ret == -1){
+ int fifo_fd;
+ do{
+ fifo_fd = open("/dev/.initramfs/usplash_fifo", O_WRONLY);
+ if(fifo_fd == -1 and (errno != EINTR or interrupted_by_signal)){
return false;
}
- *fifo_fd_r = ret;
- }
+ }while(fifo_fd == -1);
const char *cmd_line;
size_t cmd_line_len;
char *cmd_line_alloc = NULL;
if(arg == NULL){
cmd_line = cmd;
- cmd_line_len = strlen(cmd) + 1;
- } else {
- do {
+ cmd_line_len = strlen(cmd);
+ }else{
+ do{
ret = asprintf(&cmd_line_alloc, "%s %s", cmd, arg);
- if(ret == -1){
+ if(ret == -1 and (errno != EINTR or interrupted_by_signal)){
int e = errno;
- TEMP_FAILURE_RETRY(close(*fifo_fd_r));
+ close(fifo_fd);
errno = e;
return false;
}
- } while(ret == -1);
+ }while(ret == -1);
cmd_line = cmd_line_alloc;
cmd_line_len = (size_t)ret + 1;
}
size_t written = 0;
- ssize_t sret = 0;
- while(written < cmd_line_len){
- sret = write(*fifo_fd_r, cmd_line + written,
- cmd_line_len - written);
- if(sret == -1){
- int e = errno;
- TEMP_FAILURE_RETRY(close(*fifo_fd_r));
- free(cmd_line_alloc);
- errno = e;
- return false;
+ while(not interrupted_by_signal and written < cmd_line_len){
+ ret = write(fifo_fd, cmd_line + written,
+ cmd_line_len - written);
+ if(ret == -1){
+ if(errno != EINTR or interrupted_by_signal){
+ int e = errno;
+ close(fifo_fd);
+ free(cmd_line_alloc);
+ errno = e;
+ return false;
+ } else {
+ continue;
+ }
}
- written += (size_t)sret;
+ written += (size_t)ret;
}
free(cmd_line_alloc);
-
+ do{
+ ret = close(fifo_fd);
+ if(ret == -1 and (errno != EINTR or interrupted_by_signal)){
+ return false;
+ }
+ }while(ret == -1);
+ if(interrupted_by_signal){
+ return false;
+ }
return true;
}
-/* Create prompt string */
-char *makeprompt(void){
- int ret = 0;
- char *prompt;
- const char *const cryptsource = getenv("cryptsource");
- const char *const crypttarget = getenv("crypttarget");
- const char prompt_start[] = "Enter passphrase to unlock the disk";
-
- if(cryptsource == NULL){
- if(crypttarget == NULL){
- ret = asprintf(&prompt, "%s: ", prompt_start);
- } else {
- ret = asprintf(&prompt, "%s (%s): ", prompt_start,
- crypttarget);
- }
- } else {
- if(crypttarget == NULL){
- ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
- } else {
- ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
- cryptsource, crypttarget);
- }
- }
- if(ret == -1){
- return NULL;
- }
- return prompt;
-}
-
-pid_t find_usplash(char **cmdline_r, size_t *cmdline_len_r){
- int ret = 0;
- ssize_t sret = 0;
+int main(__attribute__((unused))int argc,
+ __attribute__((unused))char **argv){
+ int ret = 0;
+ ssize_t sret;
+ bool an_error_occured = false;
+
+ /* Create prompt string */
+ char *prompt = NULL;
+ {
+ const char *const cryptsource = getenv("cryptsource");
+ const char *const crypttarget = getenv("crypttarget");
+ const char prompt_start[] = "Enter passphrase to unlock the disk";
+
+ if(cryptsource == NULL){
+ if(crypttarget == NULL){
+ ret = asprintf(&prompt, "%s: ", prompt_start);
+ } else {
+ ret = asprintf(&prompt, "%s (%s): ", prompt_start,
+ crypttarget);
+ }
+ } else {
+ if(crypttarget == NULL){
+ ret = asprintf(&prompt, "%s %s: ", prompt_start, cryptsource);
+ } else {
+ ret = asprintf(&prompt, "%s %s (%s): ", prompt_start,
+ cryptsource, crypttarget);
+ }
+ }
+ if(ret == -1){
+ return EXIT_FAILURE;
+ }
+ }
+
+ /* Find usplash process */
+ pid_t usplash_pid = 0;
char *cmdline = NULL;
size_t cmdline_len = 0;
- DIR *proc_dir = opendir("/proc");
- if(proc_dir == NULL){
- error(0, errno, "opendir");
- return -1;
- }
- errno = 0;
- for(struct dirent *proc_ent = readdir(proc_dir);
- proc_ent != NULL;
- proc_ent = readdir(proc_dir)){
- pid_t pid;
- {
- intmax_t tmpmax;
- char *tmp;
- tmpmax = strtoimax(proc_ent->d_name, &tmp, 10);
- if(errno != 0 or tmp == proc_ent->d_name or *tmp != '\0'
- or tmpmax != (pid_t)tmpmax){
+ const char usplash_name[] = "/sbin/usplash";
+ {
+ DIR *proc_dir = opendir("/proc");
+ if(proc_dir == NULL){
+ free(prompt);
+ perror("opendir");
+ return EXIT_FAILURE;
+ }
+ for(struct dirent *proc_ent = readdir(proc_dir);
+ proc_ent != NULL;
+ proc_ent = readdir(proc_dir)){
+ pid_t pid = (pid_t) strtoul(proc_ent->d_name, NULL, 10);
+ if(pid == 0){
/* Not a process */
- errno = 0;
- continue;
- }
- pid = (pid_t)tmpmax;
- }
- /* Find the executable name by doing readlink() on the
- /proc//exe link */
- char exe_target[sizeof(usplash_name)];
- {
- /* create file name string */
- char *exe_link;
- ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
- if(ret == -1){
- error(0, errno, "asprintf");
- goto fail_find_usplash;
- }
-
- /* Check that it refers to a symlink owned by root:root */
- struct stat exe_stat;
- ret = lstat(exe_link, &exe_stat);
- if(ret == -1){
- if(errno == ENOENT){
- free(exe_link);
- continue;
- }
- error(0, errno, "lstat");
- free(exe_link);
- goto fail_find_usplash;
- }
- if(not S_ISLNK(exe_stat.st_mode)
- or exe_stat.st_uid != 0
- or exe_stat.st_gid != 0){
- free(exe_link);
- continue;
- }
-
- sret = readlink(exe_link, exe_target, sizeof(exe_target));
- free(exe_link);
- }
- /* Compare executable name */
- if((sret != ((ssize_t)sizeof(exe_target)-1))
- or (memcmp(usplash_name, exe_target,
- sizeof(exe_target)-1) != 0)){
- /* Not it */
- continue;
- }
- /* Found usplash */
- /* Read and save the command line of usplash in "cmdline" */
- {
- /* Open /proc//cmdline */
- int cl_fd;
+ continue;
+ }
+ /* Find the executable name by doing readlink() on the
+ /proc//exe link */
+ char exe_target[sizeof(usplash_name)];
{
- char *cmdline_filename;
- ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
- proc_ent->d_name);
- if(ret == -1){
- error(0, errno, "asprintf");
- goto fail_find_usplash;
- }
- cl_fd = open(cmdline_filename, O_RDONLY);
- free(cmdline_filename);
- if(cl_fd == -1){
- error(0, errno, "open");
- goto fail_find_usplash;
+ /* create file name string */
+ char *exe_link;
+ ret = asprintf(&exe_link, "/proc/%s/exe", proc_ent->d_name);
+ if(ret == -1){
+ perror("asprintf");
+ free(prompt);
+ closedir(proc_dir);
+ return EXIT_FAILURE;
+ }
+
+ /* Check that it refers to a symlink owned by root:root */
+ struct stat exe_stat;
+ ret = lstat(exe_link, &exe_stat);
+ if(ret == -1){
+ perror("lstat");
+ free(exe_link);
+ free(prompt);
+ closedir(proc_dir);
+ return EXIT_FAILURE;
+ }
+ if(not S_ISLNK(exe_stat.st_mode)
+ or exe_stat.st_uid != 0
+ or exe_stat.st_gid != 0){
+ free(exe_link);
+ continue;
+ }
+
+ sret = readlink(exe_link, exe_target, sizeof(exe_target));
+ free(exe_link);
+ if(sret == -1){
+ continue;
}
}
- size_t cmdline_allocated = 0;
- char *tmp;
- const size_t blocksize = 1024;
- do {
- /* Allocate more space? */
- if(cmdline_len + blocksize > cmdline_allocated){
- tmp = realloc(cmdline, cmdline_allocated + blocksize);
- if(tmp == NULL){
- error(0, errno, "realloc");
- close(cl_fd);
- goto fail_find_usplash;
+ if((sret == ((ssize_t)sizeof(exe_target)-1))
+ and (memcmp(usplash_name, exe_target,
+ sizeof(exe_target)-1) == 0)){
+ usplash_pid = pid;
+ /* Read and save the command line of usplash in "cmdline" */
+ {
+ /* Open /proc//cmdline */
+ int cl_fd;
+ {
+ char *cmdline_filename;
+ ret = asprintf(&cmdline_filename, "/proc/%s/cmdline",
+ proc_ent->d_name);
+ if(ret == -1){
+ perror("asprintf");
+ free(prompt);
+ closedir(proc_dir);
+ return EXIT_FAILURE;
+ }
+ cl_fd = open(cmdline_filename, O_RDONLY);
+ if(cl_fd == -1){
+ perror("open");
+ free(cmdline_filename);
+ free(prompt);
+ closedir(proc_dir);
+ return EXIT_FAILURE;
+ }
+ free(cmdline_filename);
}
- cmdline = tmp;
- cmdline_allocated += blocksize;
- }
- /* Read data */
- sret = read(cl_fd, cmdline + cmdline_len,
- cmdline_allocated - cmdline_len);
- if(sret == -1){
- error(0, errno, "read");
+ size_t cmdline_allocated = 0;
+ char *tmp;
+ const size_t blocksize = 1024;
+ do{
+ if(cmdline_len + blocksize > cmdline_allocated){
+ tmp = realloc(cmdline, cmdline_allocated + blocksize);
+ if(tmp == NULL){
+ perror("realloc");
+ free(cmdline);
+ free(prompt);
+ closedir(proc_dir);
+ return EXIT_FAILURE;
+ }
+ cmdline = tmp;
+ cmdline_allocated += blocksize;
+ }
+ sret = read(cl_fd, cmdline + cmdline_len,
+ cmdline_allocated - cmdline_len);
+ if(sret == -1){
+ perror("read");
+ free(cmdline);
+ free(prompt);
+ closedir(proc_dir);
+ return EXIT_FAILURE;
+ }
+ cmdline_len += (size_t)sret;
+ } while(sret != 0);
close(cl_fd);
- goto fail_find_usplash;
}
- cmdline_len += (size_t)sret;
- } while(sret != 0);
- ret = close(cl_fd);
- if(ret == -1){
- error(0, errno, "close");
- goto fail_find_usplash;
+ break;
}
}
- /* Close directory */
- ret = closedir(proc_dir);
- if(ret == -1){
- error(0, errno, "closedir");
- goto fail_find_usplash;
- }
- /* Success */
- *cmdline_r = cmdline;
- *cmdline_len_r = cmdline_len;
- return pid;
- }
-
- fail_find_usplash:
-
- free(cmdline);
- if(proc_dir != NULL){
- int e = errno;
closedir(proc_dir);
- errno = e;
- }
- return 0;
-}
-
-int main(__attribute__((unused))int argc,
- __attribute__((unused))char **argv){
- int ret = 0;
- ssize_t sret;
- int fifo_fd = -1;
- int outfifo_fd = -1;
- char *buf = NULL;
- size_t buf_len = 0;
- pid_t usplash_pid = -1;
- bool usplash_accessed = false;
- int status = EXIT_FAILURE; /* Default failure exit status */
-
- char *prompt = makeprompt();
- if(prompt == NULL){
- status = EX_OSERR;
- goto failure;
- }
-
- /* Find usplash process */
- char *cmdline = NULL;
- size_t cmdline_len = 0;
- usplash_pid = find_usplash(&cmdline, &cmdline_len);
+ }
if(usplash_pid == 0){
- status = EX_UNAVAILABLE;
- goto failure;
+ free(prompt);
+ return EXIT_FAILURE;
}
/* Set up the signal handler */
@@ -323,259 +284,194 @@
new_action = { .sa_handler = termination_handler,
.sa_flags = 0 };
sigemptyset(&new_action.sa_mask);
- ret = sigaddset(&new_action.sa_mask, SIGINT);
- if(ret == -1){
- error(0, errno, "sigaddset");
- status = EX_OSERR;
- goto failure;
- }
- ret = sigaddset(&new_action.sa_mask, SIGHUP);
- if(ret == -1){
- error(0, errno, "sigaddset");
- status = EX_OSERR;
- goto failure;
- }
- ret = sigaddset(&new_action.sa_mask, SIGTERM);
- if(ret == -1){
- error(0, errno, "sigaddset");
- status = EX_OSERR;
- goto failure;
- }
+ sigaddset(&new_action.sa_mask, SIGINT);
+ sigaddset(&new_action.sa_mask, SIGHUP);
+ sigaddset(&new_action.sa_mask, SIGTERM);
ret = sigaction(SIGINT, NULL, &old_action);
if(ret == -1){
- if(errno != EINTR){
- error(0, errno, "sigaction");
- status = EX_OSERR;
- }
- goto failure;
+ perror("sigaction");
+ free(prompt);
+ return EXIT_FAILURE;
}
if(old_action.sa_handler != SIG_IGN){
ret = sigaction(SIGINT, &new_action, NULL);
if(ret == -1){
- if(errno != EINTR){
- error(0, errno, "sigaction");
- status = EX_OSERR;
- }
- goto failure;
+ perror("sigaction");
+ free(prompt);
+ return EXIT_FAILURE;
}
}
ret = sigaction(SIGHUP, NULL, &old_action);
if(ret == -1){
- if(errno != EINTR){
- error(0, errno, "sigaction");
- status = EX_OSERR;
- }
- goto failure;
+ perror("sigaction");
+ free(prompt);
+ return EXIT_FAILURE;
}
if(old_action.sa_handler != SIG_IGN){
ret = sigaction(SIGHUP, &new_action, NULL);
if(ret == -1){
- if(errno != EINTR){
- error(0, errno, "sigaction");
- status = EX_OSERR;
- }
- goto failure;
+ perror("sigaction");
+ free(prompt);
+ return EXIT_FAILURE;
}
}
ret = sigaction(SIGTERM, NULL, &old_action);
if(ret == -1){
- if(errno != EINTR){
- error(0, errno, "sigaction");
- status = EX_OSERR;
- }
- goto failure;
+ perror("sigaction");
+ free(prompt);
+ return EXIT_FAILURE;
}
if(old_action.sa_handler != SIG_IGN){
ret = sigaction(SIGTERM, &new_action, NULL);
if(ret == -1){
- if(errno != EINTR){
- error(0, errno, "sigaction");
- status = EX_OSERR;
- }
- goto failure;
+ perror("sigaction");
+ free(prompt);
+ return EXIT_FAILURE;
}
}
}
- usplash_accessed = true;
/* Write command to FIFO */
- if(not usplash_write(&fifo_fd, "TIMEOUT", "0")){
- if(errno != EINTR){
- error(0, errno, "usplash_write");
- status = EX_OSERR;
- }
- goto failure;
- }
-
- if(interrupted_by_signal){
- goto failure;
- }
-
- if(not usplash_write(&fifo_fd, "INPUTQUIET", prompt)){
- if(errno != EINTR){
- error(0, errno, "usplash_write");
- status = EX_OSERR;
- }
- goto failure;
- }
-
- if(interrupted_by_signal){
- goto failure;
- }
-
+ if(not interrupted_by_signal){
+ if(not usplash_write("TIMEOUT", "0")
+ and (errno != EINTR)){
+ perror("usplash_write");
+ an_error_occured = true;
+ }
+ }
+ if(not interrupted_by_signal and not an_error_occured){
+ if(not usplash_write("INPUTQUIET", prompt)
+ and (errno != EINTR)){
+ perror("usplash_write");
+ an_error_occured = true;
+ }
+ }
free(prompt);
- prompt = NULL;
-
- /* Read reply from usplash */
- /* Open FIFO */
- outfifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
- if(outfifo_fd == -1){
- if(errno != EINTR){
- error(0, errno, "open");
- status = EX_OSERR;
- }
- goto failure;
- }
-
- if(interrupted_by_signal){
- goto failure;
- }
-
- /* Read from FIFO */
- size_t buf_allocated = 0;
- const size_t blocksize = 1024;
- do {
- /* Allocate more space */
- if(buf_len + blocksize > buf_allocated){
- char *tmp = realloc(buf, buf_allocated + blocksize);
+
+ /* This is not really a loop; while() is used to be able to "break"
+ out of it; those breaks are marked "Big" */
+ while(not interrupted_by_signal and not an_error_occured){
+ char *buf = NULL;
+ size_t buf_len = 0;
+
+ /* Open FIFO */
+ int fifo_fd;
+ do{
+ fifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY);
+ if(fifo_fd == -1){
+ if(errno != EINTR){
+ perror("open");
+ an_error_occured = true;
+ break;
+ }
+ if(interrupted_by_signal){
+ break;
+ }
+ }
+ }while(fifo_fd == -1);
+ if(interrupted_by_signal or an_error_occured){
+ break; /* Big */
+ }
+
+ /* Read from FIFO */
+ size_t buf_allocated = 0;
+ const size_t blocksize = 1024;
+ do{
+ if(buf_len + blocksize > buf_allocated){
+ char *tmp = realloc(buf, buf_allocated + blocksize);
+ if(tmp == NULL){
+ perror("realloc");
+ an_error_occured = true;
+ break;
+ }
+ buf = tmp;
+ buf_allocated += blocksize;
+ }
+ do{
+ sret = read(fifo_fd, buf + buf_len, buf_allocated - buf_len);
+ if(sret == -1){
+ if(errno != EINTR){
+ perror("read");
+ an_error_occured = true;
+ break;
+ }
+ if(interrupted_by_signal){
+ break;
+ }
+ }
+ }while(sret == -1);
+ if(interrupted_by_signal or an_error_occured){
+ break;
+ }
+
+ buf_len += (size_t)sret;
+ }while(sret != 0);
+ close(fifo_fd);
+ if(interrupted_by_signal or an_error_occured){
+ break; /* Big */
+ }
+
+ if(not usplash_write("TIMEOUT", "15")
+ and (errno != EINTR)){
+ perror("usplash_write");
+ an_error_occured = true;
+ }
+ if(interrupted_by_signal or an_error_occured){
+ break; /* Big */
+ }
+
+ /* Print password to stdout */
+ size_t written = 0;
+ while(written < buf_len){
+ do{
+ sret = write(STDOUT_FILENO, buf + written, buf_len - written);
+ if(sret == -1){
+ if(errno != EINTR){
+ perror("write");
+ an_error_occured = true;
+ break;
+ }
+ if(interrupted_by_signal){
+ break;
+ }
+ }
+ }while(sret == -1);
+ if(interrupted_by_signal or an_error_occured){
+ break;
+ }
+ written += (size_t)sret;
+ }
+ free(buf);
+ if(not interrupted_by_signal and not an_error_occured){
+ free(cmdline);
+ return EXIT_SUCCESS;
+ }
+ break; /* Big */
+ } /* end of non-loop while() */
+
+ /* If we got here, an error or interrupt must have happened */
+
+ /* Create argc and argv for new usplash*/
+ int cmdline_argc = 0;
+ char **cmdline_argv = malloc(sizeof(char *));
+ {
+ size_t position = 0;
+ while(position < cmdline_len){
+ char **tmp = realloc(cmdline_argv,
+ (sizeof(char *)
+ * (size_t)(cmdline_argc + 2)));
if(tmp == NULL){
- if(errno != EINTR){
- error(0, errno, "realloc");
- status = EX_OSERR;
- }
- goto failure;
- }
- buf = tmp;
- buf_allocated += blocksize;
- }
- sret = read(outfifo_fd, buf + buf_len,
- buf_allocated - buf_len);
- if(sret == -1){
- if(errno != EINTR){
- error(0, errno, "read");
- status = EX_OSERR;
- }
- TEMP_FAILURE_RETRY(close(outfifo_fd));
- goto failure;
- }
- if(interrupted_by_signal){
- break;
- }
-
- buf_len += (size_t)sret;
- } while(sret != 0);
- ret = close(outfifo_fd);
- if(ret == -1){
- if(errno != EINTR){
- error(0, errno, "close");
- status = EX_OSERR;
- }
- goto failure;
- }
- outfifo_fd = -1;
-
- if(interrupted_by_signal){
- goto failure;
- }
-
- if(not usplash_write(&fifo_fd, "TIMEOUT", "15")){
- if(errno != EINTR){
- error(0, errno, "usplash_write");
- status = EX_OSERR;
- }
- goto failure;
- }
-
- if(interrupted_by_signal){
- goto failure;
- }
-
- ret = close(fifo_fd);
- if(ret == -1){
- if(errno != EINTR){
- error(0, errno, "close");
- status = EX_OSERR;
- }
- goto failure;
- }
- fifo_fd = -1;
-
- /* Print password to stdout */
- size_t written = 0;
- while(written < buf_len){
- do {
- sret = write(STDOUT_FILENO, buf + written, buf_len - written);
- if(sret == -1){
- if(errno != EINTR){
- error(0, errno, "write");
- status = EX_OSERR;
- }
- goto failure;
- }
- } while(sret == -1);
-
- if(interrupted_by_signal){
- goto failure;
- }
- written += (size_t)sret;
- }
- free(buf);
- buf = NULL;
-
- if(interrupted_by_signal){
- goto failure;
- }
-
- free(cmdline);
- return EXIT_SUCCESS;
-
- failure:
-
- free(buf);
-
- free(prompt);
-
- /* If usplash was never accessed, we can stop now */
- if(not usplash_accessed){
- return status;
- }
-
- /* Close FIFO */
- if(fifo_fd != -1){
- ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
- if(ret == -1 and errno != EINTR){
- error(0, errno, "close");
- }
- fifo_fd = -1;
- }
-
- /* Close output FIFO */
- if(outfifo_fd != -1){
- ret = (int)TEMP_FAILURE_RETRY(close(outfifo_fd));
- if(ret == -1){
- error(0, errno, "close");
- }
- }
-
- /* Create argv for new usplash*/
- char **cmdline_argv = malloc((argz_count(cmdline, cmdline_len) + 1)
- * sizeof(char *)); /* Count args */
- if(cmdline_argv == NULL){
- error(0, errno, "malloc");
- return status;
- }
- argz_extract(cmdline, cmdline_len, cmdline_argv); /* Create argv */
-
+ perror("realloc");
+ free(cmdline_argv);
+ return EXIT_FAILURE;
+ }
+ cmdline_argv = tmp;
+ cmdline_argv[cmdline_argc] = cmdline + position;
+ cmdline_argc++;
+ position += strlen(cmdline + position) + 1;
+ }
+ cmdline_argv[cmdline_argc] = NULL;
+ }
/* Kill old usplash */
kill(usplash_pid, SIGTERM);
sleep(2);
@@ -583,76 +479,43 @@
kill(usplash_pid, SIGKILL);
sleep(1);
}
-
pid_t new_usplash_pid = fork();
if(new_usplash_pid == 0){
/* Child; will become new usplash process */
/* Make the effective user ID (root) the only user ID instead of
- the real user ID (_mandos) */
+ the real user ID (mandos) */
ret = setuid(geteuid());
if(ret == -1){
- error(0, errno, "setuid");
+ perror("setuid");
}
setsid();
ret = chdir("/");
- if(ret == -1){
- error(0, errno, "chdir");
- _exit(EX_OSERR);
- }
/* if(fork() != 0){ */
/* _exit(EXIT_SUCCESS); */
/* } */
ret = dup2(STDERR_FILENO, STDOUT_FILENO); /* replace our stdout */
if(ret == -1){
- error(0, errno, "dup2");
- _exit(EX_OSERR);
+ perror("dup2");
+ _exit(EXIT_FAILURE);
}
execv(usplash_name, cmdline_argv);
if(not interrupted_by_signal){
- error(0, errno, "execv");
+ perror("execv");
}
free(cmdline);
free(cmdline_argv);
- _exit(EX_OSERR);
+ _exit(EXIT_FAILURE);
}
free(cmdline);
free(cmdline_argv);
sleep(2);
- if(not usplash_write(&fifo_fd, "PULSATE", NULL)){
- if(errno != EINTR){
- error(0, errno, "usplash_write");
- }
- }
-
- /* Close FIFO (again) */
- if(fifo_fd != -1){
- ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd));
- if(ret == -1 and errno != EINTR){
- error(0, errno, "close");
- }
- fifo_fd = -1;
- }
-
- if(interrupted_by_signal){
- struct sigaction signal_action = { .sa_handler = SIG_DFL };
- sigemptyset(&signal_action.sa_mask);
- ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
- &signal_action, NULL));
- if(ret == -1){
- error(0, errno, "sigaction");
- }
- do {
- ret = raise(signal_received);
- } while(ret != 0 and errno == EINTR);
- if(ret != 0){
- error(0, errno, "raise");
- abort();
- }
- TEMP_FAILURE_RETRY(pause());
- }
-
- return status;
+ if(not usplash_write("PULSATE", NULL)
+ and (errno != EINTR)){
+ perror("usplash_write");
+ }
+
+ return EXIT_FAILURE;
}
=== modified file 'plugins.d/usplash.xml'
--- plugins.d/usplash.xml 2009-01-04 21:54:55 +0000
+++ plugins.d/usplash.xml 2008-10-04 03:11:39 +0000
@@ -2,7 +2,7 @@
-
+
%common;
]>
@@ -32,7 +32,6 @@
2008
- 2009
Teddy Hogeborn
Björn Påhlsson