=== modified file 'Makefile' --- Makefile 2009-05-23 05:59:52 +0000 +++ Makefile 2009-09-17 14:21:18 +0000 @@ -16,7 +16,7 @@ OPTIMIZE=-Os LANGUAGE=-std=gnu99 htmldir=man -version=1.0.11 +version=1.0.12 SED=sed ## Use these settings for a traditional /usr/local install === modified file 'NEWS' --- NEWS 2009-05-23 05:59:52 +0000 +++ NEWS 2009-09-17 14:21:18 +0000 @@ -1,6 +1,22 @@ This NEWS file records noteworthy changes, very tersely. See the manual for detailed information. +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". === modified file 'TODO' --- TODO 2009-09-07 07:48:59 +0000 +++ TODO 2009-09-19 17:41:18 +0000 @@ -1,25 +1,29 @@ -*- org -*- * mandos-client -** TODO [#A] Clean up /tmp directory and take down interface on signal :test: ** TODO [#B] use scandir(3) instead of readdir(3) ** TODO [#B] Prefix all debug output with argv[0] -** TODO [#B] Retry a server which has a non-definite reply. +** 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(). * splashy -** TODO [#A] Re-raise signal received when exiting due to handled signal :test: ** TODO [#B] use scandir(3) instead of readdir(3) -** TODO [#B] Prefix all debug output with argv[0] +** TODO [#B] Prefix all debug output with "Mandos plugin " + argv[0] * usplash -** TODO [#A] Re-raise signal received when exiting due to handled signal. ** TODO [#B] use scandir(3) instead of readdir(3) -** TODO [#B] Prefix all debug output with argv[0] +** TODO [#B] Prefix all debug output with "Mandos plugin " + argv[0] + +* askpass-fifo +** TODO [#B] Prefix all debug output with "Mandos plugin " + argv[0] +** TODO [#B] Drop privileges after opening FIFO. * password-prompt -** TODO [#B] Prefix all debug output with argv[0] +** TODO [#B] Prefix all debug output with "Mandos plugin " + argv[0] + +* TODO passdev * plugin-runner ** TODO [#B] use scandir(3) instead of readdir(3) @@ -43,11 +47,20 @@ [[info:standards:Option%20Table][Table of Long Options]] ** TODO Date+time on console log messages :BUGS: Is this the default? -** TODO Split IPv6_TCPServer into a generic and Mandos-specific class -** TODO move handle_ipc out of IPv6_TCPServer ** TODO DBusServiceObjectUsingSuper -** Global enable/disable flag -** By-client countdown on secrets given +** TODO Global enable/disable flag +** TODO By-client countdown on secrets given +** TODO 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 Delay before client receives key + This would give an operator opportunity to cancel the request if + desired. +** TODO Client manual approval mode + A client needs manual approval on the server before it gets the + secret +** TODO Persistent state + /var/lib/mandos/* * mandos.xml ** [[file:mandos.xml::XXX][Document D-Bus interface]] @@ -58,10 +71,13 @@ *** Handle "no D-Bus server" and/or "no Mandos server found" better *** [#B] --dump option -* mandos-name +* TODO mandos-dispatch + Listens for specified D-Bus signals and spawns shell commands with + arguments. + +* mandos-monitor ** D-Bus mail loop w/ signal receiver -** Urwid/Newt client data displayer -*** Urwid scaffolding +** Snack/Newt client data displayer *** Client Widgets *** Properties popup @@ -72,6 +88,10 @@ ** TODO [#B] "--test" option For testing decryption before rebooting. +* Makefile +** Implement DEB_BUILD_OPTIONS + http://www.debian.org/doc/debian-policy/ch-source.html#s-debianrules-options + * Package ** /usr/share/initramfs-tools/hooks/mandos *** TODO [#C] use same file name rules as run-parts(8) === modified file 'common.ent' --- common.ent 2009-05-23 05:59:52 +0000 +++ common.ent 2009-09-17 14:21:18 +0000 @@ -1,3 +1,3 @@ - + === modified file 'debian/changelog' --- debian/changelog 2009-05-23 05:59:52 +0000 +++ debian/changelog 2009-09-17 14:21:18 +0000 @@ -1,3 +1,19 @@ +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". === modified file 'debian/control' --- debian/control 2009-05-18 17:57:13 +0000 +++ debian/control 2009-09-17 01:21:27 +0000 @@ -7,7 +7,7 @@ Build-Depends: debhelper (>= 7), docbook-xml, docbook-xsl, libavahi-core-dev, libgpgme11-dev, libgnutls-dev, xsltproc, pkg-config -Standards-Version: 3.8.1 +Standards-Version: 3.8.3 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 === modified file 'debian/mandos-client.README.Debian' --- debian/mandos-client.README.Debian 2009-04-14 14:56:46 +0000 +++ debian/mandos-client.README.Debian 2009-09-08 06:28:20 +0000 @@ -1,32 +1,42 @@ -* 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 - - Make sure that the correct network interface is specified in the - DEVICE setting in the "/etc/initramfs-tools/initramfs.conf" file. - If this is changed, it will be necessary to update the initrd image - by doing "update-initramfs -k all -u". This setting 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, - see the file "Documentation/nfsroot.txt" in the Linux source tree. - - Note that since this 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. - -* 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 +* Choose the Client Network Interface + + You MUST make sure that the correct network interface is specified + in the DEVICE setting in the "/etc/initramfs-tools/initramfs.conf" + file. *If* this 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 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 @@ -36,16 +46,16 @@ * 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: + 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 + update-initramfs -k all -u -* Do *NOT* Edit /etc/crypttab +* 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 + 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. @@ -74,4 +84,4 @@ work, "--options-for=mandos-client:--connect=
:" needs to be manually added to the file "/etc/mandos/plugin-runner.conf". - -- Teddy Hogeborn , Tue, 14 Apr 2009 16:51:18 +0200 + -- Teddy Hogeborn , Tue, 8 Sep 2009 08:25:58 +0200 === modified file 'debian/mandos.README.Debian' --- debian/mandos.README.Debian 2009-01-04 22:15:01 +0000 +++ debian/mandos.README.Debian 2009-09-08 06:28:20 +0000 @@ -1,7 +1,10 @@ The Mandos server is useless without at least one configured client in /etc/mandos/clients.conf. To create one, install the "mandos-client" -package on a client computer, and run "mandos-keygen --password" there -to get a config file stanza. Append that to /etc/mandos/clients.conf -on the Mandos server. - - -- Teddy Hogeborn , Sun, 4 Jan 2009 22:59:22 +0100 +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 === modified file 'init.d-mandos' --- init.d-mandos 2008-09-21 12:04:02 +0000 +++ init.d-mandos 2009-09-16 23:28:39 +0000 @@ -1,8 +1,8 @@ #! /bin/sh ### BEGIN INIT INFO # Provides: mandos -# Required-Start: $remote_fs avahi-daemon -# Required-Stop: $remote_fs +# Required-Start: $remote_fs $syslog avahi +# Required-Stop: $remote_fs $syslog avahi # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Mandos server === modified file 'initramfs-tools-script' --- initramfs-tools-script 2009-02-09 02:01:13 +0000 +++ initramfs-tools-script 2009-09-16 23:28:39 +0000 @@ -10,7 +10,6 @@ # eventually be "/scripts/init-premount/mandos" in the initrd.img # file. -# No initramfs pre-requirements. PREREQ="udev" prereqs() { === modified file 'mandos' --- mandos 2009-08-30 03:10:29 +0000 +++ mandos 2009-09-20 07:04:03 +0000 @@ -77,7 +77,7 @@ SO_BINDTODEVICE = None -version = "1.0.11" +version = "1.0.12" logger = logging.Logger(u'mandos') syslogger = (logging.handlers.SysLogHandler @@ -174,7 +174,8 @@ self.server.EntryGroupNew()), avahi.DBUS_INTERFACE_ENTRY_GROUP) self.group.connect_to_signal('StateChanged', - self.entry_group_state_changed) + self + .entry_group_state_changed) logger.debug(u"Adding Zeroconf service '%s' of type '%s' ...", self.name, self.type) self.group.AddService( @@ -702,7 +703,8 @@ self.interval = datetime.timedelta(0, 0, 0, milliseconds) # Emit D-Bus signal self.PropertyChanged(dbus.String(u"interval"), - (dbus.UInt64(self.interval_milliseconds(), + (dbus.UInt64(self + .interval_milliseconds(), variant_level=1))) # SetSecret - method @@ -983,9 +985,6 @@ clients: set of Client objects gnutls_priority GnuTLS priority string use_dbus: Boolean; to emit D-Bus signals or not - 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. """ @@ -1172,7 +1171,7 @@ def main(): - ###################################################################### + ################################################################## # Parsing of options, both command line and config file parser = optparse.OptionParser(version = "%%prog %s" % version) === modified file 'mandos-clients.conf.xml' --- mandos-clients.conf.xml 2009-02-15 09:09:27 +0000 +++ mandos-clients.conf.xml 2009-09-17 01:21:27 +0000 @@ -3,7 +3,7 @@ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ /etc/mandos/clients.conf"> - + %common; ]> @@ -108,10 +108,11 @@ 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 timeout is how long the server will wait (for either a + successful checker run or a client receiving its secret) + 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 === modified file 'mandos-ctl' --- mandos-ctl 2009-08-30 03:10:29 +0000 +++ mandos-ctl 2009-09-17 14:21:18 +0000 @@ -31,7 +31,7 @@ server_path = '/' server_interface = domain + '.Mandos' client_interface = domain + '.Mandos.Client' -version = "1.0.11" +version = "1.0.12" bus = dbus.SystemBus() mandos_dbus_objc = bus.get_object(busname, server_path) mandos_serv = dbus.Interface(mandos_dbus_objc, === modified file 'mandos-keygen' --- mandos-keygen 2009-05-23 05:59:52 +0000 +++ mandos-keygen 2009-09-17 14:21:18 +0000 @@ -21,7 +21,7 @@ # Contact the authors at . # -VERSION="1.0.11" +VERSION="1.0.12" KEYDIR="/etc/keys/mandos" KEYTYPE=DSA === modified file 'mandos.lsm' --- mandos.lsm 2009-05-23 05:59:52 +0000 +++ mandos.lsm 2009-09-17 14:21:18 +0000 @@ -1,7 +1,7 @@ Begin4 Title: Mandos -Version: 1.0.11 -Entered-date: 2009-05-23 +Version: 1.0.12 +Entered-date: 2009-09-17 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,9 +12,9 @@ Maintained-by: teddy@fukt.bsnet.se (Teddy Hogeborn), belorn@fukt.bsnet.se (Björn Påhlsson) Primary-site: http://www.fukt.bsnet.se/mandos - 99K mandos_1.0.11.orig.tar.gz + 103K mandos_1.0.12.orig.tar.gz Alternate-site: ftp://ftp.fukt.bsnet.se/pub/mandos - 99K mandos_1.0.11.orig.tar.gz + 103K mandos_1.0.12.orig.tar.gz Platforms: Requires GCC, GNU libC, Avahi, GnuPG, Python 2.5, and various other libraries. While made for Debian GNU/Linux, it is probably portable to other distributions, but not other Unixes. === modified file 'mandos.xml' --- mandos.xml 2009-02-25 01:47:45 +0000 +++ mandos.xml 2009-09-17 01:21:27 +0000 @@ -2,7 +2,7 @@ - + %common; ]> @@ -327,11 +327,14 @@ 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. The timeout, + longer eligible to receive the encrypted password. (Manual + intervention is required to re-enable a client.) The timeout, checker program, and interval between checks can be configured both globally and per client; see mandos-clients.conf - 5. + 5. A client successfully + receiving its password will also be treated as a successful + checker run. === modified file 'plugin-runner.c' --- plugin-runner.c 2009-09-21 13:13:47 +0000 +++ plugin-runner.c 2009-09-21 13:51:11 +0000 @@ -230,13 +230,14 @@ | [[info:libc:Descriptor%20Flags][File Descriptor Flags]] | */ static int set_cloexec_flag(int fd){ - int ret = TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD, 0)); + int ret = (int)TEMP_FAILURE_RETRY(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 TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD, ret | FD_CLOEXEC)); + return (int)TEMP_FAILURE_RETRY(fcntl(fd, F_SETFD, + ret | FD_CLOEXEC)); } @@ -788,18 +789,19 @@ char *filename; if(plugindir == NULL){ - ret = TEMP_FAILURE_RETRY(asprintf(&filename, PDIR "/%s", - dirst->d_name)); + ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, PDIR "/%s", + dirst->d_name)); } else { - ret = TEMP_FAILURE_RETRY(asprintf(&filename, "%s/%s", plugindir, - dirst->d_name)); + ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, "%s/%s", + plugindir, + dirst->d_name)); } if(ret < 0){ perror("asprintf"); continue; } - ret = TEMP_FAILURE_RETRY(stat(filename, &st)); + ret = (int)TEMP_FAILURE_RETRY(stat(filename, &st)); if(ret == -1){ perror("stat"); free(filename); @@ -860,7 +862,7 @@ } int pipefd[2]; - ret = TEMP_FAILURE_RETRY(pipe(pipefd)); + ret = (int)TEMP_FAILURE_RETRY(pipe(pipefd)); if(ret == -1){ perror("pipe"); exitstatus = EXIT_FAILURE; @@ -880,9 +882,9 @@ goto fallback; } /* Block SIGCHLD until process is safely in process list */ - ret = TEMP_FAILURE_RETRY(sigprocmask(SIG_BLOCK, - &sigchld_action.sa_mask, - NULL)); + ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_BLOCK, + &sigchld_action.sa_mask, + NULL)); if(ret < 0){ perror("sigprocmask"); exitstatus = EXIT_FAILURE; @@ -942,9 +944,9 @@ plugin *new_plugin = getplugin(dirst->d_name); if(new_plugin == NULL){ perror("getplugin"); - ret = TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK, - &sigchld_action.sa_mask, - NULL)); + ret = (int)(TEMP_FAILURE_RETRY + (sigprocmask(SIG_UNBLOCK, &sigchld_action.sa_mask, + NULL))); if(ret < 0){ perror("sigprocmask"); } @@ -957,16 +959,17 @@ /* Unblock SIGCHLD so signal handler can be run if this process has already completed */ - ret = TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK, - &sigchld_action.sa_mask, - NULL)); + ret = (int)TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK, + &sigchld_action.sa_mask, + NULL)); if(ret < 0){ perror("sigprocmask"); exitstatus = EXIT_FAILURE; goto fallback; } - FD_SET(new_plugin->fd, &rfds_all); + FD_SET(new_plugin->fd, &rfds_all); /* Spurious warning from + -Wconversion */ if(maxfd < new_plugin->fd){ maxfd = new_plugin->fd; @@ -1026,12 +1029,14 @@ } /* Remove the plugin */ - FD_CLR(proc->fd, &rfds_all); + FD_CLR(proc->fd, &rfds_all); /* Spurious warning from + -Wconversion */ /* Block signal while modifying process_list */ - ret = TEMP_FAILURE_RETRY(sigprocmask(SIG_BLOCK, - &sigchld_action.sa_mask, - NULL)); + ret = (int)TEMP_FAILURE_RETRY(sigprocmask + (SIG_BLOCK, + &sigchld_action.sa_mask, + NULL)); if(ret < 0){ perror("sigprocmask"); exitstatus = EXIT_FAILURE; @@ -1043,9 +1048,9 @@ proc = next_plugin; /* We are done modifying process list, so unblock signal */ - ret = TEMP_FAILURE_RETRY(sigprocmask(SIG_UNBLOCK, - &sigchld_action.sa_mask, - NULL)); + ret = (int)(TEMP_FAILURE_RETRY + (sigprocmask(SIG_UNBLOCK, + &sigchld_action.sa_mask, NULL))); if(ret < 0){ perror("sigprocmask"); exitstatus = EXIT_FAILURE; @@ -1071,7 +1076,9 @@ } /* This process has not completed. Does it have any output? */ - if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ + if(proc->eof or not FD_ISSET(proc->fd, &rfds)){ /* Spurious + warning from + -Wconversion */ /* This process had nothing to say at this time */ proc = proc->next; continue; === modified file 'plugins.d/askpass-fifo.c' --- plugins.d/askpass-fifo.c 2009-09-07 07:48:59 +0000 +++ plugins.d/askpass-fifo.c 2009-09-16 23:28:39 +0000 @@ -42,14 +42,14 @@ /* Create FIFO */ const char passfifo[] = "/lib/cryptsetup/passfifo"; - ret = (int)TEMP_FAILURE_RETRY(mkfifo(passfifo, S_IRUSR | S_IWUSR)); + ret = mkfifo(passfifo, S_IRUSR | S_IWUSR); if(ret == -1 and errno != EEXIST){ perror("mkfifo"); return EXIT_FAILURE; } /* Open FIFO */ - int fifo_fd = (int)TEMP_FAILURE_RETRY(open(passfifo, O_RDONLY)); + int fifo_fd = open(passfifo, O_RDONLY); if(fifo_fd == -1){ perror("open"); return EXIT_FAILURE; @@ -72,8 +72,7 @@ buf = tmp; buf_allocated += blocksize; } - sret = TEMP_FAILURE_RETRY(read(fifo_fd, buf + buf_len, - buf_allocated - buf_len)); + sret = read(fifo_fd, buf + buf_len, buf_allocated - buf_len); if(sret == -1){ perror("read"); free(buf); @@ -84,13 +83,12 @@ } /* Close FIFO */ - TEMP_FAILURE_RETRY(close(fifo_fd)); + 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)); + sret = write(STDOUT_FILENO, buf + written, buf_len - written); if(sret == -1){ perror("write"); free(buf); === modified file 'plugins.d/mandos-client.c' --- plugins.d/mandos-client.c 2009-09-07 07:48:59 +0000 +++ plugins.d/mandos-client.c 2009-09-17 11:22:28 +0000 @@ -44,7 +44,7 @@ #include /* uint16_t, uint32_t */ #include /* NULL, size_t, ssize_t */ #include /* free(), EXIT_SUCCESS, EXIT_FAILURE, - srand(), strtof() */ + srand(), strtof(), abort() */ #include /* bool, false, true */ #include /* memset(), strcmp(), strlen(), strerror(), asprintf(), strcpy() */ @@ -71,8 +71,8 @@ INET_ADDRSTRLEN, INET6_ADDRSTRLEN */ #include /* close(), SEEK_SET, off_t, write(), - getuid(), getgid(), setuid(), - setgid() */ + getuid(), getgid(), seteuid(), + setgid(), pause() */ #include /* inet_pton(), htons */ #include /* not, or, and */ #include /* struct argp_option, error_t, struct @@ -142,6 +142,9 @@ .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, @@ -474,7 +477,12 @@ static int init_gnutls_session(gnutls_session_t *session){ int ret; /* GnuTLS session creation */ - ret = gnutls_init(session, GNUTLS_SERVER); + 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){ fprintf(stderr, "Error in GnuTLS session initialization: %s\n", safer_gnutls_strerror(ret)); @@ -482,7 +490,13 @@ { const char *err; - ret = gnutls_priority_set_direct(*session, mc.priority, &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){ fprintf(stderr, "Syntax error at: %s\n", err); fprintf(stderr, "GnuTLS error: %s\n", @@ -492,8 +506,14 @@ } } - ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE, - mc.cred); + 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){ fprintf(stderr, "Error setting GnuTLS credentials: %s\n", safer_gnutls_strerror(ret)); @@ -502,8 +522,7 @@ } /* 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); @@ -514,9 +533,6 @@ static void empty_log(__attribute__((unused)) AvahiLogLevel level, __attribute__((unused)) const char *txt){} -sig_atomic_t quit_now = 0; -int signal_received = 0; - /* Called when a Mandos server is found */ static int start_mandos_communication(const char *ip, uint16_t port, AvahiIfIndex if_index, @@ -528,11 +544,11 @@ struct sockaddr_in6 in6; } to; char *buffer = NULL; - char *decrypted_buffer; + char *decrypted_buffer = NULL; size_t buffer_length = 0; size_t buffer_capacity = 0; size_t written; - int retval = 0; + int retval = -1; gnutls_session_t session; int pf; /* Protocol family */ @@ -565,7 +581,6 @@ tcp_sd = socket(pf, SOCK_STREAM, 0); if(tcp_sd < 0){ perror("socket"); - retval = -1; goto mandos_end; } @@ -583,12 +598,10 @@ } if(ret < 0 ){ perror("inet_pton"); - retval = -1; goto mandos_end; } if(ret == 0){ fprintf(stderr, "Bad address: %s\n", ip); - retval = -1; goto mandos_end; } if(af == AF_INET6){ @@ -602,7 +615,6 @@ if(if_index == AVAHI_IF_UNSPEC){ fprintf(stderr, "An IPv6 link-local address is incomplete" " without a network interface\n"); - retval = -1; goto mandos_end; } /* Set the network interface number as scope */ @@ -661,7 +673,6 @@ } if(ret < 0){ perror("connect"); - retval = -1; goto mandos_end; } @@ -677,7 +688,6 @@ out_size - written)); if(ret == -1){ perror("write"); - retval = -1; goto mandos_end; } written += (size_t)ret; @@ -723,7 +733,6 @@ fprintf(stderr, "*** GnuTLS Handshake failed ***\n"); gnutls_perror(ret); } - retval = -1; goto mandos_end; } @@ -744,7 +753,6 @@ buffer_capacity); if(buffer_capacity == 0){ perror("incbuffer"); - retval = -1; goto mandos_end; } @@ -773,14 +781,12 @@ if(ret < 0){ fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n"); gnutls_perror(ret); - retval = -1; goto mandos_end; } break; default: fprintf(stderr, "Unknown error while reading data from" " encrypted session with Mandos server\n"); - retval = -1; gnutls_bye(session, GNUTLS_SHUT_RDWR); goto mandos_end; } @@ -797,11 +803,12 @@ goto mandos_end; } - gnutls_bye(session, GNUTLS_SHUT_RDWR); - - if(quit_now){ - goto mandos_end; - } + do { + ret = gnutls_bye(session, GNUTLS_SHUT_RDWR); + if(quit_now){ + goto mandos_end; + } + } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED); if(buffer_length > 0){ ssize_t decrypted_buffer_size; @@ -824,22 +831,18 @@ fprintf(stderr, "Error writing encrypted data: %s\n", strerror(errno)); } - retval = -1; - break; + goto mandos_end; } written += (size_t)ret; } - free(decrypted_buffer); - } else { - retval = -1; + retval = 0; } - } else { - retval = -1; } /* Shutdown procedure */ mandos_end: + free(decrypted_buffer); free(buffer); if(tcp_sd >= 0){ ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd)); @@ -995,9 +998,30 @@ bool gpgme_initialized = false; float delay = 2.5f; - struct sigaction old_sigterm_action; + 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, @@ -1187,6 +1211,13 @@ 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 to mess up the prompt */ @@ -1210,6 +1241,12 @@ } } #endif /* __linux__ */ + /* Lower privileges */ + errno = 0; + ret = seteuid(uid); + if(ret == -1){ + perror("seteuid"); + } goto end; } strcpy(network.ifr_name, interface); @@ -1225,6 +1262,12 @@ } #endif /* __linux__ */ exitcode = EXIT_FAILURE; + /* Lower privileges */ + errno = 0; + ret = seteuid(uid); + if(ret == -1){ + perror("seteuid"); + } goto end; } if((network.ifr_flags & IFF_UP) == 0){ @@ -1243,6 +1286,12 @@ } } #endif /* __linux__ */ + /* Lower privileges */ + errno = 0; + ret = seteuid(uid); + if(ret == -1){ + perror("seteuid"); + } goto end; } } @@ -1276,24 +1325,21 @@ } } #endif /* __linux__ */ - } - - if(quit_now){ - goto end; - } - - uid = getuid(); - gid = getgid(); - - errno = 0; - setgid(gid); - if(ret == -1){ - perror("setgid"); - } - - ret = setuid(uid); - if(ret == -1){ - perror("setuid"); + /* 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){ @@ -1473,19 +1519,33 @@ /* Take down the network interface */ if(take_down_interface){ - ret = ioctl(sd, SIOCGIFFLAGS, &network); + /* Re-raise priviliges */ + errno = 0; + ret = seteuid(0); if(ret == -1){ - perror("ioctl SIOCGIFFLAGS"); - } else if(network.ifr_flags & IFF_UP) { - network.ifr_flags &= ~IFF_UP; /* clear flag */ - ret = ioctl(sd, SIOCSIFFLAGS, &network); - if(ret == -1){ - perror("ioctl SIOCSIFFLAGS"); - } + perror("seteuid"); } - ret = (int)TEMP_FAILURE_RETRY(close(sd)); - if(ret == -1){ - perror("close"); + if(geteuid() == 0){ + ret = ioctl(sd, SIOCGIFFLAGS, &network); + if(ret == -1){ + perror("ioctl SIOCGIFFLAGS"); + } else if(network.ifr_flags & IFF_UP) { + network.ifr_flags &= ~IFF_UP; /* clear flag */ + ret = ioctl(sd, SIOCSIFFLAGS, &network); + if(ret == -1){ + perror("ioctl SIOCSIFFLAGS"); + } + } + 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"); + } } } @@ -1536,11 +1596,20 @@ if(quit_now){ sigemptyset(&old_sigterm_action.sa_mask); old_sigterm_action.sa_handler = SIG_DFL; - ret = sigaction(signal_received, &old_sigterm_action, NULL); + ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received, + &old_sigterm_action, + NULL)); if(ret == -1){ perror("sigaction"); } - raise(signal_received); + do { + ret = raise(signal_received); + } while(ret != 0 and errno == EINTR); + if(ret != 0){ + perror("raise"); + abort(); + } + TEMP_FAILURE_RETRY(pause()); } return exitcode; === modified file 'plugins.d/password-prompt.c' --- plugins.d/password-prompt.c 2009-09-21 13:13:47 +0000 +++ plugins.d/password-prompt.c 2009-09-21 13:51:11 +0000 @@ -190,7 +190,7 @@ } t_new = t_old; - t_new.c_lflag &= ~ECHO; + t_new.c_lflag &= ~(tcflag_t)ECHO; if(tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){ perror("tcsetattr-echo"); return EXIT_FAILURE; === modified file 'plugins.d/splashy.c' --- plugins.d/splashy.c 2009-09-07 07:48:59 +0000 +++ plugins.d/splashy.c 2009-09-16 23:28:39 +0000 @@ -172,17 +172,17 @@ new_action = { .sa_handler = termination_handler, .sa_flags = 0 }; sigemptyset(&new_action.sa_mask); - sigaddset(&new_action.sa_mask, SIGINT); - if(ret == -1){ - perror("sigaddset"); - goto failure; - } - sigaddset(&new_action.sa_mask, SIGHUP); - if(ret == -1){ - perror("sigaddset"); - goto failure; - } - sigaddset(&new_action.sa_mask, SIGTERM); + ret = sigaddset(&new_action.sa_mask, SIGINT); + if(ret == -1){ + perror("sigaddset"); + goto failure; + } + ret = sigaddset(&new_action.sa_mask, SIGHUP); + if(ret == -1){ + perror("sigaddset"); + goto failure; + } + ret = sigaddset(&new_action.sa_mask, SIGTERM); if(ret == -1){ perror("sigaddset"); goto failure; @@ -298,7 +298,7 @@ TEMP_FAILURE_RETRY(kill(splashy_pid, SIGKILL)); sleep(1); } - pid_t new_splashy_pid = TEMP_FAILURE_RETRY(fork()); + pid_t new_splashy_pid = (pid_t)TEMP_FAILURE_RETRY(fork()); if(new_splashy_pid == 0){ /* Child; will become new splashy process */ @@ -333,8 +333,8 @@ struct sigaction signal_action; sigemptyset(&signal_action.sa_mask); signal_action.sa_handler = SIG_DFL; - ret = TEMP_FAILURE_RETRY(sigaction(signal_received, - &signal_action, NULL)); + ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received, + &signal_action, NULL)); if(ret == -1){ perror("sigaction"); } === modified file 'plugins.d/usplash.c' --- plugins.d/usplash.c 2009-09-07 23:50:12 +0000 +++ plugins.d/usplash.c 2009-09-21 13:51:11 +0000 @@ -22,7 +22,7 @@ * Contact the authors at . */ -#define _GNU_SOURCE /* asprintf() */ +#define _GNU_SOURCE /* asprintf(), TEMP_FAILURE_RETRY() */ #include /* sig_atomic_t, struct sigaction, sigemptyset(), sigaddset(), SIGINT, SIGHUP, SIGTERM, sigaction(), @@ -49,39 +49,46 @@ #include /* struct stat, lstat(), S_ISLNK */ sig_atomic_t interrupted_by_signal = 0; +int signal_received; +const char usplash_name[] = "/sbin/usplash"; -static void termination_handler(__attribute__((unused))int signum){ +static void termination_handler(int signum){ + if(interrupted_by_signal){ + return; + } interrupted_by_signal = 1; + signal_received = signum; } -static bool usplash_write(const char *cmd, const char *arg){ +static bool usplash_write(int *fifo_fd_r, + const char *cmd, const char *arg){ /* - * usplash_write("TIMEOUT", "15") will write "TIMEOUT 15\0" - * usplash_write("PULSATE", NULL) will write "PULSATE\0" + * usplash_write(&fd, "TIMEOUT", "15") will write "TIMEOUT 15\0" + * usplash_write(&fd, "PULSATE", NULL) will write "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)){ + if(*fifo_fd_r == -1){ + ret = open("/dev/.initramfs/usplash_fifo", O_WRONLY); + if(ret == -1){ return false; } - } while(fifo_fd == -1); + *fifo_fd_r = ret; + } 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); + cmd_line_len = strlen(cmd) + 1; } else { do { ret = asprintf(&cmd_line_alloc, "%s %s", cmd, arg); - if(ret == -1 and (errno != EINTR or interrupted_by_signal)){ + if(ret == -1){ int e = errno; - close(fifo_fd); + TEMP_FAILURE_RETRY(close(*fifo_fd_r)); errno = e; return false; } @@ -92,199 +99,216 @@ size_t written = 0; ssize_t sret = 0; - while(not interrupted_by_signal and written < cmd_line_len){ - sret = write(fifo_fd, cmd_line + written, + while(written < cmd_line_len){ + sret = write(*fifo_fd_r, cmd_line + written, cmd_line_len - written); if(sret == -1){ - if(errno != EINTR or interrupted_by_signal){ - int e = errno; - close(fifo_fd); - free(cmd_line_alloc); - errno = e; - return false; - } else { - continue; - } + int e = errno; + TEMP_FAILURE_RETRY(close(*fifo_fd_r)); + free(cmd_line_alloc); + errno = e; + return false; } written += (size_t)sret; } 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; + char *cmdline = NULL; + size_t cmdline_len = 0; + DIR *proc_dir = opendir("/proc"); + if(proc_dir == NULL){ + perror("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){ + /* 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){ + perror("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; + } + perror("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; + { + char *cmdline_filename; + ret = asprintf(&cmdline_filename, "/proc/%s/cmdline", + proc_ent->d_name); + if(ret == -1){ + perror("asprintf"); + goto fail_find_usplash; + } + cl_fd = open(cmdline_filename, O_RDONLY); + free(cmdline_filename); + if(cl_fd == -1){ + perror("open"); + goto fail_find_usplash; + } + } + 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){ + perror("realloc"); + close(cl_fd); + goto fail_find_usplash; + } + cmdline = tmp; + cmdline_allocated += blocksize; + } + /* Read data */ + sret = read(cl_fd, cmdline + cmdline_len, + cmdline_allocated - cmdline_len); + if(sret == -1){ + perror("read"); + close(cl_fd); + goto fail_find_usplash; + } + cmdline_len += (size_t)sret; + } while(sret != 0); + ret = close(cl_fd); + if(ret == -1){ + perror("close"); + goto fail_find_usplash; + } + } + /* Close directory */ + ret = closedir(proc_dir); + if(ret == -1){ + perror("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; - bool an_error_occured = false; + 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; - /* 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; - } + char *prompt = makeprompt(); + if(prompt == NULL){ + goto 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; - { - 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; - } - /* 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){ - 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; - } - 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 == ((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); - } + usplash_pid = find_usplash(&cmdline, &cmdline_len); if(usplash_pid == 0){ - free(prompt); - return EXIT_FAILURE; + goto failure; } /* Set up the signal handler */ @@ -293,172 +317,231 @@ 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 = sigaddset(&new_action.sa_mask, SIGINT); + if(ret == -1){ + perror("sigaddset"); + goto failure; + } + ret = sigaddset(&new_action.sa_mask, SIGHUP); + if(ret == -1){ + perror("sigaddset"); + goto failure; + } + ret = sigaddset(&new_action.sa_mask, SIGTERM); + if(ret == -1){ + perror("sigaddset"); + goto failure; + } ret = sigaction(SIGINT, NULL, &old_action); if(ret == -1){ - perror("sigaction"); - free(prompt); - return EXIT_FAILURE; + if(errno != EINTR){ + perror("sigaction"); + } + goto failure; } if(old_action.sa_handler != SIG_IGN){ ret = sigaction(SIGINT, &new_action, NULL); if(ret == -1){ - perror("sigaction"); - free(prompt); - return EXIT_FAILURE; + if(errno != EINTR){ + perror("sigaction"); + } + goto failure; } } ret = sigaction(SIGHUP, NULL, &old_action); if(ret == -1){ - perror("sigaction"); - free(prompt); - return EXIT_FAILURE; + if(errno != EINTR){ + perror("sigaction"); + } + goto failure; } if(old_action.sa_handler != SIG_IGN){ ret = sigaction(SIGHUP, &new_action, NULL); if(ret == -1){ - perror("sigaction"); - free(prompt); - return EXIT_FAILURE; + if(errno != EINTR){ + perror("sigaction"); + } + goto failure; } } ret = sigaction(SIGTERM, NULL, &old_action); if(ret == -1){ - perror("sigaction"); - free(prompt); - return EXIT_FAILURE; + if(errno != EINTR){ + perror("sigaction"); + } + goto failure; } if(old_action.sa_handler != SIG_IGN){ ret = sigaction(SIGTERM, &new_action, NULL); if(ret == -1){ - perror("sigaction"); - free(prompt); - return EXIT_FAILURE; + if(errno != EINTR){ + perror("sigaction"); + } + goto failure; } } } + usplash_accessed = true; /* 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; - } - } + if(not usplash_write(&fifo_fd, "TIMEOUT", "0")){ + if(errno != EINTR){ + perror("usplash_write"); + } + goto failure; + } + + if(interrupted_by_signal){ + goto failure; + } + + if(not usplash_write(&fifo_fd, "INPUTQUIET", prompt)){ + if(errno != EINTR){ + perror("usplash_write"); + } + goto failure; + } + + if(interrupted_by_signal){ + goto failure; + } + 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){ + prompt = NULL; + + /* Read reply from usplash */ + /* Open FIFO */ + outfifo_fd = open("/dev/.initramfs/usplash_outfifo", O_RDONLY); + if(outfifo_fd == -1){ + if(errno != EINTR){ + perror("open"); + } + 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); + if(tmp == NULL){ 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 */ + } + goto failure; + } + buf = tmp; + buf_allocated += blocksize; + } + sret = read(outfifo_fd, buf + buf_len, + buf_allocated - buf_len); + if(sret == -1){ + if(errno != EINTR){ + perror("read"); + } + 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){ + perror("close"); + } + goto failure; + } + outfifo_fd = -1; + + if(interrupted_by_signal){ + goto failure; + } + + if(not usplash_write(&fifo_fd, "TIMEOUT", "15")){ + if(errno != EINTR){ + perror("usplash_write"); + } + goto failure; + } + + if(interrupted_by_signal){ + goto failure; + } + + ret = close(fifo_fd); + if(ret == -1){ + if(errno != EINTR){ + perror("close"); + } + 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){ + perror("write"); + } + 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 EXIT_FAILURE; + } + + /* Close FIFO */ + if(fifo_fd != -1){ + ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd)); + if(ret == -1 and errno != EINTR){ + perror("close"); + } + fifo_fd = -1; + } + + /* Close output FIFO */ + if(outfifo_fd != -1){ + ret = (int)TEMP_FAILURE_RETRY(close(outfifo_fd)); + if(ret == -1){ + perror("close"); + } + } /* Create argc and argv for new usplash*/ int cmdline_argc = 0; @@ -488,6 +571,7 @@ kill(usplash_pid, SIGKILL); sleep(1); } + pid_t new_usplash_pid = fork(); if(new_usplash_pid == 0){ /* Child; will become new usplash process */ @@ -521,9 +605,37 @@ free(cmdline); free(cmdline_argv); sleep(2); - if(not usplash_write("PULSATE", NULL) - and (errno != EINTR)){ - perror("usplash_write"); + if(not usplash_write(&fifo_fd, "PULSATE", NULL)){ + if(errno != EINTR){ + perror("usplash_write"); + } + } + + /* Close FIFO (again) */ + if(fifo_fd != -1){ + ret = (int)TEMP_FAILURE_RETRY(close(fifo_fd)); + if(ret == -1 and errno != EINTR){ + perror("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){ + perror("sigaction"); + } + do { + ret = raise(signal_received); + } while(ret != 0 and errno == EINTR); + if(ret != 0){ + perror("raise"); + abort(); + } + TEMP_FAILURE_RETRY(pause()); } return EXIT_FAILURE;