=== modified file '.bzrignore' --- .bzrignore 2008-09-06 16:33:54 +0000 +++ .bzrignore 2008-09-26 05:04:15 +0000 @@ -1,8 +1,12 @@ *.5 *.8 *.8mandos +confdir +debian/po/messages.mo +debian/po/templates.pot +keydir plugin-runner +plugins.d/mandos-client plugins.d/password-prompt -plugins.d/mandos-client -confdir -keydir +plugins.d/splashy +plugins.d/usplash === modified file 'Makefile' --- Makefile 2008-09-19 16:29:40 +0000 +++ Makefile 2008-09-26 19:47:21 +0000 @@ -55,7 +55,8 @@ # DocBook-to-man post-processing to fix a '\n' escape bug MANPOST=sed --in-place --expression='s,\\\\en,\\en,g;s,\\n,\\en,g' -PLUGINS=plugins.d/password-prompt plugins.d/mandos-client +PLUGINS=plugins.d/password-prompt plugins.d/mandos-client \ + plugins.d/usplash plugins.d/splashy plugins.d/askpass-fifo PROGS=plugin-runner $(PLUGINS) DOCS=mandos.8 plugin-runner.8mandos mandos-keygen.8 \ plugins.d/mandos-client.8mandos \ @@ -151,7 +152,9 @@ $(DESTDIR)/etc/init.d/mandos install --mode=u=rw,go=r default-mandos \ $(DESTDIR)/etc/default/mandos - if [ -z $(DESTDIR) ]; then update-rc.d mandos defaults; fi + if [ -z $(DESTDIR) ]; then \ + update-rc.d mandos defaults 25 15;\ + fi gzip --best --to-stdout mandos.8 \ > $(MANDIR)/man8/mandos.8.gz gzip --best --to-stdout mandos.conf.5 \ @@ -165,9 +168,7 @@ $(PREFIX)/lib/mandos/plugins.d if [ "$(CONFDIR)" != "$(PREFIX)/lib/mandos" ]; then \ install --mode=u=rwx \ - --directory "$(CONFDIR)/plugins.d" && \ - install --mode=u=rw,go=r etc-plugins.d-README \ - $(CONFDIR)/plugins.d/README ; \ + --directory "$(CONFDIR)/plugins.d"; \ fi install --mode=u=rwx,go=rx \ --target-directory=$(PREFIX)/lib/mandos plugin-runner @@ -179,9 +180,15 @@ install --mode=u=rwxs,go=rx \ --target-directory=$(PREFIX)/lib/mandos/plugins.d \ plugins.d/mandos-client - install --mode=u=rwx,go=rx \ + install --mode=u=rwxs,go=rx \ --target-directory=$(PREFIX)/lib/mandos/plugins.d \ plugins.d/usplash + install --mode=u=rwxs,go=rx \ + --target-directory=$(PREFIX)/lib/mandos/plugins.d \ + plugins.d/splashy + install --mode=u=rwxs,go=rx \ + --target-directory=$(PREFIX)/lib/mandos/plugins.d \ + plugins.d/askpass-fifo install initramfs-tools-hook \ $(INITRAMFSTOOLS)/hooks/mandos install --mode=u=rw,go=r initramfs-tools-hook-conf \ @@ -224,6 +231,7 @@ $(PREFIX)/lib/mandos/plugins.d/password-prompt \ $(PREFIX)/lib/mandos/plugins.d/mandos-client \ $(PREFIX)/lib/mandos/plugins.d/usplash \ + $(PREFIX)/lib/mandos/plugins.d/splashy \ $(INITRAMFSTOOLS)/hooks/mandos \ $(INITRAMFSTOOLS)/conf-hooks.d/mandos \ $(INITRAMFSTOOLS)/scripts/local-top/mandos \ === modified file 'TODO' --- TODO 2008-09-19 12:02:03 +0000 +++ TODO 2008-09-21 14:05:44 +0000 @@ -1,8 +1,6 @@ -*- org -*- -* plugin-runner -** TODO Man page for plugin-runner.conf.5 - link to plugin-runner.8 +* DONE plugin-runner * mandos-client ** TODO [#B] Temporarily lower kernel log level @@ -41,18 +39,11 @@ * Installer ** Client-side -*** TODO Update initrd.img after installation - This seems to use some kind of "trigger" system - [[file:/usr/share/doc/dpkg/triggers.txt.gz]] - dpkg-trigger(1), deb-triggers(5) *** mandos-keygen -**** TODO [#A] Ask for password twice for confirmation -**** TODO "--passfile" option +**** TODO "--secfile" option Using the "secfile" option instead of "secret" **** TODO [#B] "--test" option For testing decryption before rebooting. -** Server-side -*** TODO [#A] Create mandos user and group for server * [#A] Package @@ -63,14 +54,11 @@ ** TODO /etc/bash_completion.d/mandos From XML sources directly? ** TODO unperish -** DONE bzr-builddeb -** DONE mandos user/group creation :test: -** DONE Key creation in postinst :test: * TODO Web site ** DONE http://www.fukt.bsnet.se/mandos Redirects to the wiki page -** TODO http://wiki.fukt.bsnet.se/wiki/Mandos +** DONE http://wiki.fukt.bsnet.se/wiki/Mandos * Mailing list ** DONE mandos-dev === modified file 'clients.conf' --- clients.conf 2008-08-27 01:18:25 +0000 +++ clients.conf 2008-09-21 13:42:34 +0000 @@ -55,7 +55,7 @@ ;fingerprint = 3e393aeaefb84c7e89e2f547b3a107558fca3a27 ; ;# If "secret" is not specified, a file can be read for the data. -;;secfile = /etc/mandos/bar-secret.txt.asc +;secfile = /etc/mandos/bar-secret.bin ; ;# An IP address for host is also fine, if the checker accepts it. ;host = 192.0.2.3 === modified file 'debian/control' --- debian/control 2008-09-19 17:30:43 +0000 +++ debian/control 2008-09-21 13:42:34 +0000 @@ -3,15 +3,16 @@ Priority: extra Maintainer: Mandos Maintainers Build-Depends: debhelper (>= 7), docbook-xsl, libavahi-core-dev, - libgpgme11-dev, libgnutls-dev, xsltproc + libgpgme11-dev, libgnutls-dev, xsltproc, po-debconf, + pkg-config Standards-Version: 3.8.0 Vcs-Bzr: ftp://anonymous@ftp.fukt.bsnet.se/pub/mandos/latest Homepage: http://www.fukt.bsnet.se/mandos Package: mandos Architecture: all -Depends: python (>=2.5), python-gnutls, python-dbus, python-avahi, - avahi-daemon, gnupg (< 2), adduser +Depends: ${misc:Depends}, python (>=2.5), python-gnutls, python-dbus, + 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 @@ -30,7 +31,7 @@ Package: mandos-client Architecture: any -Depends: ${shlibs:Depends}, adduser +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/mandos-client.README.Debian' --- debian/mandos-client.README.Debian 2008-09-19 00:00:51 +0000 +++ debian/mandos-client.README.Debian 2008-09-19 20:54:58 +0000 @@ -8,8 +8,16 @@ change the line there. If this file is changed, it will be necessary to update the initrd image by doing "update-initramfs -k all -u". +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 + 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. + + -- Teddy Hogeborn , Fri, 19 Sep 2008 22:50:16 +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.lintian-overrides' --- debian/mandos-client.lintian-overrides 2008-09-17 00:34:09 +0000 +++ debian/mandos-client.lintian-overrides 2008-09-26 19:47:21 +0000 @@ -1,4 +1,7 @@ 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 mandos-client binary: non-standard-dir-perm etc/keys/mandos/ 0700 != 0755 mandos-client binary: setuid-binary usr/lib/mandos/plugins.d/mandos-client 4755 root/root +mandos-client binary: setuid-binary usr/lib/mandos/plugins.d/askpass-fifo 4755 root/root +mandos-client binary: setuid-binary usr/lib/mandos/plugins.d/splashy 4755 root/root +mandos-client binary: setuid-binary usr/lib/mandos/plugins.d/usplash 4755 root/root mandos-client binary: non-standard-dir-perm usr/lib/mandos/plugins.d/ 0700 != 0755 === modified file 'debian/mandos-client.postinst' --- debian/mandos-client.postinst 2008-09-19 17:30:43 +0000 +++ debian/mandos-client.postinst 2008-09-26 04:54:35 +0000 @@ -29,7 +29,7 @@ add_mandos_user(){ if ! getent passwd mandos >/dev/null; then adduser --disabled-password --quiet --system \ - --home /var/run/mandos --no-create-home \ + --home /nonexistent --no-create-home \ --gecos "Mandos password system" --group mandos fi } === modified file 'debian/mandos-client.postrm' --- debian/mandos-client.postrm 2008-09-19 17:30:43 +0000 +++ debian/mandos-client.postrm 2008-09-19 20:54:58 +0000 @@ -41,10 +41,10 @@ ;; purge) - shred --remove /etc/keys/mandos/seckey.txt || : + shred --remove /etc/keys/mandos/seckey.txt 2>/dev/null || : rm --force /etc/mandos/plugin-runner.conf \ /etc/keys/mandos/pubkey.txt \ - /etc/keys/mandos/seckey.txt + /etc/keys/mandos/seckey.txt 2>/dev/null ;; upgrade|failed-upgrade|disappear|abort-install|abort-upgrade) ;; === 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. === added file 'debian/mandos.README.Debian' --- debian/mandos.README.Debian 1970-01-01 00:00:00 +0000 +++ debian/mandos.README.Debian 2008-09-21 04:22:50 +0000 @@ -0,0 +1,7 @@ +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 "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.postinst' --- debian/mandos.postinst 2008-09-19 17:30:43 +0000 +++ debian/mandos.postinst 2008-09-26 04:54:35 +0000 @@ -21,7 +21,7 @@ configure) if ! getent passwd mandos >/dev/null; then adduser --disabled-password --quiet --system \ - --home /var/run/mandos --no-create-home \ + --home /nonexistent --no-create-home \ --gecos "Mandos password system" --group mandos fi ;; === added file 'debian/mandos.prerm' --- debian/mandos.prerm 1970-01-01 00:00:00 +0000 +++ debian/mandos.prerm 2008-09-21 13:42:34 +0000 @@ -0,0 +1,38 @@ +#! /bin/sh +# prerm script for mandos +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `upgrade' +# * `failed-upgrade' +# * `remove' `in-favour' +# * `deconfigure' `in-favour' +# `removing' +# +# for details, see /usr/share/doc/packaging-manual/ + +case "$1" in + remove|deconfigure) + if [ -x /etc/init.d/mandos ]; then + if [ -x /usr/sbin/invoke-rc.d ]; then + invoke-rc.d mandos stop + else + /etc/init.d/mandos stop + fi + fi + ;; + upgrade|failed-upgrade) + ;; + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 0 + ;; +esac + +#DEBHELPER# + +exit 0 === 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 directory 'debian/po' === 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 2008-09-19 13:50:22 +0000 +++ debian/rules 2008-09-21 12:04:02 +0000 @@ -38,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: @@ -47,7 +48,8 @@ dh_installdirs --indep $(MAKE) DESTDIR=$(CURDIR)/debian/mandos install-server dh_lintian - dh_installinit --onlyscripts --no-start + dh_installinit --onlyscripts --no-start \ + --update-rcd-params="defaults 25 15" dh_install --indep install-arch: @@ -64,7 +66,7 @@ dh_testroot dh_installchangelogs dh_installdocs -# dh_installdebconf + dh_installdebconf dh_link dh_strip dh_compress === removed file 'etc-plugins.d-README' --- etc-plugins.d-README 2008-09-06 16:11:50 +0000 +++ etc-plugins.d-README 1970-01-01 00:00:00 +0000 @@ -1,5 +0,0 @@ -Any plugins found here 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 === modified file 'init.d-mandos' --- init.d-mandos 2008-09-05 16:24:33 +0000 +++ init.d-mandos 2008-09-21 12:04:02 +0000 @@ -1,7 +1,7 @@ #! /bin/sh ### BEGIN INIT INFO # Provides: mandos -# Required-Start: $remote_fs +# Required-Start: $remote_fs avahi-daemon # Required-Stop: $remote_fs # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 === modified file 'mandos' --- mandos 2008-09-05 18:37:28 +0000 +++ mandos 2008-09-19 20:42:17 +0000 @@ -11,7 +11,7 @@ # and some lines in "main". # # Everything else is -# Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson +# Copyright © 2008 Teddy Hogeborn & Björn Påhlsson # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by === modified file 'mandos-keygen' --- mandos-keygen 2008-09-19 18:08:19 +0000 +++ mandos-keygen 2008-09-21 14:05:44 +0000 @@ -2,7 +2,7 @@ # # Mandos key generator - create a new OpenPGP key for a Mandos client # -# Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson +# Copyright © 2008 Teddy Hogeborn & 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 @@ -40,8 +40,8 @@ fi # Parse options -TEMP=`getopt --options vhd:t:l:n:e:c:x:f \ - --longoptions version,help,password,dir:,type:,length:,subtype:,sublength:,name:,email:,comment:,expire:,force \ +TEMP=`getopt --options vhpF:d:t:l:s:L:n:e:c:x:f \ + --longoptions version,help,password,passfile:,dir:,type:,length:,subtype:,sublength:,name:,email:,comment:,expire:,force \ --name "$0" -- "$@"` help(){ @@ -53,6 +53,7 @@ $basename [ OPTIONS ] Encrypted password creation: $basename { -p | --password } [ --name NAME ] [ --dir DIR] + $basename { -F | --passfile } FILE [ --name NAME ] [ --dir DIR] Key creation options: -v, --version Show program's version number and exit @@ -74,10 +75,14 @@ -x TIME, --expire TIME Key expire time. Default is no expiration. See gpg(1) for syntax. - -f, --force Force overwriting old keys. + -f, --force Force overwriting old key files. Password creation options: - -p, --password Create an encrypted password using the keys in + -p, --password Create an encrypted password using the key in + the key directory. All options other than + --dir and --name are ignored. + -F FILE, --passfile FILE + Encrypt a password from FILE using the key in the key directory. All options other than --dir and --name are ignored. EOF @@ -87,6 +92,7 @@ while :; do case "$1" in -p|--password) mode=password; shift;; + -F|--passfile) mode=password; PASSFILE="$2"; shift 2;; -d|--dir) KEYDIR="$2"; shift 2;; -t|--type) KEYTYPE="$2"; shift 2;; -s|--subtype) SUBKEYTYPE="$2"; shift 2;; @@ -235,7 +241,7 @@ FILECOMMENT="$FILECOMMENT <$KEYEMAIL>" fi - # Export keys from key rings to key files + # Export key from key rings to key files gpg --quiet --batch --no-tty --no-options --enable-dsa2 \ --homedir "$RINGDIR" --armor --export-options export-minimal \ --comment "$FILECOMMENT" --output "$SECKEYFILE" \ @@ -246,7 +252,7 @@ fi if [ "$mode" = password ]; then - # Import keys into temporary key rings + # Import key into temporary key rings gpg --quiet --batch --no-tty --no-options --enable-dsa2 \ --homedir "$RINGDIR" --trust-model always --armor \ --import "$SECKEYFILE" @@ -265,22 +271,37 @@ FILECOMMENT="Encrypted password for a Mandos client" - stty -echo - echo -n "Enter passphrase: " >&2 - head --lines=1 | tr --delete '\n' \ - | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \ + if [ -n "$PASSFILE" ]; then + cat "$PASSFILE" + else + stty -echo + echo -n "Enter passphrase: " >&2 + first="$(head --lines=1 | tr --delete '\n')" + echo -n -e "\nRepeat passphrase: " >&2 + second="$(head --lines=1 | tr --delete '\n')" + echo >&2 + stty echo + if [ "$first" != "$second" ]; then + echo -e "Passphrase mismatch" >&2 + false + else + echo -n "$first" + fi + fi | gpg --quiet --batch --no-tty --no-options --enable-dsa2 \ --homedir "$RINGDIR" --trust-model always --armor --encrypt \ --recipient "$FINGERPRINT" --comment "$FILECOMMENT" \ > "$SECFILE" - echo >&2 - stty echo + status="${PIPESTATUS[0]}" + if [ "$status" -ne 0 ]; then + exit "$status" + fi cat <<-EOF [$KEYNAME] host = $KEYNAME fingerprint = $FINGERPRINT secret = -EOF + EOF sed --quiet --expression=' /^-----BEGIN PGP MESSAGE-----$/,/^-----END PGP MESSAGE-----$/{ /^$/,${ === modified file 'mandos-keygen.xml' --- mandos-keygen.xml 2008-09-12 19:12:40 +0000 +++ mandos-keygen.xml 2008-09-19 23:31:34 +0000 @@ -3,7 +3,7 @@ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ - + ]> @@ -122,6 +122,10 @@ + + + FILE @@ -167,8 +171,9 @@ This program can also be used with the - option to generate a ready-made - section for clients.conf (see + or + options to generate a ready-made section for + clients.conf (see mandos-clients.conf 5). @@ -326,6 +331,18 @@ + + + + + + The same as , but read from + FILE, not the terminal. + + + === modified file 'mandos.xml' --- mandos.xml 2008-09-12 19:12:40 +0000 +++ mandos.xml 2008-09-21 12:20:55 +0000 @@ -3,7 +3,7 @@ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ - + ]> @@ -504,7 +504,7 @@ mandos-clients.conf 5) must be made non-readable by anyone - except the user running the server. + except the user starting the server (usually root). As detailed in , the status of all === modified file 'plugin-runner.c' --- plugin-runner.c 2008-09-19 00:00:51 +0000 +++ plugin-runner.c 2008-09-26 04:54:35 +0000 @@ -2,7 +2,7 @@ /* * Mandos plugin runner - Run Mandos plugins * - * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson + * Copyright © 2008 Teddy Hogeborn & 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 @@ -27,8 +27,8 @@ #include /* malloc(), exit(), EXIT_FAILURE, EXIT_SUCCESS, realloc() */ #include /* bool, true, false */ -#include /* perror, popen(), fileno(), - fprintf(), stderr, STDOUT_FILENO */ +#include /* perror, fileno(), fprintf(), + stderr, STDOUT_FILENO */ #include /* DIR, opendir(), stat(), struct stat, waitpid(), WIFEXITED(), WEXITSTATUS(), wait(), pid_t, @@ -46,7 +46,7 @@ fcntl(), setuid(), setgid(), F_GETFD, F_SETFD, FD_CLOEXEC, access(), pipe(), fork(), close() - dup2, STDOUT_FILENO, _exit(), + dup2(), STDOUT_FILENO, _exit(), execv(), write(), read(), close() */ #include /* fcntl(), F_GETFD, F_SETFD, @@ -846,12 +846,12 @@ perror("sigaction"); _exit(EXIT_FAILURE); } - ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask, NULL); + ret = sigprocmask(SIG_UNBLOCK, &sigchld_action.sa_mask, NULL); if(ret < 0){ perror("sigprocmask"); _exit(EXIT_FAILURE); } - + ret = dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */ if(ret == -1){ perror("dup2"); @@ -907,12 +907,11 @@ if (maxfd < new_plugin->fd){ maxfd = new_plugin->fd; } - } closedir(dir); dir = NULL; - + for(plugin *p = plugin_list; p != NULL; p = p->next){ if(p->pid != 0){ break; @@ -923,7 +922,7 @@ free_plugin_list(); } } - + /* Main loop while running plugins exist */ while(plugin_list){ fd_set rfds = rfds_all; @@ -969,6 +968,10 @@ goto fallback; } + plugin *next_plugin = proc->next; + free_plugin(proc); + proc = next_plugin; + /* We are done modifying process list, so unblock signal */ ret = sigprocmask (SIG_UNBLOCK, &sigchld_action.sa_mask, NULL); @@ -982,14 +985,11 @@ break; } - plugin *next_plugin = proc->next; - free_plugin(proc); - proc = next_plugin; continue; } /* This process exited nicely, so print its buffer */ - + bool bret = print_out_password(proc->buffer, proc->buffer_length); if(not bret){ @@ -1061,7 +1061,7 @@ perror("sigaction"); exitstatus = EXIT_FAILURE; } - + if(custom_argv != NULL){ for(char **arg = custom_argv+1; *arg != NULL; arg++){ free(*arg); @@ -1073,7 +1073,7 @@ closedir(dir); } - /* Free the process list and kill the processes */ + /* Kill the processes */ for(plugin *p = plugin_list; p != NULL; p = p->next){ if(p->pid != 0){ close(p->fd); @@ -1092,7 +1092,7 @@ if(errno != ECHILD){ perror("wait"); } - + free_plugin_list(); free(plugindir); === added file 'plugins.d/askpass-fifo.c' --- plugins.d/askpass-fifo.c 1970-01-01 00:00:00 +0000 +++ plugins.d/askpass-fifo.c 2008-09-26 19:47:21 +0000 @@ -0,0 +1,80 @@ +#define _GNU_SOURCE /* TEMP_FAILURE_RETRY() */ +#include /* ssize_t */ +#include /* mkfifo(), S_IRUSR, S_IWUSR */ +#include /* and */ +#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 */ + + +int main(__attribute__((unused))int argc, + __attribute__((unused))char **argv){ + int ret = 0; + ssize_t sret; + + /* Create FIFO */ + const char passfifo[] = "/lib/cryptsetup/passfifo"; + 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 = TEMP_FAILURE_RETRY(open(passfifo, O_RDONLY)); + if(fifo_fd == -1){ + perror("open"); + return EXIT_FAILURE; + } + + /* Read from FIFO */ + char *buf = NULL; + size_t buf_len = 0; + { + 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"); + free(buf); + return EXIT_FAILURE; + } + buf = tmp; + buf_allocated += blocksize; + } + sret = TEMP_FAILURE_RETRY(read(fifo_fd, buf + buf_len, + buf_allocated - buf_len)); + if(sret == -1){ + perror("read"); + free(buf); + return EXIT_FAILURE; + } + buf_len += (size_t)sret; + }while(sret != 0); + } + + /* Close FIFO */ + TEMP_FAILURE_RETRY(close(fifo_fd)); + + /* Print password to stdout */ + size_t written = 0; + while(written < buf_len){ + sret = TEMP_FAILURE_RETRY(write(STDOUT_FILENO, buf + written, + buf_len - written)); + if(sret == -1){ + perror("write"); + free(buf); + return EXIT_FAILURE; + } + written += (size_t)sret; + } + free(buf); + + return EXIT_SUCCESS; +} === modified file 'plugins.d/mandos-client.c' --- plugins.d/mandos-client.c 2008-09-07 01:44:44 +0000 +++ plugins.d/mandos-client.c 2008-09-19 20:42:17 +0000 @@ -9,7 +9,7 @@ * "browse_callback", and parts of "main". * * Everything else is - * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson + * Copyright © 2008 Teddy Hogeborn & Björn Påhlsson * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as === modified file 'plugins.d/password-prompt.c' --- plugins.d/password-prompt.c 2008-09-07 01:44:44 +0000 +++ plugins.d/password-prompt.c 2008-09-19 20:42:17 +0000 @@ -2,7 +2,7 @@ /* * Passprompt - Read a password from the terminal and print it * - * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson + * Copyright © 2008 Teddy Hogeborn & 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 === added file 'plugins.d/splashy.c' --- plugins.d/splashy.c 1970-01-01 00:00:00 +0000 +++ plugins.d/splashy.c 2008-09-24 23:03:31 +0000 @@ -0,0 +1,220 @@ +#define _GNU_SOURCE /* asprintf() */ +#include /* sig_atomic_t, struct sigaction, + sigemptyset(), sigaddset(), + sigaction, SIGINT, SIG_IGN, SIGHUP, + SIGTERM, kill(), SIGKILL */ +#include /* NULL */ +#include /* getenv() */ +#include /* asprintf(), perror() */ +#include /* EXIT_FAILURE, EXIT_SUCCESS, + strtoul(), free() */ +#include /* pid_t, DIR, struct dirent, + ssize_t */ +#include /* opendir(), readdir(), closedir() */ +#include /* readlink(), fork(), execl(), + _exit */ +#include /* memcmp() */ +#include /* and */ +#include /* errno */ +#include /* waitpid(), WIFEXITED(), + WEXITSTATUS() */ + +sig_atomic_t interrupted_by_signal = 0; + +static void termination_handler(__attribute__((unused))int signum){ + interrupted_by_signal = 1; +} + +int main(__attribute__((unused))int argc, + __attribute__((unused))char **argv){ + int ret = 0; + + /* Create prompt string */ + char *prompt = NULL; + { + const char *const cryptsource = getenv("cryptsource"); + const char *const crypttarget = getenv("crypttarget"); + const char *const prompt_start = "getpass " + "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 splashy process */ + pid_t splashy_pid = 0; + { + const char splashy_name[] = "/sbin/splashy"; + 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 */ + continue; + } + /* Find the executable name by doing readlink() on the + /proc//exe link */ + char exe_target[sizeof(splashy_name)]; + ssize_t sret; + { + 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; + } + sret = readlink(exe_link, exe_target, sizeof(exe_target)); + free(exe_link); + } + if((sret == ((ssize_t)sizeof(exe_target)-1)) + and (memcmp(splashy_name, exe_target, + sizeof(exe_target)-1) == 0)){ + splashy_pid = pid; + break; + } + } + closedir(proc_dir); + } + if(splashy_pid == 0){ + free(prompt); + return EXIT_FAILURE; + } + + /* Set up the signal handler */ + { + struct sigaction old_action, + new_action = { .sa_handler = termination_handler, + .sa_flags = 0 }; + sigemptyset(&new_action.sa_mask); + 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){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + if (old_action.sa_handler != SIG_IGN){ + ret = sigaction(SIGINT, &new_action, NULL); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + } + ret = sigaction(SIGHUP, NULL, &old_action); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + if (old_action.sa_handler != SIG_IGN){ + ret = sigaction(SIGHUP, &new_action, NULL); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + } + ret = sigaction(SIGTERM, NULL, &old_action); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + if (old_action.sa_handler != SIG_IGN){ + ret = sigaction(SIGTERM, &new_action, NULL); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + } + } + + /* Fork off the splashy command to prompt for password */ + 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"; + ret = execl(splashy_command, splashy_command, prompt, + (char *)NULL); + if(not interrupted_by_signal and errno != ENOENT){ + /* Don't report "File not found", since splashy might not be + installed. */ + perror("execl"); + } + free(prompt); + return EXIT_FAILURE; + } + } + + /* Parent */ + free(prompt); + + /* Wait for command to complete */ + int status; + while(not interrupted_by_signal){ + waitpid(splashy_command_pid, &status, 0); + if(not interrupted_by_signal + and WIFEXITED(status) and WEXITSTATUS(status)==0){ + return EXIT_SUCCESS; + } + } + kill(splashy_pid, SIGTERM); + if(interrupted_by_signal){ + kill(splashy_command_pid, SIGTERM); + } + + pid_t new_splashy_pid = fork(); + if(new_splashy_pid == 0){ + /* Child; will become new splashy process */ + while(kill(splashy_pid, 0)){ + sleep(2); + kill(splashy_pid, SIGKILL); + sleep(1); + } + 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); + } + + return EXIT_FAILURE; +} === removed file 'plugins.d/usplash' --- plugins.d/usplash 2008-08-14 02:24:59 +0000 +++ plugins.d/usplash 1970-01-01 00:00:00 +0000 @@ -1,42 +0,0 @@ -#!/bin/sh -e - -# If not on a tty, then get rid of possibly disrupting stderr output -if ! tty -s; then - exec 2>/dev/null -fi - -test -x /sbin/usplash - -usplash="`pidof usplash -o $$`" -test -n "$usplash" - -# We get some variables from cryptsetup: -# $cryptsource the device node, like "/dev/sda3" -# $crypttarget the device mapper name, like "sda3_crypt". - -prompt="Enter passphrase to unlock" -if [ -n "$crypttarget" ]; then - prompt="$prompt the disk $crypttarget" -fi -if [ -n "$cryptsource" ]; then - prompt="$prompt ($cryptsource)" -fi - -splash_input_password(){ - test -p /dev/.initramfs/usplash_outfifo || return 1 - /sbin/usplash_write "INPUTQUIET $1" || return 1 - cat /dev/.initramfs/usplash_outfifo 2> /dev/null || return 1 -} - -# Usplash keeps waiting for input even if some other plugin provided -# the password, so we must kill it -trap "kill -TERM $usplash; sleep 2; kill -KILL $usplash; - kill -TERM $$" TERM HUP - -password="`splash_input_password \"$prompt: \" password`" - -trap - TERM - -/sbin/usplash_write "TIMEOUT 15" - -echo -n "$password" === added file 'plugins.d/usplash.c' --- plugins.d/usplash.c 1970-01-01 00:00:00 +0000 +++ plugins.d/usplash.c 2008-09-26 19:27:46 +0000 @@ -0,0 +1,479 @@ +#define _GNU_SOURCE /* asprintf() */ +#include /* sig_atomic_t, struct sigaction, + sigemptyset(), sigaddset(), SIGINT, + SIGHUP, SIGTERM, sigaction(), + SIG_IGN, kill(), SIGKILL */ +#include /* bool, false, true */ +#include /* open(), O_WRONLY, O_RDONLY */ +#include /* errno, EINTR */ +#include /* size_t, ssize_t, pid_t, DIR, + struct dirent */ +#include /* NULL */ +#include /* strlen(), memcmp() */ +#include /* asprintf(), perror() */ +#include /* close(), write(), readlink(), + read(), STDOUT_FILENO, sleep(), + fork(), setuid(), geteuid(), + setsid(), chdir(), dup2(), + STDERR_FILENO, execv() */ +#include /* free(), EXIT_FAILURE, strtoul(), + realloc(), EXIT_SUCCESS, malloc(), + _exit() */ +#include /* getenv() */ +#include /* opendir(), readdir(), closedir() */ + + + +#include /* and */ +#include /* waitpid(), WIFEXITED(), + WEXITSTATUS() */ + +sig_atomic_t interrupted_by_signal = 0; + +static void termination_handler(__attribute__((unused))int signum){ + interrupted_by_signal = 1; +} + +static bool usplash_write(const char *cmd, const char *arg){ + /* + * usplash_write("TIMEOUT", "15"); -> "TIMEOUT 15\0" + * usplash_write("PULSATE", NULL); -> "PULSATE\0" + * SEE ALSO + * usplash_write(8) + */ + int ret; + 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; + } + }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); + }else{ + do{ + ret = asprintf(&cmd_line_alloc, "%s %s", cmd, arg); + if(ret == -1 and (errno != EINTR or interrupted_by_signal)){ + int e = errno; + close(fifo_fd); + errno = e; + return false; + } + }while(ret == -1); + cmd_line = cmd_line_alloc; + cmd_line_len = (size_t)ret + 1; + } + + size_t written = 0; + 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)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; +} + +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; + 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 */ + continue; + } + /* Find the executable name by doing readlink() on the + /proc//exe link */ + char exe_target[sizeof(usplash_name)]; + { + 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; + } + sret = readlink(exe_link, exe_target, sizeof(exe_target)); + free(exe_link); + if(sret == -1){ + continue; + } + } + 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); + } + 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); + } + break; + } + } + closedir(proc_dir); + } + if(usplash_pid == 0){ + free(prompt); + return EXIT_FAILURE; + } + + /* Set up the signal handler */ + { + struct sigaction old_action, + new_action = { .sa_handler = termination_handler, + .sa_flags = 0 }; + sigemptyset(&new_action.sa_mask); + 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){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + if (old_action.sa_handler != SIG_IGN){ + ret = sigaction(SIGINT, &new_action, NULL); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + } + ret = sigaction(SIGHUP, NULL, &old_action); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + if (old_action.sa_handler != SIG_IGN){ + ret = sigaction(SIGHUP, &new_action, NULL); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + } + ret = sigaction(SIGTERM, NULL, &old_action); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + if (old_action.sa_handler != SIG_IGN){ + ret = sigaction(SIGTERM, &new_action, NULL); + if(ret == -1){ + perror("sigaction"); + free(prompt); + return EXIT_FAILURE; + } + } + } + + /* Write command to FIFO */ + 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); + + /* 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 */ + } + + /* If we got here, an error or interrupt must have happened */ + + int cmdline_argc = 0; + char **cmdline_argv = malloc(sizeof(char *)); + /* Create argv and argc for new usplash*/ + { + size_t position = 0; + while(position < cmdline_len){ + char **tmp = realloc(cmdline_argv, + (sizeof(char *) + * (size_t)(cmdline_argc + 2))); + if(tmp == NULL){ + 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); + while(kill(usplash_pid, 0) == 0){ + 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) */ + 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); + } + + execv(usplash_name, cmdline_argv); + perror("execv"); + free(cmdline); + free(cmdline_argv); + _exit(EXIT_FAILURE); + } + free(cmdline); + free(cmdline_argv); + sleep(2); + if(not usplash_write("PULSATE", NULL) + and (errno != EINTR)){ + perror("usplash_write"); + } + + return EXIT_FAILURE; +}