=== modified file 'Makefile' --- Makefile 2014-02-16 13:12:20 +0000 +++ Makefile 2014-03-28 21:31:12 +0000 @@ -1,14 +1,17 @@ -WARN=-O -Wall -Wformat=2 -Winit-self -Wmissing-include-dirs \ - -Wswitch-default -Wswitch-enum -Wunused-parameter \ - -Wstrict-aliasing=1 -Wextra -Wfloat-equal -Wundef -Wshadow \ +WARN=-O -Wall -Wextra -Wdouble-promotion -Wformat=2 -Winit-self \ + -Wmissing-include-dirs -Wswitch-default -Wswitch-enum \ + -Wunused -Wuninitialized -Wstrict-overflow=5 \ + -Wsuggest-attribute=pure -Wsuggest-attribute=const \ + -Wsuggest-attribute=noreturn -Wfloat-equal -Wundef -Wshadow \ -Wunsafe-loop-optimizations -Wpointer-arith \ -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings \ - -Wconversion -Wstrict-prototypes -Wold-style-definition \ - -Wpacked -Wnested-externs -Winline -Wvolatile-register-var -# -Wunreachable-code + -Wconversion -Wlogical-op -Waggregate-return \ + -Wstrict-prototypes -Wold-style-definition \ + -Wmissing-format-attribute -Wnormalized=nfc -Wpacked \ + -Wredundant-decls -Wnested-externs -Winline -Wvla \ + -Wvolatile-register-var -Woverlength-strings #DEBUG=-ggdb3 -# For info about _FORTIFY_SOURCE, see -# +# For info about _FORTIFY_SOURCE, see feature_test_macros(7) # and . FORTIFY=-D_FORTIFY_SOURCE=2 -fstack-protector-all -fPIC LINK_FORTIFY_LD=-z relro -z now @@ -20,7 +23,7 @@ LINK_FORTIFY += -pie endif #COVERAGE=--coverage -OPTIMIZE=-Os +OPTIMIZE=-Os -fno-strict-aliasing LANGUAGE=-std=gnu99 htmldir=man version=1.6.4 @@ -82,13 +85,10 @@ --param man.authors.section.enabled 0 \ /usr/share/xml/docbook/stylesheet/nwalsh/manpages/docbook.xsl \ $(notdir $<); \ - $(MANPOST) $(notdir $@);\ if locale --all 2>/dev/null | grep --regexp='^en_US\.utf8$$' \ && type man 2>/dev/null; then LANG=en_US.UTF-8 MANWIDTH=80 \ man --warnings --encoding=UTF-8 --local-file $(notdir $@); \ fi >/dev/null) -# DocBook-to-man post-processing to fix a '\n' escape bug -MANPOST=$(SED) --in-place --expression='s,\\\\en,\\en,g;s,\\n,\\en,g' DOCBOOKTOHTML=$(strip xsltproc --nonet --xinclude \ --param make.year.ranges 1 \ @@ -239,9 +239,11 @@ $(LINK.c) $^ -lrt $(GNUTLS_LIBS) $(AVAHI_LIBS) $(strip\ ) $(GPGME_LIBS) $(LOADLIBES) $(LDLIBS) -o $@ -.PHONY : all doc html clean distclean run-client run-server install \ - install-server install-client uninstall uninstall-server \ - uninstall-client purge purge-server purge-client +.PHONY : all doc html clean distclean mostlyclean maintainer-clean \ + check run-client run-server install install-html \ + install-server install-client-nokey install-client uninstall \ + uninstall-server uninstall-client purge purge-server \ + purge-client clean: -rm --force $(CPROGS) $(objects) $(htmldocs) $(DOCS) core === modified file 'TODO' --- TODO 2014-01-20 20:54:47 +0000 +++ TODO 2014-03-27 21:24:33 +0000 @@ -21,10 +21,7 @@ * mandos-client ** TODO [#B] Use capabilities instead of seteuid(). -** TODO [#B] Use struct sockaddr_storage instead of a union ** TODO [#B] Use getaddrinfo(hints=AI_NUMERICHOST) instead of inet_pton() -** TODO [#B] Use getnameinfo(serv=NULL, NI_NUMERICHOST) instead of inet_ntop() -** TODO [#B] Prefer /run/tmp over /tmp, if it exists ** TODO [#C] Make start_mandos_communication() take "struct server". * splashy @@ -47,10 +44,10 @@ * plugin-runner ** TODO handle printing for errors for plugins *** Hook up stderr of plugins, buffer them, and prepend "Mandos Plugin [plugin name]" -** TODO [#B] use scandir(3) instead of readdir(3) +** TODO [#B] use scandirat(3) instead of readdir(3) +*** Must wait until GNU libc 2.15 ** TODO [#C] use same file name rules as run-parts(8) ** kernel command line option for debug info -** TODO [#B] Use openat() * mandos (server) ** TODO [#B] Log level :BUGS: @@ -114,10 +111,6 @@ ** TODO [#B] "--test" option For testing decryption before rebooting. -* Makefile -** TODO [#C] 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 'debian/control' --- debian/control 2014-02-16 02:42:42 +0000 +++ debian/control 2014-05-11 20:09:27 +0000 @@ -6,9 +6,11 @@ Björn Påhlsson Build-Depends: debhelper (>= 9), docbook-xml, docbook-xsl, libavahi-core-dev, libgpgme11-dev, libgnutls-dev, xsltproc, - pkg-config, systemd, python (>=2.6), python-gnutls, python-dbus, - python-avahi, python-gobject, python (>=2.7) | python-argparse -Standards-Version: 3.9.4 + pkg-config +Build-Depends-Indep: systemd, python (>=2.6), python-gnutls, + python-dbus, python-avahi, python-gobject, + python (>=2.7) | python-argparse +Standards-Version: 3.9.5 Vcs-Bzr: http://ftp.recompile.se/pub/mandos/trunk Vcs-Browser: http://bzr.recompile.se/loggerhead/mandos/trunk/files Homepage: http://www.recompile.se/mandos @@ -18,8 +20,7 @@ Depends: ${misc:Depends}, python (>=2.6), python-gnutls, python-dbus, python-avahi, python-gobject, avahi-daemon, adduser, python-urwid, python (>=2.7) | python-argparse, gnupg (<< 2), - initscripts (>= 2.88dsf-13.3), avahi-daemon (>= 0.6.31-3) - | systemd-sysv + initscripts (>= 2.88dsf-13.3) Recommends: fping Description: server giving encrypted passwords to Mandos clients This is the server part of the Mandos system, which allows === modified file 'debian/copyright' --- debian/copyright 2014-02-16 02:42:42 +0000 +++ debian/copyright 2014-03-01 09:39:25 +0000 @@ -4,8 +4,8 @@ Source: Files: * -Copyright: Copyright © 2008-2013 Teddy Hogeborn - Copyright © 2008-2013 Björn Påhlsson +Copyright: Copyright © 2008-2014 Teddy Hogeborn + Copyright © 2008-2014 Björn Påhlsson License: GPL-3+ This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as === added directory 'debian/upstream' === added file 'debian/upstream/signing-key.asc' --- debian/upstream/signing-key.asc 1970-01-01 00:00:00 +0000 +++ debian/upstream/signing-key.asc 2014-03-28 22:32:21 +0000 @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- +Version: GnuPG v1.4.12 (GNU/Linux) + +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 +6vKRsaQikZujRdP9Dkf0mLmJ7LANWw== +=9Noe +-----END PGP PUBLIC KEY BLOCK----- === modified file 'mandos' --- mandos 2014-02-16 13:12:20 +0000 +++ mandos 2014-02-22 17:13:00 +0000 @@ -1352,11 +1352,7 @@ *args, **kwargs) def start_checker(self, *args, **kwargs): - old_checker = self.checker - if self.checker is not None: - old_checker_pid = self.checker.pid - else: - old_checker_pid = None + old_checker_pid = getattr(self.checker, "pid", None) r = Client.start_checker(self, *args, **kwargs) # Only if new checker process was started if (self.checker is not None === modified file 'mandos-ctl' --- mandos-ctl 2014-02-16 13:12:20 +0000 +++ mandos-ctl 2014-03-01 09:39:25 +0000 @@ -3,8 +3,8 @@ # # Mandos Monitor - Control and monitor the Mandos server # -# Copyright © 2008-2012 Teddy Hogeborn -# Copyright © 2008-2012 Björn Påhlsson +# Copyright © 2008-2014 Teddy Hogeborn +# Copyright © 2008-2014 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 2014-02-16 13:12:20 +0000 +++ mandos-keygen 2014-03-29 02:38:15 +0000 @@ -2,8 +2,8 @@ # # Mandos key generator - create a new OpenPGP key for a Mandos client # -# Copyright © 2008-2013 Teddy Hogeborn -# Copyright © 2008-2013 Björn Påhlsson +# Copyright © 2008-2014 Teddy Hogeborn +# Copyright © 2008-2014 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 @@ -228,6 +228,11 @@ date fi + # Make sure trustdb.gpg exists; + # this is a workaround for Debian bug #737128 + gpg --quiet --batch --no-tty --no-options --enable-dsa2 \ + --homedir "$RINGDIR" \ + --import-ownertrust < /dev/null # Generate a new key in the key rings gpg --quiet --batch --no-tty --no-options --enable-dsa2 \ --homedir "$RINGDIR" --trust-model always \ === modified file 'mandos-monitor' --- mandos-monitor 2014-02-16 13:12:20 +0000 +++ mandos-monitor 2014-03-01 09:39:25 +0000 @@ -3,8 +3,8 @@ # # Mandos Monitor - Control and monitor the Mandos server # -# Copyright © 2009-2013 Teddy Hogeborn -# Copyright © 2009-2013 Björn Påhlsson +# Copyright © 2009-2014 Teddy Hogeborn +# Copyright © 2009-2014 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 @@ -32,7 +32,6 @@ import sys import os -import signal import datetime === modified file 'mandos.lsm' --- mandos.lsm 2014-02-16 13:12:20 +0000 +++ mandos.lsm 2014-02-16 14:22:03 +0000 @@ -3,10 +3,10 @@ Version: 1.6.4 Entered-date: 2014-02-16 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. + root file systems and at the same time be capable of + remote and/or unattended reboots. Keywords: boot, encryption, luks, cryptsetup, network, openpgp, -tls, dm-crypt + tls, dm-crypt Author: teddy@recompile.se (Teddy Hogeborn), belorn@recompile.se (Björn Påhlsson) Maintained-by: teddy@recompile.se (Teddy Hogeborn), @@ -16,7 +16,8 @@ Alternate-site: ftp://ftp.recompile.se/pub/mandos 158K mandos_1.6.4.orig.tar.gz Platforms: Requires GCC, GNU libC, Avahi, GnuPG, Python 2.6, and -various other libraries. While made for Debian GNU/Linux, it is -probably portable to other distributions, but not other Unixes. + various other libraries. While made for Debian + GNU/Linux, it is probably portable to other + distributions, but not other Unixes. Copying-policy: GNU General Public License version 3.0 or later End === modified file 'plugin-runner.c' --- plugin-runner.c 2013-12-15 22:21:28 +0000 +++ plugin-runner.c 2014-03-29 02:38:15 +0000 @@ -2,8 +2,8 @@ /* * Mandos plugin runner - Run Mandos plugins * - * Copyright © 2008-2013 Teddy Hogeborn - * Copyright © 2008-2013 Björn Påhlsson + * Copyright © 2008-2014 Teddy Hogeborn + * Copyright © 2008-2014 Björn Påhlsson * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -23,14 +23,14 @@ */ #define _GNU_SOURCE /* TEMP_FAILURE_RETRY(), getline(), - asprintf(), O_CLOEXEC */ + O_CLOEXEC */ #include /* size_t, NULL */ #include /* malloc(), exit(), EXIT_SUCCESS, realloc() */ #include /* bool, true, false */ #include /* fileno(), fprintf(), - stderr, STDOUT_FILENO */ -#include /* DIR, fdopendir(), stat(), struct + stderr, STDOUT_FILENO, fclose() */ +#include /* DIR, fdopendir(), fstat(), struct stat, waitpid(), WIFEXITED(), WEXITSTATUS(), wait(), pid_t, uid_t, gid_t, getuid(), getgid(), @@ -40,21 +40,21 @@ #include /* wait(), waitpid(), WIFEXITED(), WEXITSTATUS(), WTERMSIG(), WCOREDUMP() */ -#include /* struct stat, stat(), S_ISREG() */ +#include /* struct stat, fstat(), S_ISREG() */ #include /* and, or, not */ #include /* DIR, struct dirent, fdopendir(), readdir(), closedir(), dirfd() */ -#include /* struct stat, stat(), S_ISREG(), - fcntl(), setuid(), setgid(), - F_GETFD, F_SETFD, FD_CLOEXEC, - access(), pipe(), fork(), close() - dup2(), STDOUT_FILENO, _exit(), - execv(), write(), read(), - close() */ +#include /* fcntl(), F_GETFD, F_SETFD, + FD_CLOEXEC, write(), STDOUT_FILENO, + struct stat, fstat(), close(), + setgid(), setuid(), S_ISREG(), + faccessat() pipe(), fork(), + _exit(), dup2(), fexecve(), read() + */ #include /* fcntl(), F_GETFD, F_SETFD, - FD_CLOEXEC */ -#include /* strsep, strlen(), asprintf(), - strsignal(), strcmp(), strncmp() */ + FD_CLOEXEC, openat() */ +#include /* strsep, strlen(), strsignal(), + strcmp(), strncmp() */ #include /* errno */ #include /* struct argp_option, struct argp_state, struct argp, @@ -72,6 +72,7 @@ EX_CONFIG, EX_UNAVAILABLE, EX_OK */ #include /* errno */ #include /* error() */ +#include /* fnmatch() */ #define BUFFER_SIZE 256 @@ -105,6 +106,7 @@ /* Gets an existing plugin based on name, or if none is found, creates a new one */ +__attribute__((warn_unused_result)) static plugin *getplugin(char *name){ /* Check for existing plugin with that name */ for(plugin *p = plugin_list; p != NULL; p = p->next){ @@ -171,18 +173,20 @@ } /* Helper function for add_argument and add_environment */ -__attribute__((nonnull)) +__attribute__((nonnull, warn_unused_result)) static bool add_to_char_array(const char *new, char ***array, int *len){ /* Resize the pointed-to array to hold one more pointer */ + char **new_array = NULL; do { - *array = realloc(*array, sizeof(char *) - * (size_t) ((*len) + 2)); - } while(*array == NULL and errno == EINTR); + new_array = realloc(*array, sizeof(char *) + * (size_t) ((*len) + 2)); + } while(new_array == NULL and errno == EINTR); /* Malloc check */ - if(*array == NULL){ + if(new_array == NULL){ return false; } + *array = new_array; /* Make a copy of the new string */ char *copy; do { @@ -200,7 +204,7 @@ } /* Add to a plugin's argument vector */ -__attribute__((nonnull(2))) +__attribute__((nonnull(2), warn_unused_result)) static bool add_argument(plugin *p, const char *arg){ if(p == NULL){ return false; @@ -209,7 +213,7 @@ } /* Add to a plugin's environment */ -__attribute__((nonnull(2))) +__attribute__((nonnull(2), warn_unused_result)) static bool add_environment(plugin *p, const char *def, bool replace){ if(p == NULL){ return false; @@ -217,19 +221,19 @@ /* namelen = length of name of environment variable */ size_t namelen = (size_t)(strchrnul(def, '=') - def); /* Search for this environment variable */ - for(char **e = p->environ; *e != NULL; e++){ - if(strncmp(*e, def, namelen + 1) == 0){ + for(char **envdef = p->environ; *envdef != NULL; envdef++){ + if(strncmp(*envdef, def, namelen + 1) == 0){ /* It already exists */ if(replace){ - char *new; + char *new_envdef; do { - new = realloc(*e, strlen(def) + 1); - } while(new == NULL and errno == EINTR); - if(new == NULL){ + new_envdef = realloc(*envdef, strlen(def) + 1); + } while(new_envdef == NULL and errno == EINTR); + if(new_envdef == NULL){ return false; } - *e = new; - strcpy(*e, def); + *envdef = new_envdef; + strcpy(*envdef, def); } return true; } @@ -242,6 +246,7 @@ * Descriptor Flags". | [[info:libc:Descriptor%20Flags][File Descriptor Flags]] | */ +__attribute__((warn_unused_result)) static int set_cloexec_flag(int fd){ int ret = (int)TEMP_FAILURE_RETRY(fcntl(fd, F_GETFD, 0)); /* If reading the flags failed, return error indication now. */ @@ -289,7 +294,7 @@ } /* Prints out a password to stdout */ -__attribute__((nonnull)) +__attribute__((nonnull, warn_unused_result)) static bool print_out_password(const char *buffer, size_t length){ ssize_t ret; for(size_t written = 0; written < length; written += (size_t)ret){ @@ -343,7 +348,6 @@ char *plugindir = NULL; char *argfile = NULL; FILE *conffp; - size_t d_name_len; DIR *dir = NULL; struct dirent *dirst; struct stat st; @@ -359,6 +363,7 @@ .sa_flags = SA_NOCLDSTOP }; char **custom_argv = NULL; int custom_argc = 0; + int dir_fd; /* Establish a signal handler */ sigemptyset(&sigchld_action.sa_mask); @@ -435,10 +440,13 @@ break; } } + errno = 0; } break; case 'G': /* --global-env */ - add_environment(getplugin(NULL), arg, true); + if(add_environment(getplugin(NULL), arg, true)){ + errno = 0; + } break; case 'o': /* --options-for */ { @@ -461,6 +469,7 @@ break; } } + errno = 0; } break; case 'E': /* --env-for */ @@ -478,7 +487,9 @@ errno = EINVAL; break; } - add_environment(getplugin(arg), envdef, true); + if(add_environment(getplugin(arg), envdef, true)){ + errno = 0; + } } break; case 'd': /* --disable */ @@ -486,6 +497,7 @@ plugin *p = getplugin(arg); if(p != NULL){ p->disabled = true; + errno = 0; } } break; @@ -494,12 +506,16 @@ plugin *p = getplugin(arg); if(p != NULL){ p->disabled = false; + errno = 0; } } break; case 128: /* --plugin-dir */ free(plugindir); plugindir = strdup(arg); + if(plugindir != NULL){ + errno = 0; + } break; case 129: /* --config-file */ /* This is already done by parse_opt_config_file() */ @@ -513,6 +529,7 @@ break; } uid = (uid_t)tmp_id; + errno = 0; break; case 131: /* --groupid */ tmp_id = strtoimax(arg, &tmp, 10); @@ -523,6 +540,7 @@ break; } gid = (gid_t)tmp_id; + errno = 0; break; case 132: /* --debug */ debug = true; @@ -576,6 +594,9 @@ case 129: /* --config-file */ free(argfile); argfile = strdup(arg); + if(argfile != NULL){ + errno = 0; + } break; case 130: /* --userid */ case 131: /* --groupid */ @@ -664,13 +685,19 @@ } custom_argc += 1; - custom_argv = realloc(custom_argv, sizeof(char *) - * ((unsigned int) custom_argc + 1)); - if(custom_argv == NULL){ - error(0, errno, "realloc"); - exitstatus = EX_OSERR; - free(org_line); - goto fallback; + { + char **new_argv = realloc(custom_argv, sizeof(char *) + * ((unsigned int) + custom_argc + 1)); + if(new_argv == NULL){ + error(0, errno, "realloc"); + exitstatus = EX_OSERR; + free(new_arg); + free(org_line); + goto fallback; + } else { + custom_argv = new_argv; + } } custom_argv[custom_argc-1] = new_arg; custom_argv[custom_argc] = NULL; @@ -753,7 +780,9 @@ */ int plugindir_fd = open(/* plugindir or */ PDIR, O_RDONLY); if(plugindir_fd == -1){ - error(0, errno, "open"); + if(errno != ENOENT){ + error(0, errno, "open(\"" PDIR "\")"); + } } else { ret = (int)TEMP_FAILURE_RETRY(fstat(plugindir_fd, &st)); if(ret == -1){ @@ -782,24 +811,13 @@ /* Open plugin directory with close_on_exec flag */ { - int dir_fd = -1; - if(plugindir == NULL){ - dir_fd = open(PDIR, O_RDONLY | -#ifdef O_CLOEXEC - O_CLOEXEC -#else /* not O_CLOEXEC */ - 0 -#endif /* not O_CLOEXEC */ - ); - } else { - dir_fd = open(plugindir, O_RDONLY | -#ifdef O_CLOEXEC - O_CLOEXEC -#else /* not O_CLOEXEC */ - 0 -#endif /* not O_CLOEXEC */ - ); - } + dir_fd = open(plugindir != NULL ? plugindir : PDIR, O_RDONLY | +#ifdef O_CLOEXEC + O_CLOEXEC +#else /* not O_CLOEXEC */ + 0 +#endif /* not O_CLOEXEC */ + ); if(dir_fd == -1){ error(0, errno, "Could not open plugin dir"); exitstatus = EX_UNAVAILABLE; @@ -844,88 +862,81 @@ break; } - d_name_len = strlen(dirst->d_name); - /* Ignore dotfiles, backup files and other junk */ { bool bad_name = false; - - const char const *bad_prefixes[] = { ".", "#", NULL }; - - const char const *bad_suffixes[] = { "~", "#", ".dpkg-new", - ".dpkg-old", - ".dpkg-bak", - ".dpkg-divert", NULL }; - for(const char **pre = bad_prefixes; *pre != NULL; pre++){ - size_t pre_len = strlen(*pre); - if((d_name_len >= pre_len) - and strncmp((dirst->d_name), *pre, pre_len) == 0){ - if(debug){ - fprintf(stderr, "Ignoring plugin dir entry \"%s\"" - " with bad prefix %s\n", dirst->d_name, *pre); - } - bad_name = true; - break; - } - } - if(bad_name){ - continue; - } - for(const char **suf = bad_suffixes; *suf != NULL; suf++){ - size_t suf_len = strlen(*suf); - if((d_name_len >= suf_len) - and (strcmp((dirst->d_name) + d_name_len-suf_len, *suf) - == 0)){ - if(debug){ - fprintf(stderr, "Ignoring plugin dir entry \"%s\"" - " with bad suffix %s\n", dirst->d_name, *suf); - } - bad_name = true; - break; - } - } - + const char * const patterns[] = { ".*", "#*#", "*~", + "*.dpkg-new", "*.dpkg-old", + "*.dpkg-bak", "*.dpkg-divert", + NULL }; +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-qual" +#endif + for(const char **pat = (const char **)patterns; + *pat != NULL; pat++){ +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif + if(fnmatch(*pat, dirst->d_name, + FNM_FILE_NAME | FNM_PERIOD) != FNM_NOMATCH){ + if(debug){ + fprintf(stderr, "Ignoring plugin dir entry \"%s\"" + " matching pattern %s\n", dirst->d_name, *pat); + } + bad_name = true; + break; + } + } if(bad_name){ continue; } } - char *filename; - if(plugindir == NULL){ - ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, PDIR "/%s", - dirst->d_name)); - } else { - ret = (int)TEMP_FAILURE_RETRY(asprintf(&filename, "%s/%s", - plugindir, - dirst->d_name)); + int plugin_fd = openat(dir_fd, dirst->d_name, O_RDONLY | +#ifdef O_CLOEXEC + O_CLOEXEC +#else /* not O_CLOEXEC */ + 0 +#endif /* not O_CLOEXEC */ + ); + if(plugin_fd == -1){ + error(0, errno, "Could not open plugin"); + continue; } +#ifndef O_CLOEXEC + /* Set the FD_CLOEXEC flag on the plugin FD */ + ret = set_cloexec_flag(plugin_fd); if(ret < 0){ - error(0, errno, "asprintf"); + error(0, errno, "set_cloexec_flag"); + TEMP_FAILURE_RETRY(close(plugin_fd)); continue; } - - ret = (int)TEMP_FAILURE_RETRY(stat(filename, &st)); +#endif /* O_CLOEXEC */ + ret = (int)TEMP_FAILURE_RETRY(fstat(plugin_fd, &st)); if(ret == -1){ error(0, errno, "stat"); - free(filename); + TEMP_FAILURE_RETRY(close(plugin_fd)); continue; } /* Ignore non-executable files */ if(not S_ISREG(st.st_mode) - or (TEMP_FAILURE_RETRY(access(filename, X_OK)) != 0)){ + or (TEMP_FAILURE_RETRY(faccessat(dir_fd, dirst->d_name, X_OK, + 0)) != 0)){ if(debug){ - fprintf(stderr, "Ignoring plugin dir entry \"%s\"" - " with bad type or mode\n", filename); + fprintf(stderr, "Ignoring plugin dir entry \"%s/%s\"" + " with bad type or mode\n", + plugindir != NULL ? plugindir : PDIR, dirst->d_name); } - free(filename); + TEMP_FAILURE_RETRY(close(plugin_fd)); continue; } plugin *p = getplugin(dirst->d_name); if(p == NULL){ error(0, errno, "getplugin"); - free(filename); + TEMP_FAILURE_RETRY(close(plugin_fd)); continue; } if(p->disabled){ @@ -933,7 +944,7 @@ fprintf(stderr, "Ignoring disabled plugin \"%s\"\n", dirst->d_name); } - free(filename); + TEMP_FAILURE_RETRY(close(plugin_fd)); continue; } { @@ -953,9 +964,8 @@ } } } - /* If this plugin has any environment variables, we will call - using execve and need to duplicate the environment from this - process, too. */ + /* If this plugin has any environment variables, we need to + duplicate the environment from this process, too. */ if(p->environ[0] != NULL){ for(char **e = environ; *e != NULL; e++){ if(not add_environment(p, *e, false)){ @@ -1027,23 +1037,18 @@ above and must now close it manually here. */ closedir(dir); } - if(p->environ[0] == NULL){ - if(execv(filename, p->argv) < 0){ - error(0, errno, "execv for %s", filename); - _exit(EX_OSERR); - } - } else { - if(execve(filename, p->argv, p->environ) < 0){ - error(0, errno, "execve for %s", filename); - _exit(EX_OSERR); - } + if(fexecve(plugin_fd, p->argv, + (p->environ[0] != NULL) ? p->environ : environ) < 0){ + error(0, errno, "fexecve for %s/%s", + plugindir != NULL ? plugindir : PDIR, dirst->d_name); + _exit(EX_OSERR); } /* no return */ } /* Parent process */ TEMP_FAILURE_RETRY(close(pipefd[1])); /* Close unused write end of pipe */ - free(filename); + TEMP_FAILURE_RETRY(close(plugin_fd)); plugin *new_plugin = getplugin(dirst->d_name); if(new_plugin == NULL){ error(0, errno, "getplugin"); @@ -1226,13 +1231,14 @@ } /* Before reading, make the process' data buffer large enough */ if(proc->buffer_length + BUFFER_SIZE > proc->buffer_size){ - proc->buffer = realloc(proc->buffer, proc->buffer_size - + (size_t) BUFFER_SIZE); - if(proc->buffer == NULL){ + char *new_buffer = realloc(proc->buffer, proc->buffer_size + + (size_t) BUFFER_SIZE); + if(new_buffer == NULL){ error(0, errno, "malloc"); exitstatus = EX_OSERR; goto fallback; } + proc->buffer = new_buffer; proc->buffer_size += BUFFER_SIZE; } /* Read from the process */ === modified file 'plugins.d/askpass-fifo.c' --- plugins.d/askpass-fifo.c 2011-12-31 23:05:34 +0000 +++ plugins.d/askpass-fifo.c 2014-03-29 02:38:15 +0000 @@ -2,8 +2,8 @@ /* * Askpass-FIFO - Read a password from a FIFO and output it * - * Copyright © 2008-2012 Teddy Hogeborn - * Copyright © 2008-2012 Björn Påhlsson + * Copyright © 2008-2014 Teddy Hogeborn + * Copyright © 2008-2014 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 @@ -55,7 +55,7 @@ va_start(ap, formatstring); ret = vasprintf(&text, formatstring, ap); - if (ret == -1){ + if(ret == -1){ fprintf(stderr, "Mandos plugin %s: ", program_invocation_short_name); vfprintf(stderr, formatstring, ap); === modified file 'plugins.d/mandos-client.c' --- plugins.d/mandos-client.c 2013-12-15 22:21:28 +0000 +++ plugins.d/mandos-client.c 2014-03-29 05:16:37 +0000 @@ -9,8 +9,8 @@ * "browse_callback", and parts of "main". * * Everything else is - * Copyright © 2008-2013 Teddy Hogeborn - * Copyright © 2008-2013 Björn Påhlsson + * Copyright © 2008-2014 Teddy Hogeborn + * Copyright © 2008-2014 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 @@ -55,7 +55,8 @@ opendir(), DIR */ #include /* open(), S_ISREG */ #include /* socket(), struct sockaddr_in6, - inet_pton(), connect() */ + inet_pton(), connect(), + getnameinfo() */ #include /* open() */ #include /* opendir(), struct dirent, readdir() */ @@ -73,7 +74,7 @@ #include /* close(), SEEK_SET, off_t, write(), getuid(), getgid(), seteuid(), setgid(), pause(), _exit() */ -#include /* inet_pton(), htons, inet_ntop() */ +#include /* inet_pton(), htons() */ #include /* not, or, and */ #include /* struct argp_option, error_t, struct argp_state, struct argp, @@ -91,6 +92,8 @@ argz_delete(), argz_append(), argz_stringify(), argz_add(), argz_count() */ +#include /* getnameinfo(), NI_NUMERICHOST, + EAI_SYSTEM, gai_strerror() */ #ifdef __linux__ #include /* klogctl() */ @@ -180,7 +183,7 @@ perror(print_text); } -__attribute__((format (gnu_printf, 2, 3))) +__attribute__((format (gnu_printf, 2, 3), nonnull)) int fprintf_plus(FILE *stream, const char *format, ...){ va_list ap; va_start (ap, format); @@ -195,19 +198,26 @@ * bytes. "buffer_capacity" is how much is currently allocated, * "buffer_length" is how much is already used. */ +__attribute__((nonnull, warn_unused_result)) size_t incbuffer(char **buffer, size_t buffer_length, size_t buffer_capacity){ if(buffer_length + BUFFER_SIZE > buffer_capacity){ - *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE); - if(buffer == NULL){ + char *new_buf = realloc(*buffer, buffer_capacity + BUFFER_SIZE); + if(new_buf == NULL){ + int old_errno = errno; + free(*buffer); + errno = old_errno; + *buffer = NULL; return 0; } + *buffer = new_buf; buffer_capacity += BUFFER_SIZE; } return buffer_capacity; } /* Add server to set of servers to retry periodically */ +__attribute__((nonnull, warn_unused_result)) bool add_server(const char *ip, in_port_t port, AvahiIfIndex if_index, int af, server **current_server){ int ret; @@ -224,38 +234,41 @@ perror_plus("strdup"); return false; } + ret = clock_gettime(CLOCK_MONOTONIC, &(new_server->last_seen)); + if(ret == -1){ + perror_plus("clock_gettime"); + return false; + } /* Special case of first server */ if(*current_server == NULL){ new_server->next = new_server; new_server->prev = new_server; *current_server = new_server; - /* Place the new server last in the list */ } else { + /* Place the new server last in the list */ new_server->next = *current_server; new_server->prev = (*current_server)->prev; new_server->prev->next = new_server; (*current_server)->prev = new_server; } - ret = clock_gettime(CLOCK_MONOTONIC, &(*current_server)->last_seen); - if(ret == -1){ - perror_plus("clock_gettime"); - return false; - } return true; } /* * Initialize GPGME. */ -static bool init_gpgme(const char *seckey, const char *pubkey, - const char *tempdir, mandos_context *mc){ +__attribute__((nonnull, warn_unused_result)) +static bool init_gpgme(const char * const seckey, + const char * const pubkey, + const char * const tempdir, + mandos_context *mc){ gpgme_error_t rc; gpgme_engine_info_t engine_info; /* * Helper function to insert pub and seckey to the engine keyring. */ - bool import_key(const char *filename){ + bool import_key(const char * const filename){ int ret; int fd; gpgme_data_t pgp_data; @@ -342,6 +355,7 @@ * Decrypt OpenPGP data. * Returns -1 on error */ +__attribute__((nonnull, warn_unused_result)) static ssize_t pgp_packet_decrypt(const char *cryptotext, size_t crypto_size, char **plaintext, @@ -467,7 +481,8 @@ return plaintext_length; } -static const char * safer_gnutls_strerror(int value){ +__attribute__((warn_unused_result)) +static const char *safer_gnutls_strerror(int value){ const char *ret = gnutls_strerror(value); if(ret == NULL) ret = "(unknown)"; @@ -475,11 +490,13 @@ } /* GnuTLS log function callback */ +__attribute__((nonnull)) static void debuggnutls(__attribute__((unused)) int level, const char* string){ fprintf_plus(stderr, "GnuTLS: %s", string); } +__attribute__((nonnull, warn_unused_result)) static int init_gnutls_global(const char *pubkeyfilename, const char *seckeyfilename, mandos_context *mc){ @@ -559,6 +576,7 @@ return -1; } +__attribute__((nonnull, warn_unused_result)) static int init_gnutls_session(gnutls_session_t *session, mandos_context *mc){ int ret; @@ -621,15 +639,13 @@ __attribute__((unused)) const char *txt){} /* Called when a Mandos server is found */ +__attribute__((nonnull, warn_unused_result)) static int start_mandos_communication(const char *ip, in_port_t port, AvahiIfIndex if_index, int af, mandos_context *mc){ int ret, tcp_sd = -1; ssize_t sret; - union { - struct sockaddr_in in; - struct sockaddr_in6 in6; - } to; + struct sockaddr_storage to; char *buffer = NULL; char *decrypted_buffer = NULL; size_t buffer_length = 0; @@ -716,11 +732,11 @@ memset(&to, 0, sizeof(to)); if(af == AF_INET6){ - to.in6.sin6_family = (sa_family_t)af; - ret = inet_pton(af, ip, &to.in6.sin6_addr); + ((struct sockaddr_in6 *)&to)->sin6_family = (sa_family_t)af; + ret = inet_pton(af, ip, &((struct sockaddr_in6 *)&to)->sin6_addr); } else { /* IPv4 */ - to.in.sin_family = (sa_family_t)af; - ret = inet_pton(af, ip, &to.in.sin_addr); + ((struct sockaddr_in *)&to)->sin_family = (sa_family_t)af; + ret = inet_pton(af, ip, &((struct sockaddr_in *)&to)->sin_addr); } if(ret < 0 ){ int e = errno; @@ -735,16 +751,9 @@ goto mandos_end; } if(af == AF_INET6){ - to.in6.sin6_port = htons(port); -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wstrict-aliasing" -#endif - if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */ - (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower */ -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif + ((struct sockaddr_in6 *)&to)->sin6_port = htons(port); + if(IN6_IS_ADDR_LINKLOCAL + (&((struct sockaddr_in6 *)&to)->sin6_addr)){ if(if_index == AVAHI_IF_UNSPEC){ fprintf_plus(stderr, "An IPv6 link-local address is" " incomplete without a network interface\n"); @@ -752,10 +761,10 @@ goto mandos_end; } /* Set the network interface number as scope */ - to.in6.sin6_scope_id = (uint32_t)if_index; + ((struct sockaddr_in6 *)&to)->sin6_scope_id = (uint32_t)if_index; } } else { - to.in.sin_port = htons(port); + ((struct sockaddr_in *)&to)->sin_port = htons(port); } if(quit_now){ @@ -778,20 +787,23 @@ } char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = ""; - const char *pcret; if(af == AF_INET6){ - pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr, - sizeof(addrstr)); + ret = getnameinfo((struct sockaddr *)&to, + sizeof(struct sockaddr_in6), + addrstr, sizeof(addrstr), NULL, 0, + NI_NUMERICHOST); } else { - pcret = inet_ntop(af, &(to.in.sin_addr), addrstr, - sizeof(addrstr)); + ret = getnameinfo((struct sockaddr *)&to, + sizeof(struct sockaddr_in), + addrstr, sizeof(addrstr), NULL, 0, + NI_NUMERICHOST); } - if(pcret == NULL){ - perror_plus("inet_ntop"); - } else { - if(strcmp(addrstr, ip) != 0){ - fprintf_plus(stderr, "Canonical address form: %s\n", addrstr); - } + if(ret == EAI_SYSTEM){ + perror_plus("getnameinfo"); + } else if(ret != 0) { + fprintf_plus(stderr, "getnameinfo: %s", gai_strerror(ret)); + } else if(strcmp(addrstr, ip) != 0){ + fprintf_plus(stderr, "Canonical address form: %s\n", addrstr); } } @@ -801,12 +813,14 @@ } if(af == AF_INET6){ - ret = connect(tcp_sd, &to.in6, sizeof(to)); + ret = connect(tcp_sd, (struct sockaddr *)&to, + sizeof(struct sockaddr_in6)); } else { - ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */ + ret = connect(tcp_sd, (struct sockaddr *)&to, /* IPv4 */ + sizeof(struct sockaddr_in)); } if(ret < 0){ - if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){ + if((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){ int e = errno; perror_plus("connect"); errno = e; @@ -1027,6 +1041,7 @@ return retval; } +__attribute__((nonnull)) static void resolve_callback(AvahiSServiceResolver *r, AvahiIfIndex interface, AvahiProtocol proto, @@ -1040,7 +1055,7 @@ AVAHI_GCC_UNUSED AvahiStringList *txt, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, - void* mc){ + void *mc){ if(r == NULL){ return; } @@ -1099,7 +1114,7 @@ const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, - void* mc){ + void *mc){ if(b == NULL){ return; } @@ -1165,6 +1180,7 @@ errno = old_errno; } +__attribute__((nonnull, warn_unused_result)) bool get_flags(const char *ifname, struct ifreq *ifr){ int ret; error_t ret_errno; @@ -1189,6 +1205,7 @@ return true; } +__attribute__((nonnull, warn_unused_result)) bool good_flags(const char *ifname, const struct ifreq *ifr){ /* Reject the loopback device */ @@ -1236,6 +1253,7 @@ * corresponds to an acceptable network device. * (This function is passed to scandir(3) as a filter function.) */ +__attribute__((nonnull, warn_unused_result)) int good_interface(const struct dirent *if_entry){ if(if_entry->d_name[0] == '.'){ return 0; @@ -1259,6 +1277,7 @@ /* * This function determines if a network interface is up. */ +__attribute__((nonnull, warn_unused_result)) bool interface_is_up(const char *interface){ struct ifreq ifr; if(not get_flags(interface, &ifr)){ @@ -1275,6 +1294,7 @@ /* * This function determines if a network interface is running */ +__attribute__((nonnull, warn_unused_result)) bool interface_is_running(const char *interface){ struct ifreq ifr; if(not get_flags(interface, &ifr)){ @@ -1288,6 +1308,7 @@ return (bool)(ifr.ifr_flags & IFF_RUNNING); } +__attribute__((nonnull, pure, warn_unused_result)) int notdotentries(const struct dirent *direntry){ /* Skip "." and ".." */ if(direntry->d_name[0] == '.' @@ -1300,6 +1321,7 @@ } /* Is this directory entry a runnable program? */ +__attribute__((nonnull, warn_unused_result)) int runnable_hook(const struct dirent *direntry){ int ret; size_t sret; @@ -1360,6 +1382,7 @@ return 1; } +__attribute__((nonnull, warn_unused_result)) int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval, mandos_context *mc){ int ret; @@ -1369,13 +1392,13 @@ while(true){ if(mc->current_server == NULL){ - if (debug){ + if(debug){ fprintf_plus(stderr, "Wait until first server is found." " No timeout!\n"); } ret = avahi_simple_poll_iterate(s, -1); } else { - if (debug){ + if(debug){ fprintf_plus(stderr, "Check current_server if we should run" " it, or wait\n"); } @@ -1398,7 +1421,7 @@ - ((intmax_t)waited_time.tv_sec * 1000)) - ((intmax_t)waited_time.tv_nsec / 1000000)); - if (debug){ + if(debug){ fprintf_plus(stderr, "Blocking for %" PRIdMAX " ms\n", block_time); } @@ -1426,7 +1449,7 @@ ret = avahi_simple_poll_iterate(s, (int)block_time); } if(ret != 0){ - if (ret > 0 or errno != EINTR){ + if(ret > 0 or errno != EINTR){ return (ret != 1) ? ret : 0; } } @@ -1434,6 +1457,7 @@ } /* Set effective uid to 0, return errno */ +__attribute__((warn_unused_result)) error_t raise_privileges(void){ error_t old_errno = errno; error_t ret_errno = 0; @@ -1446,6 +1470,7 @@ } /* Set effective and real user ID to 0. Return errno. */ +__attribute__((warn_unused_result)) error_t raise_privileges_permanently(void){ error_t old_errno = errno; error_t ret_errno = raise_privileges(); @@ -1462,6 +1487,7 @@ } /* Set effective user ID to unprivileged saved user ID */ +__attribute__((warn_unused_result)) error_t lower_privileges(void){ error_t old_errno = errno; error_t ret_errno = 0; @@ -1474,6 +1500,7 @@ } /* Lower privileges permanently */ +__attribute__((warn_unused_result)) error_t lower_privileges_permanently(void){ error_t old_errno = errno; error_t ret_errno = 0; @@ -1485,11 +1512,10 @@ return ret_errno; } -bool run_network_hooks(const char *mode, const char *interface, +__attribute__((nonnull)) +void run_network_hooks(const char *mode, const char *interface, const float delay){ struct dirent **direntries; - struct dirent *direntry; - int ret; int numhooks = scandir(hookdir, &direntries, runnable_hook, alphasort); if(numhooks == -1){ @@ -1502,6 +1528,8 @@ perror_plus("scandir"); } } else { + struct dirent *direntry; + int ret; int devnull = open("/dev/null", O_RDONLY); for(int i = 0; i < numhooks; i++){ direntry = direntries[i]; @@ -1519,22 +1547,39 @@ if(hook_pid == 0){ /* Child */ /* Raise privileges */ - raise_privileges_permanently(); + if(raise_privileges_permanently() != 0){ + perror_plus("Failed to raise privileges"); + _exit(EX_NOPERM); + } /* Set group */ errno = 0; ret = setgid(0); if(ret == -1){ perror_plus("setgid"); + _exit(EX_NOPERM); } /* Reset supplementary groups */ errno = 0; ret = setgroups(0, NULL); if(ret == -1){ perror_plus("setgroups"); - } - dup2(devnull, STDIN_FILENO); - close(devnull); - dup2(STDERR_FILENO, STDOUT_FILENO); + _exit(EX_NOPERM); + } + ret = dup2(devnull, STDIN_FILENO); + if(ret == -1){ + perror_plus("dup2(devnull, STDIN_FILENO)"); + _exit(EX_OSERR); + } + ret = close(devnull); + if(ret == -1){ + perror_plus("close"); + _exit(EX_OSERR); + } + ret = dup2(STDERR_FILENO, STDOUT_FILENO); + if(ret == -1){ + perror_plus("dup2(STDERR_FILENO, STDOUT_FILENO)"); + _exit(EX_OSERR); + } ret = setenv("MANDOSNETHOOKDIR", hookdir, 1); if(ret == -1){ perror_plus("setenv"); @@ -1556,7 +1601,7 @@ _exit(EX_OSERR); } char *delaystring; - ret = asprintf(&delaystring, "%f", delay); + ret = asprintf(&delaystring, "%f", (double)delay); if(ret == -1){ perror_plus("asprintf"); _exit(EX_OSERR); @@ -1615,15 +1660,13 @@ } close(devnull); } - return true; } +__attribute__((nonnull, warn_unused_result)) error_t bring_up_interface(const char *const interface, const float delay){ - int sd = -1; error_t old_errno = errno; - error_t ret_errno = 0; - int ret, ret_setflags; + int ret; struct ifreq network; unsigned int if_index = if_nametoindex(interface); if(if_index == 0){ @@ -1638,24 +1681,29 @@ } if(not interface_is_up(interface)){ - if(not get_flags(interface, &network) and debug){ + error_t ret_errno = 0, ioctl_errno = 0; + if(not get_flags(interface, &network)){ ret_errno = errno; fprintf_plus(stderr, "Failed to get flags for interface " "\"%s\"\n", interface); + errno = old_errno; return ret_errno; } - network.ifr_flags |= IFF_UP; + network.ifr_flags |= IFF_UP; /* set flag */ - sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP); - if(sd < 0){ + int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP); + if(sd == -1){ ret_errno = errno; perror_plus("socket"); errno = old_errno; return ret_errno; } - + if(quit_now){ - close(sd); + ret = (int)TEMP_FAILURE_RETRY(close(sd)); + if(ret == -1){ + perror_plus("close"); + } errno = old_errno; return EINTR; } @@ -1665,21 +1713,28 @@ interface); } - /* Raise priviliges */ - raise_privileges(); + /* Raise privileges */ + ret_errno = raise_privileges(); + if(ret_errno != 0){ + perror_plus("Failed to raise privileges"); + } #ifdef __linux__ - /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO - messages about the network interface to mess up the prompt */ - int ret_linux = klogctl(8, NULL, 5); - bool restore_loglevel = true; - if(ret_linux == -1){ - restore_loglevel = false; - perror_plus("klogctl"); + int ret_linux; + bool restore_loglevel = false; + if(ret_errno == 0){ + /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO + messages about the network interface to mess up the prompt */ + ret_linux = klogctl(8, NULL, 5); + if(ret_linux == -1){ + perror_plus("klogctl"); + } else { + restore_loglevel = true; + } } #endif /* __linux__ */ - ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network); - ret_errno = errno; + int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network); + ioctl_errno = errno; #ifdef __linux__ if(restore_loglevel){ ret_linux = klogctl(7, NULL, 0); @@ -1689,8 +1744,15 @@ } #endif /* __linux__ */ - /* Lower privileges */ - lower_privileges(); + /* If raise_privileges() succeeded above */ + if(ret_errno == 0){ + /* Lower privileges */ + ret_errno = lower_privileges(); + if(ret_errno != 0){ + errno = ret_errno; + perror_plus("Failed to lower privileges"); + } + } /* Close the socket */ ret = (int)TEMP_FAILURE_RETRY(close(sd)); @@ -1699,10 +1761,10 @@ } if(ret_setflags == -1){ - errno = ret_errno; + errno = ioctl_errno; perror_plus("ioctl SIOCSIFFLAGS +IFF_UP"); errno = old_errno; - return ret_errno; + return ioctl_errno; } } else if(debug){ fprintf_plus(stderr, "Interface \"%s\" is already up; good\n", @@ -1726,11 +1788,9 @@ return 0; } +__attribute__((nonnull, warn_unused_result)) error_t take_down_interface(const char *const interface){ - int sd = -1; error_t old_errno = errno; - error_t ret_errno = 0; - int ret, ret_setflags; struct ifreq network; unsigned int if_index = if_nametoindex(interface); if(if_index == 0){ @@ -1739,16 +1799,18 @@ return ENXIO; } if(interface_is_up(interface)){ + error_t ret_errno = 0, ioctl_errno = 0; if(not get_flags(interface, &network) and debug){ ret_errno = errno; fprintf_plus(stderr, "Failed to get flags for interface " "\"%s\"\n", interface); + errno = old_errno; return ret_errno; } network.ifr_flags &= ~(short)IFF_UP; /* clear flag */ - sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP); - if(sd < 0){ + int sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP); + if(sd == -1){ ret_errno = errno; perror_plus("socket"); errno = old_errno; @@ -1760,26 +1822,36 @@ interface); } - /* Raise priviliges */ - raise_privileges(); - - ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network); - ret_errno = errno; - - /* Lower privileges */ - lower_privileges(); + /* Raise privileges */ + ret_errno = raise_privileges(); + if(ret_errno != 0){ + perror_plus("Failed to raise privileges"); + } + + int ret_setflags = ioctl(sd, SIOCSIFFLAGS, &network); + ioctl_errno = errno; + + /* If raise_privileges() succeeded above */ + if(ret_errno == 0){ + /* Lower privileges */ + ret_errno = lower_privileges(); + if(ret_errno != 0){ + errno = ret_errno; + perror_plus("Failed to lower privileges"); + } + } /* Close the socket */ - ret = (int)TEMP_FAILURE_RETRY(close(sd)); + int ret = (int)TEMP_FAILURE_RETRY(close(sd)); if(ret == -1){ perror_plus("close"); } if(ret_setflags == -1){ - errno = ret_errno; + errno = ioctl_errno; perror_plus("ioctl SIOCSIFFLAGS -IFF_UP"); errno = old_errno; - return ret_errno; + return ioctl_errno; } } else if(debug){ fprintf_plus(stderr, "Interface \"%s\" is already down; odd\n", @@ -1793,7 +1865,7 @@ int main(int argc, char *argv[]){ mandos_context mc = { .server = NULL, .dh_bits = 1024, .priority = "SECURE256:!CTYPE-X.509:" - "+CTYPE-OPENPGP", .current_server = NULL, + "+CTYPE-OPENPGP", .current_server = NULL, .interfaces = NULL, .interfaces_size = 0 }; AvahiSServiceBrowser *sb = NULL; error_t ret_errno; @@ -1803,13 +1875,13 @@ int exitcode = EXIT_SUCCESS; char *interfaces_to_take_down = NULL; size_t interfaces_to_take_down_size = 0; - char tempdir[] = "/tmp/mandosXXXXXX"; - bool tempdir_created = false; + char run_tempdir[] = "/run/tmp/mandosXXXXXX"; + char old_tempdir[] = "/tmp/mandosXXXXXX"; + char *tempdir = NULL; AvahiIfIndex if_index = AVAHI_IF_UNSPEC; const char *seckey = PATHDIR "/" SECKEY; const char *pubkey = PATHDIR "/" PUBKEY; char *interfaces_hooks = NULL; - size_t interfaces_hooks_size = 0; bool gnutls_initialized = false; bool gpgme_initialized = false; @@ -1993,8 +2065,12 @@ /* Work around Debian bug #633582: */ - /* Re-raise priviliges */ - if(raise_privileges() == 0){ + /* Re-raise privileges */ + ret_errno = raise_privileges(); + if(ret_errno != 0){ + errno = ret_errno; + perror_plus("Failed to raise privileges"); + } else { struct stat st; if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){ @@ -2040,7 +2116,11 @@ } /* Lower privileges */ - lower_privileges(); + ret_errno = lower_privileges(); + if(ret_errno != 0){ + errno = ret_errno; + perror_plus("Failed to lower privileges"); + } } } @@ -2070,14 +2150,10 @@ goto end; } memcpy(interfaces_hooks, mc.interfaces, mc.interfaces_size); - interfaces_hooks_size = mc.interfaces_size; - argz_stringify(interfaces_hooks, interfaces_hooks_size, - (int)','); - } - if(not run_network_hooks("start", interfaces_hooks != NULL ? - interfaces_hooks : "", delay)){ - goto end; - } + argz_stringify(interfaces_hooks, mc.interfaces_size, (int)','); + } + run_network_hooks("start", interfaces_hooks != NULL ? + interfaces_hooks : "", delay); } if(not debug){ @@ -2171,6 +2247,7 @@ ret_errno = argz_add(&mc.interfaces, &mc.interfaces_size, direntries[i]->d_name); if(ret_errno != 0){ + errno = ret_errno; perror_plus("argz_add"); continue; } @@ -2210,15 +2287,17 @@ break; } bool interface_was_up = interface_is_up(interface); - ret = bring_up_interface(interface, delay); + errno = bring_up_interface(interface, delay); if(not interface_was_up){ - if(ret != 0){ - errno = ret; + if(errno != 0){ perror_plus("Failed to bring up interface"); } else { - ret_errno = argz_add(&interfaces_to_take_down, - &interfaces_to_take_down_size, - interface); + errno = argz_add(&interfaces_to_take_down, + &interfaces_to_take_down_size, + interface); + if(errno != 0){ + perror_plus("argz_add"); + } } } } @@ -2253,11 +2332,19 @@ goto end; } - if(mkdtemp(tempdir) == NULL){ + /* Try /run/tmp before /tmp */ + tempdir = mkdtemp(run_tempdir); + if(tempdir == NULL and errno == ENOENT){ + if(debug){ + fprintf_plus(stderr, "Tempdir %s did not work, trying %s\n", + run_tempdir, old_tempdir); + } + tempdir = mkdtemp(old_tempdir); + } + if(tempdir == NULL){ perror_plus("mkdtemp"); goto end; } - tempdir_created = true; if(quit_now){ goto end; @@ -2338,7 +2425,7 @@ sleep((unsigned int)retry_interval); } - if (not quit_now){ + if(not quit_now){ exitcode = EXIT_SUCCESS; } @@ -2446,45 +2533,52 @@ } } - /* Re-raise priviliges */ + /* Re-raise privileges */ { - raise_privileges(); - - /* Run network hooks */ - run_network_hooks("stop", interfaces_hooks != NULL ? - interfaces_hooks : "", delay); - - /* Take down the network interfaces which were brought up */ - { - char *interface = NULL; - while((interface=argz_next(interfaces_to_take_down, - interfaces_to_take_down_size, - interface))){ - ret_errno = take_down_interface(interface); - if(ret_errno != 0){ - errno = ret_errno; - perror_plus("Failed to take down interface"); - } - } - if(debug and (interfaces_to_take_down == NULL)){ - fprintf_plus(stderr, "No interfaces needed to be taken" - " down\n"); - } - } - - lower_privileges_permanently(); + ret_errno = raise_privileges(); + if(ret_errno != 0){ + perror_plus("Failed to raise privileges"); + } else { + + /* Run network hooks */ + run_network_hooks("stop", interfaces_hooks != NULL ? + interfaces_hooks : "", delay); + + /* Take down the network interfaces which were brought up */ + { + char *interface = NULL; + while((interface=argz_next(interfaces_to_take_down, + interfaces_to_take_down_size, + interface))){ + ret_errno = take_down_interface(interface); + if(ret_errno != 0){ + errno = ret_errno; + perror_plus("Failed to take down interface"); + } + } + if(debug and (interfaces_to_take_down == NULL)){ + fprintf_plus(stderr, "No interfaces needed to be taken" + " down\n"); + } + } + } + + ret_errno = lower_privileges_permanently(); + if(ret_errno != 0){ + perror_plus("Failed to lower privileges permanently"); + } } free(interfaces_to_take_down); free(interfaces_hooks); /* Removes the GPGME temp directory and all files inside */ - if(tempdir_created){ + if(tempdir != NULL){ struct dirent **direntries = NULL; struct dirent *direntry = NULL; int numentries = scandir(tempdir, &direntries, notdotentries, alphasort); - if (numentries > 0){ + if(numentries > 0){ for(int i = 0; i < numentries; i++){ direntry = direntries[i]; char *fullname = NULL; @@ -2505,7 +2599,7 @@ /* need to clean even if 0 because man page doesn't specify */ free(direntries); - if (numentries == -1){ + if(numentries == -1){ perror_plus("scandir"); } ret = rmdir(tempdir); === modified file 'plugins.d/mandos-client.xml' --- plugins.d/mandos-client.xml 2014-01-20 20:54:47 +0000 +++ plugins.d/mandos-client.xml 2014-03-06 02:26:04 +0000 @@ -2,7 +2,7 @@ - + %common; ]> @@ -35,6 +35,7 @@ 2009 2012 2013 + 2014 Teddy Hogeborn Björn Påhlsson @@ -260,10 +261,9 @@ NAME can be the string none; this will make - &COMMANDNAME; not bring up - any interfaces specified - after this string. This is not - recommended, and only meant for advanced users. + &COMMANDNAME; only bring up interfaces + specified before this string. This + is not recommended, and only meant for advanced users. === modified file 'plugins.d/password-prompt.c' --- plugins.d/password-prompt.c 2013-10-20 15:25:09 +0000 +++ plugins.d/password-prompt.c 2014-03-29 02:38:15 +0000 @@ -2,8 +2,8 @@ /* * Password-prompt - Read a password from the terminal and print it * - * Copyright © 2008-2013 Teddy Hogeborn - * Copyright © 2008-2013 Björn Påhlsson + * Copyright © 2008-2014 Teddy Hogeborn + * Copyright © 2008-2014 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 @@ -72,16 +72,6 @@ /* Needed for conflict resolution */ const char plymouth_name[] = "plymouthd"; -__attribute__((format (gnu_printf, 2, 3), nonnull(1))) -int fprintf_plus(FILE *stream, const char *format, ...){ - va_list ap; - va_start (ap, format); - - TEMP_FAILURE_RETRY(fprintf(stream, "Mandos plugin %s: ", - program_invocation_short_name)); - return (int)TEMP_FAILURE_RETRY(vfprintf(stream, format, ap)); -} - /* Function to use when printing errors */ __attribute__((format (gnu_printf, 3, 4))) void error_plus(int status, int errnum, const char *formatstring, @@ -92,7 +82,7 @@ va_start(ap, formatstring); ret = vasprintf(&text, formatstring, ap); - if (ret == -1){ + if(ret == -1){ fprintf(stderr, "Mandos plugin %s: ", program_invocation_short_name); vfprintf(stderr, formatstring, ap); @@ -222,7 +212,7 @@ struct dirent **direntries = NULL; int ret; ret = scandir("/proc", &direntries, is_plymouth, alphasort); - if (ret == -1){ + if(ret == -1){ error_plus(1, errno, "scandir"); } free(direntries); @@ -313,7 +303,7 @@ fprintf(stderr, "Starting %s\n", argv[0]); } - if (conflict_detection()){ + if(conflict_detection()){ if(debug){ fprintf(stderr, "Stopping %s because of conflict\n", argv[0]); } === modified file 'plugins.d/plymouth.c' --- plugins.d/plymouth.c 2013-10-20 15:25:09 +0000 +++ plugins.d/plymouth.c 2014-03-29 02:38:15 +0000 @@ -2,8 +2,8 @@ /* * Plymouth - Read a password from Plymouth and output it * - * Copyright © 2010-2013 Teddy Hogeborn - * Copyright © 2010-2013 Björn Påhlsson + * Copyright © 2010-2014 Teddy Hogeborn + * Copyright © 2010-2014 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 @@ -84,7 +84,7 @@ va_start(ap, formatstring); ret = vasprintf(&text, formatstring, ap); - if (ret == -1){ + if(ret == -1){ fprintf(stderr, "Mandos plugin %s: ", program_invocation_short_name); vfprintf(stderr, formatstring, ap); @@ -179,7 +179,7 @@ int i = 0; for (; argv[i]!=NULL; i++){ tmp = realloc(new_argv, sizeof(const char *) * ((size_t)i + 1)); - if (tmp == NULL){ + if(tmp == NULL){ error_plus(0, errno, "realloc"); free(new_argv); _exit(EX_OSERR); @@ -290,12 +290,12 @@ if(proc_id == 0){ struct dirent **direntries = NULL; ret = scandir("/proc", &direntries, is_plymouth, alphasort); - if (ret == -1){ + if(ret == -1){ error_plus(0, errno, "scandir"); } - if (ret > 0){ + if(ret > 0){ ret = sscanf(direntries[0]->d_name, "%" SCNuMAX, &proc_id); - if (ret < 0){ + if(ret < 0){ error_plus(0, errno, "sscanf"); } } === modified file 'plugins.d/splashy.c' --- plugins.d/splashy.c 2011-12-31 23:05:34 +0000 +++ plugins.d/splashy.c 2014-03-29 02:38:15 +0000 @@ -2,8 +2,8 @@ /* * Splashy - Read a password from splashy and output it * - * Copyright © 2008-2012 Teddy Hogeborn - * Copyright © 2008-2012 Björn Påhlsson + * Copyright © 2008-2014 Teddy Hogeborn + * Copyright © 2008-2014 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 @@ -70,7 +70,7 @@ va_start(ap, formatstring); ret = vasprintf(&text, formatstring, ap); - if (ret == -1){ + if(ret == -1){ fprintf(stderr, "Mandos plugin %s: ", program_invocation_short_name); vfprintf(stderr, formatstring, ap); === modified file 'plugins.d/usplash.c' --- plugins.d/usplash.c 2011-12-31 23:05:34 +0000 +++ plugins.d/usplash.c 2014-03-29 02:38:15 +0000 @@ -2,8 +2,8 @@ /* * Usplash - Read a password from usplash and output it * - * Copyright © 2008-2012 Teddy Hogeborn - * Copyright © 2008-2012 Björn Påhlsson + * Copyright © 2008-2014 Teddy Hogeborn + * Copyright © 2008-2014 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 @@ -67,7 +67,7 @@ va_start(ap, formatstring); ret = vasprintf(&text, formatstring, ap); - if (ret == -1){ + if(ret == -1){ fprintf(stderr, "Mandos plugin %s: ", program_invocation_short_name); vfprintf(stderr, formatstring, ap);