=== modified file 'Makefile' --- Makefile 2009-02-07 04:50:39 +0000 +++ Makefile 2009-02-09 02:01:13 +0000 @@ -1,6 +1,6 @@ WARN=-O -Wall -Wformat=2 -Winit-self -Wmissing-include-dirs \ -Wswitch-default -Wswitch-enum -Wunused-parameter \ - -Wstrict-aliasing=2 -Wextra -Wfloat-equal -Wundef -Wshadow \ + -Wstrict-aliasing=1 -Wextra -Wfloat-equal -Wundef -Wshadow \ -Wunsafe-loop-optimizations -Wpointer-arith \ -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings \ -Wconversion -Wstrict-prototypes -Wold-style-definition \ === modified file 'debian/mandos-client.README.Debian' --- debian/mandos-client.README.Debian 2009-01-15 02:52:02 +0000 +++ debian/mandos-client.README.Debian 2009-02-09 02:01:13 +0000 @@ -7,10 +7,13 @@ * Use the Correct Network Interface - If some other network interface than "eth0" is used, it will be - necessary to edit /etc/mandos/plugin-runner.conf to uncomment and - change the line there. If this is done, it will be necessary to - update the initrd image by doing "update-initramfs -k all -u". + 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. * Test the Server @@ -23,19 +26,19 @@ --seckey=/etc/keys/mandos/seckey.txt; echo This command should retrieve the password from the server, decrypt - it, and output it to standard output. It is now possible to verify - the correctness of the password before rebooting. + it, and output it to standard output. There it can be verified to + be the correct password, before rebooting. * User-Supplied Plugins - + Any plugins found in /etc/mandos/plugins.d will override and add to the normal Mandos plugins. When adding or changing plugins, do not forget to update the initital RAM disk image: - + # update-initramfs -k all -u * Do *NOT* Edit /etc/crypttab - + It is NOT necessary to edit /etc/crypttab to specify /usr/lib/mandos/plugin-runner as a keyscript for the root file system; if no keyscript is given for the root file system, the @@ -48,4 +51,22 @@ prevented from running at startup by passing the parameter "mandos=off" to the kernel. - -- Teddy Hogeborn , Mon, 12 Jan 2009 02:29:10 +0100 +* Non-local Connection (Not Using ZeroConf) + + If the "ip=" kernel command line option is used to specify a + complete IP address and device name, as noted above, it then becomes + possible to specify a specific IP address and port to connect to, + instead of using ZeroConf. The syntax for doing this is + "mandos=connect::". + + Warning: this will cause the client to make exactly one attempt at + connecting, and then fail if it does not succeed. + + For very advanced users, it it possible to specify simply + "mandos=connect" on the kernel command line to make the system only + set up the network (using the data in the "ip=" option) and not pass + any extra "--connect" options to mandos-client at boot. For this to + work, "--options-for=mandos-client:--connect=
:" needs + to be manually added to the file "/etc/mandos/plugin-runner.conf". + + -- Teddy Hogeborn , Mon, 9 Feb 2009 00:36:55 +0100 === modified file 'initramfs-tools-script' --- initramfs-tools-script 2009-02-07 04:50:39 +0000 +++ initramfs-tools-script 2009-02-09 02:01:13 +0000 @@ -24,17 +24,86 @@ ;; esac +. /scripts/functions + for param in `cat /proc/cmdline`; do case "$param" in - mandos=off) exit 0;; + ip=*) IPOPTS="${param#ip=}" ;; + mandos=*) + # Split option line on commas + old_ifs="$IFS" + IFS="$IFS," + for mpar in ${param#mandos=}; do + IFS="$old_ifs" + case "$mpar" in + off) exit 0 ;; + connect) connect="" ;; + connect:*) connect="${mpar#connect:}" ;; + *) log_warning_msg "$0: Bad option ${mpar}" ;; + esac + done + unset mpar + IFS="$old_ifs" + unset old_ifs + ;; esac done +unset param chmod a=rwxt /tmp test -r /conf/conf.d/cryptroot test -w /conf/conf.d +# Get DEVICE from /conf/initramfs.conf and other files +. /conf/initramfs.conf +for conf in /conf/conf.d/*; do + [ -f ${conf} ] && . ${conf} +done +if [ -e /conf/param.conf ]; then + . /conf/param.conf +fi + +# Override DEVICE from sixth field of ip= kernel option, if passed +case "$IPOPTS" in + *:*:*:*:*:*) # At least six fields + # Remove the first five fields + device="${IPOPTS#*:*:*:*:*:}" + # Remove all fields except the first one + DEVICE="${device%%:*}" + ;; +esac + +# Add device setting (if any) to plugin-runner.conf +if [ "${DEVICE+set}" = set ]; then + # Did we get the device from an ip= option? + if [ "${device+set}" = set ]; then + # Let ip= option override local config; append: + cat <<-EOF >>/conf/conf.d/mandos/plugin-runner.conf + + --options-for=mandos-client:--interface=${DEVICE} +EOF + else + # Prepend device setting so any later options would override: + sed -i -e \ + '1i--options-for=mandos-client:--interface='"${DEVICE}" \ + /conf/conf.d/mandos/plugin-runner.conf + fi +fi +unset device + +# If we are connecting directly, run "configure_networking" (from +# /scripts/functions); it needs IPOPTS and DEVICE +if [ "${connect+set}" = set ]; then + configure_networking + if [ -n "$connect" ]; then + cat <<-EOF >>/conf/conf.d/mandos/plugin-runner.conf + + --options-for=mandos-client:--connect=${connect} +EOF + fi +fi + # Do not replace cryptroot file unless we need to. replace_cryptroot=no === modified file 'plugin-runner.conf' --- plugin-runner.conf 2008-10-05 17:38:31 +0000 +++ plugin-runner.conf 2009-02-09 02:01:13 +0000 @@ -4,8 +4,6 @@ ## ## After editing this file, the initrd image file must be updated for ## the changes to take effect! -## -## The default network interface for mandos-client(8mandos) is -## "eth0". Uncomment this line and change it if necessary. -## -#--options-for=mandos-client:--interface=eth0 + +## Example: +#--options-for=mandos-client:--debug === modified file 'plugins.d/mandos-client.c' --- plugins.d/mandos-client.c 2009-02-04 06:52:40 +0000 +++ plugins.d/mandos-client.c 2009-02-09 02:01:13 +0000 @@ -42,19 +42,17 @@ #include /* NULL, size_t, ssize_t */ #include /* free(), EXIT_SUCCESS, EXIT_FAILURE, srand() */ -#include /* bool, true */ +#include /* bool, false, true */ #include /* memset(), strcmp(), strlen(), strerror(), asprintf(), strcpy() */ -#include /* ioctl */ +#include /* ioctl */ #include /* socket(), inet_pton(), sockaddr, sockaddr_in6, PF_INET6, - SOCK_STREAM, INET6_ADDRSTRLEN, - uid_t, gid_t, open(), opendir(), - DIR */ + SOCK_STREAM, uid_t, gid_t, open(), + opendir(), DIR */ #include /* open() */ #include /* socket(), struct sockaddr_in6, - struct in6_addr, inet_pton(), - connect() */ + inet_pton(), connect() */ #include /* open() */ #include /* opendir(), struct dirent, readdir() */ @@ -65,12 +63,14 @@ #include /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS, if_indextoname(), if_nametoindex(), IF_NAMESIZE */ -#include +#include /* IN6_IS_ADDR_LINKLOCAL, + INET_ADDRSTRLEN, INET6_ADDRSTRLEN + */ #include /* close(), SEEK_SET, off_t, write(), getuid(), getgid(), setuid(), setgid() */ #include /* inet_pton(), htons */ -#include /* not, and, or */ +#include /* not, or, and */ #include /* struct argp_option, error_t, struct argp_state, struct argp, argp_parse(), ARGP_KEY_ARG, @@ -410,9 +410,9 @@ gnutls_certificate_allocate_credentials(&mc->cred); if(ret != GNUTLS_E_SUCCESS){ fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning - * from - * -Wunreachable-code - */ + from + -Wunreachable-code + */ safer_gnutls_strerror(ret)); gnutls_global_deinit(); return -1; @@ -509,10 +509,13 @@ /* Called when a Mandos server is found */ static int start_mandos_communication(const char *ip, uint16_t port, AvahiIfIndex if_index, - mandos_context *mc){ + mandos_context *mc, int af){ int ret, tcp_sd; ssize_t sret; - union { struct sockaddr in; struct sockaddr_in6 in6; } to; + union { + struct sockaddr_in in; + struct sockaddr_in6 in6; + } to; char *buffer = NULL; char *decrypted_buffer; size_t buffer_length = 0; @@ -520,8 +523,20 @@ ssize_t decrypted_buffer_size; size_t written; int retval = 0; - char interface[IF_NAMESIZE]; gnutls_session_t session; + int pf; /* Protocol family */ + + switch(af){ + case AF_INET6: + pf = PF_INET6; + break; + case AF_INET: + pf = PF_INET; + break; + default: + fprintf(stderr, "Bad address family: %d\n", af); + return -1; + } ret = init_gnutls_session(mc, &session); if(ret != 0){ @@ -529,29 +544,24 @@ } if(debug){ - fprintf(stderr, "Setting up a tcp connection to %s, port %" PRIu16 + fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16 "\n", ip, port); } - tcp_sd = socket(PF_INET6, SOCK_STREAM, 0); + tcp_sd = socket(pf, SOCK_STREAM, 0); if(tcp_sd < 0){ perror("socket"); return -1; } - if(debug){ - if(if_indextoname((unsigned int)if_index, interface) == NULL){ - perror("if_indextoname"); - return -1; - } - fprintf(stderr, "Binding to interface %s\n", interface); - } - memset(&to, 0, sizeof(to)); - to.in6.sin6_family = AF_INET6; - /* It would be nice to have a way to detect if we were passed an - IPv4 address here. Now we assume an IPv6 address. */ - ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr); + if(af == AF_INET6){ + to.in6.sin6_family = (uint16_t)af; + ret = inet_pton(af, ip, &to.in6.sin6_addr); + } else { /* IPv4 */ + to.in.sin_family = (sa_family_t)af; + ret = inet_pton(af, ip, &to.in.sin_addr); + } if(ret < 0 ){ perror("inet_pton"); return -1; @@ -560,18 +570,52 @@ fprintf(stderr, "Bad address: %s\n", ip); return -1; } - to.in6.sin6_port = htons(port); /* Spurious warnings from + if(af == AF_INET6){ + to.in6.sin6_port = htons(port); /* Spurious warnings from + -Wconversion and + -Wunreachable-code */ + + if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */ + (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and + -Wunreachable-code*/ + if(if_index == AVAHI_IF_UNSPEC){ + fprintf(stderr, "An IPv6 link-local address is incomplete" + " without a network interface\n"); + return -1; + } + /* Set the network interface number as scope */ + to.in6.sin6_scope_id = (uint32_t)if_index; + } + } else { + to.in.sin_port = htons(port); /* Spurious warnings from -Wconversion and -Wunreachable-code */ - - to.in6.sin6_scope_id = (uint32_t)if_index; + } if(debug){ - fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip, - port); - char addrstr[INET6_ADDRSTRLEN] = ""; - if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr, - sizeof(addrstr)) == NULL){ + if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){ + char interface[IF_NAMESIZE]; + if(if_indextoname((unsigned int)if_index, interface) == NULL){ + perror("if_indextoname"); + } else { + fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n", + ip, interface, port); + } + } else { + fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip, + port); + } + char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ? + INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = ""; + const char *pcret; + if(af == AF_INET6){ + pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr, + sizeof(addrstr)); + } else { + pcret = inet_ntop(af, &(to.in.sin_addr), addrstr, + sizeof(addrstr)); + } + if(pcret == NULL){ perror("inet_ntop"); } else { if(strcmp(addrstr, ip) != 0){ @@ -580,7 +624,11 @@ } } - ret = connect(tcp_sd, &to.in, sizeof(to)); + if(af == AF_INET6){ + ret = connect(tcp_sd, &to.in6, sizeof(to)); + } else { + ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */ + } if(ret < 0){ perror("connect"); return -1; @@ -632,7 +680,7 @@ /* Read OpenPGP packet that contains the wanted password */ if(debug){ - fprintf(stderr, "Retrieving pgp encrypted password from %s\n", + fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n", ip); } @@ -726,7 +774,7 @@ static void resolve_callback(AvahiSServiceResolver *r, AvahiIfIndex interface, - AVAHI_GCC_UNUSED AvahiProtocol protocol, + AvahiProtocol proto, AvahiResolverEvent event, const char *name, const char *type, @@ -761,7 +809,8 @@ PRIdMAX ") on port %" PRIu16 "\n", name, host_name, ip, (intmax_t)interface, port); } - int ret = start_mandos_communication(ip, port, interface, mc); + int ret = start_mandos_communication(ip, port, interface, mc, + avahi_proto_to_af(proto)); if(ret == 0){ avahi_simple_poll_quit(mc->simple_poll); } @@ -857,8 +906,8 @@ .group = 1 }, { .name = "interface", .key = 'i', .arg = "NAME", - .doc = "Interface that will be used to search for Mandos" - " servers", + .doc = "Network interface that will be used to search for" + " Mandos servers", .group = 1 }, { .name = "seckey", .key = 's', .arg = "FILE", @@ -944,12 +993,14 @@ } /* If the interface is down, bring it up */ - { + if(interface[0] != '\0'){ #ifdef __linux__ /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO messages to mess up the prompt */ ret = klogctl(8, NULL, 5); + bool restore_loglevel = true; if(ret == -1){ + restore_loglevel = false; perror("klogctl"); } #endif @@ -959,9 +1010,11 @@ perror("socket"); exitcode = EXIT_FAILURE; #ifdef __linux__ - ret = klogctl(7, NULL, 0); - if(ret == -1){ - perror("klogctl"); + if(restore_loglevel){ + ret = klogctl(7, NULL, 0); + if(ret == -1){ + perror("klogctl"); + } } #endif goto end; @@ -971,9 +1024,11 @@ if(ret == -1){ perror("ioctl SIOCGIFFLAGS"); #ifdef __linux__ - ret = klogctl(7, NULL, 0); - if(ret == -1){ - perror("klogctl"); + if(restore_loglevel){ + ret = klogctl(7, NULL, 0); + if(ret == -1){ + perror("klogctl"); + } } #endif exitcode = EXIT_FAILURE; @@ -986,9 +1041,11 @@ perror("ioctl SIOCSIFFLAGS"); exitcode = EXIT_FAILURE; #ifdef __linux__ - ret = klogctl(7, NULL, 0); - if(ret == -1){ - perror("klogctl"); + if(restore_loglevel){ + ret = klogctl(7, NULL, 0); + if(ret == -1){ + perror("klogctl"); + } } #endif goto end; @@ -1013,10 +1070,12 @@ perror("close"); } #ifdef __linux__ - /* Restores kernel loglevel to default */ - ret = klogctl(7, NULL, 0); - if(ret == -1){ - perror("klogctl"); + if(restore_loglevel){ + /* Restores kernel loglevel to default */ + ret = klogctl(7, NULL, 0); + if(ret == -1){ + perror("klogctl"); + } } #endif } @@ -1024,6 +1083,7 @@ uid = getuid(); gid = getgid(); + errno = 0; setgid(gid); if(ret == -1){ perror("setgid"); @@ -1057,11 +1117,13 @@ gpgme_initialized = true; } - if_index = (AvahiIfIndex) if_nametoindex(interface); - if(if_index == 0){ - fprintf(stderr, "No such interface: \"%s\"\n", interface); - exitcode = EXIT_FAILURE; - goto end; + if(interface[0] != '\0'){ + if_index = (AvahiIfIndex) if_nametoindex(interface); + if(if_index == 0){ + fprintf(stderr, "No such interface: \"%s\"\n", interface); + exitcode = EXIT_FAILURE; + goto end; + } } if(connect_to != NULL){ @@ -1084,7 +1146,15 @@ port = (uint16_t)tmpmax; *address = '\0'; address = connect_to; - ret = start_mandos_communication(address, port, if_index, &mc); + /* Colon in address indicates IPv6 */ + int af; + if(strchr(address, ':') != NULL){ + af = AF_INET6; + } else { + af = AF_INET; + } + ret = start_mandos_communication(address, port, if_index, &mc, + af); if(ret < 0){ exitcode = EXIT_FAILURE; } else { === modified file 'plugins.d/mandos-client.xml' --- plugins.d/mandos-client.xml 2009-01-31 10:33:17 +0000 +++ plugins.d/mandos-client.xml 2009-02-09 02:01:13 +0000 @@ -2,7 +2,7 @@ - + %common; ]> @@ -195,14 +195,14 @@ - + Network interface that will be brought up and scanned for - Mandos servers to connect to. The default it + Mandos servers to connect to. The default is eth0. @@ -219,6 +219,12 @@ until much later in the boot process, and can not be used by this program. + + NAME can be the empty string; + this will not use any specific interface, and will not + bring up an interface on startup. This is not + recommended, and only meant for advanced users. + @@ -446,15 +452,15 @@ Run in debug mode, with a custom key, and do not use Zeroconf - to locate a server; connect directly to the IPv6 address - 2001:db8:f983:bd0b:30de:ae4a:71f2:f672, - port 4711, using interface eth2: + to locate a server; connect directly to the IPv6 link-local + address fe80::aede:48ff:fe71:f6f2, port 4711, + using interface eth2: -&COMMANDNAME; --debug --pubkey keydir/pubkey.txt --seckey keydir/seckey.txt --connect 2001:db8:f983:bd0b:30de:ae4a:71f2:f672:4711 --interface eth2 +&COMMANDNAME; --debug --pubkey keydir/pubkey.txt --seckey keydir/seckey.txt --connect fe80::aede:48ff:fe71:f6f2:4711 --interface eth2