=== modified file 'Makefile' --- Makefile 2008-07-21 15:34:44 +0000 +++ Makefile 2008-07-20 03:51:41 +0000 @@ -1,27 +1,7 @@ -WARN=-O -Wall -Wformat=2 -Winit-self -Wmissing-include-dirs -Wswitch-default -Wswitch-enum -Wunused-parameter -Wstrict-aliasing=2 -Wextra -Wfloat-equal -Wundef -Wshadow -Wunsafe-loop-optimizations -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Wconversion -Wstrict-prototypes -Wold-style-definition -Wpacked -Wnested-externs -Wunreachable-code -Winline -Wvolatile-register-var -DEBUG=-ggdb3 -#COVERAGE=--coverage -LANGUAGE=-std=gnu99 - -# Do not change these two -LDFLAGS=$(COVERAGE) -CFLAGS=$(WARN) $(COVERAGE) $(DEBUG) $(LANGUAGE) - -PROGS=plugbasedclient plugins.d/mandosclient plugins.d/passprompt - -objects=$(shell for p in $(PROGS); do echo $${p}.o; done) - -all: $(PROGS) - -plugbasedclient: plugbasedclient.o - $(LINK.o) -lgnutls $(COMMON) $^ $(LOADLIBES) $(LDLIBS) -o $@ - -plugins.d/mandosclient: plugins.d/mandosclient.o - $(LINK.o) -lgnutls -lavahi-core -lgpgme $(COMMON) $^ $(LOADLIBES) $(LDLIBS) -o $@ - -plugins.d/passprompt: plugins.d/passprompt.o - $(LINK.o) $(COMMON) $^ $(LOADLIBES) $(LDLIBS) -o $@ - -.PHONY : clean +CFLAGS=-Wall -g -std=gnu99 +LDFLAGS=-lgnutls + +all: plugbasedclient + clean: - -rm -f $(PROGS) $(objects) core + rm -f plugbasedclient === modified file 'TODO' --- TODO 2008-07-21 19:15:06 +0000 +++ TODO 2008-07-20 06:33:48 +0000 @@ -1,16 +1,9 @@ -[Mandos client] -configuration for OpenPGP key +[Client] +configuration for OpenPGP key and interface IPv4 support -[Pluginbasedclient] -disable certain plugins -change uid to nobody:nogroup - other drop privs stuff? - [Server] -config file for: - TXT record - GnuTLS priority string +config file run-time communication with server [Mandos-tools/utilities] === modified file 'plugbasedclient.c' --- plugbasedclient.c 2008-07-21 15:34:44 +0000 +++ plugbasedclient.c 2008-07-20 03:51:41 +0000 @@ -1,29 +1,3 @@ -/* -*- coding: utf-8 -*- */ -/* - * Mandos plugin runner - Run Mandos plugins - * - * Copyright © 2007-2008 Teddy Hogeborn and Björn Påhlsson. - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - * . - * - * Contact the authors at and - * . - */ - -#define _FORTIFY_SOURCE 2 - #include /* popen, fileno */ #include /* and, or, not */ #include /* DIR, opendir, stat, struct stat, waitpid, @@ -33,8 +7,7 @@ #include /* stat, struct stat */ #include /* stat, struct stat, chdir */ #include /* EXIT_FAILURE */ -#include /* fd_set, select, FD_ZERO, FD_SET, - FD_ISSET */ +#include /* fd_set, select, FD_ZERO, FD_SET, FD_ISSET */ #include /* strlen, strcpy, strcat */ #include /* true */ #include /* waitpid, WIFEXITED, WEXITSTATUS */ @@ -46,8 +19,8 @@ pid_t pid; int fd; char *buffer; - size_t buffer_size; - size_t buffer_length; + int buffer_size; + int buffer_length; struct process *next; } process; @@ -107,8 +80,7 @@ close(pipefd[0]); /* close unused read end of pipe */ dup2(pipefd[1], STDOUT_FILENO); /* replace our stdout */ /* create a new modified argument list */ - char **new_argv = malloc(sizeof(char *) - * ((unsigned int) argc + 1)); + char **new_argv = malloc(sizeof(char *) * (argc + 1)); new_argv[0] = filename; for(int i = 1; i < argc; i++){ new_argv[i] = argv[i]; @@ -159,7 +131,7 @@ > process_itr->buffer_size){ process_itr->buffer = realloc(process_itr->buffer, process_itr->buffer_size - + (size_t) BUFFER_SIZE); + + BUFFER_SIZE); if (process_itr->buffer == NULL){ perror(argv[0]); goto end; @@ -168,11 +140,7 @@ } ret = read(process_itr->fd, process_itr->buffer + process_itr->buffer_length, BUFFER_SIZE); - if(ret < 0){ - /* Read error from this process; ignore it */ - continue; - } - process_itr->buffer_length += (size_t) ret; + process_itr->buffer_length+=ret; if(ret == 0){ /* got EOF */ /* wait for process exit */ === added file 'plugins.d/Makefile' --- plugins.d/Makefile 1970-01-01 00:00:00 +0000 +++ plugins.d/Makefile 2008-07-20 02:52:20 +0000 @@ -0,0 +1,18 @@ +CFLAGS=-Wall -g --std=gnu99 +LDFLAGS=-lgnutls -lavahi-core -lgpgme + +PROGS=mandosclient passprompt + +objects=mandosclient.o passprompt.o + +all: $(PROGS) + +mandosclient: mandosclient.o + $(LINK.o) -lgnutls -lavahi-core -lgpgme $(COMMON) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +passprompt: passprompt.o + $(LINK.o) $(COMMON) $^ $(LOADLIBES) $(LDLIBS) -o $@ + +.PHONY : clean +clean : + -rm -f $(PROGS) $(objects) core === modified file 'plugins.d/mandosclient.c' --- plugins.d/mandosclient.c 2008-07-21 22:51:46 +0000 +++ plugins.d/mandosclient.c 2008-07-20 02:52:20 +0000 @@ -1,35 +1,34 @@ -/* -*- coding: utf-8 -*- */ -/* - * Mandos client - get and decrypt data from a Mandos server +/* $Id$ */ + +/* PLEASE NOTE * + * This file demonstrates how to use Avahi's core API, this is + * the embeddable mDNS stack for embedded applications. * - * This program is partly derived from an example program for an Avahi - * service browser, downloaded from - * . This - * includes the following functions: "resolve_callback", - * "browse_callback", and parts of "main". - * - * Everything else is Copyright © 2007-2008 Teddy Hogeborn and Björn - * Påhlsson. - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - * . - * - * Contact the authors at and - * . + * End user applications should *not* use this API and should use + * the D-Bus or C APIs, please see + * client-browse-services.c and glib-integration.c + * + * I repeat, you probably do *not* want to use this example. */ -#define _FORTIFY_SOURCE 2 +/*** + This file is part of avahi. + + avahi is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 2.1 of the + License, or (at your option) any later version. + + avahi is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General + Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with avahi; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + USA. +***/ #define _LARGEFILE_SOURCE #define _FILE_OFFSET_BITS 64 @@ -48,11 +47,10 @@ #include //mandos client part -#include /* socket(), inet_pton() */ -#include /* socket(), struct sockaddr_in6, - struct in6_addr, inet_pton() */ -#include /* All GnuTLS stuff */ -#include /* GnuTLS with openpgp stuff */ +#include /* socket(), setsockopt(), inet_pton() */ +#include /* socket(), setsockopt(), struct sockaddr_in6, struct in6_addr, inet_pton() */ +#include /* ALL GNUTLS STUFF */ +#include /* gnutls with openpgp stuff */ #include /* close() */ #include @@ -65,8 +63,6 @@ #include /* perror() */ #include -// getopt long -#include #ifndef CERT_ROOT #define CERT_ROOT "/conf/conf.d/cryptkeyreq/" @@ -76,8 +72,6 @@ #define BUFFER_SIZE 256 #define DH_BITS 1024 -bool debug = false; - typedef struct { gnutls_session_t session; gnutls_certificate_credentials_t cred; @@ -85,20 +79,15 @@ } encrypted_session; -ssize_t pgp_packet_decrypt (char *packet, size_t packet_size, - char **new_packet, const char *homedir){ +ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){ gpgme_data_t dh_crypto, dh_plain; gpgme_ctx_t ctx; gpgme_error_t rc; ssize_t ret; - ssize_t new_packet_capacity = 0; - ssize_t new_packet_length = 0; + size_t new_packet_capacity = 0; + size_t new_packet_length = 0; gpgme_engine_info_t engine_info; - if (debug){ - fprintf(stderr, "Trying to decrypt OpenPGP packet\n"); - } - /* Init GPGME */ gpgme_check_version(NULL); gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP); @@ -147,60 +136,44 @@ return -1; } - /* Decrypt data from the FILE pointer to the plaintext data - buffer */ + /* Decrypt data from the FILE pointer to the plaintext data buffer */ rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain); if (rc != GPG_ERR_NO_ERROR){ fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n", gpgme_strsource(rc), gpgme_strerror(rc)); return -1; } - - if(debug){ - fprintf(stderr, "Decryption of OpenPGP packet succeeded\n"); - } - - if (debug){ - gpgme_decrypt_result_t result; - result = gpgme_op_decrypt_result(ctx); - if (result == NULL){ - fprintf(stderr, "gpgme_op_decrypt_result failed\n"); - } else { - fprintf(stderr, "Unsupported algorithm: %s\n", - result->unsupported_algorithm); - fprintf(stderr, "Wrong key usage: %d\n", - result->wrong_key_usage); - if(result->file_name != NULL){ - fprintf(stderr, "File name: %s\n", result->file_name); - } - gpgme_recipient_t recipient; - recipient = result->recipients; - if(recipient){ - while(recipient != NULL){ - fprintf(stderr, "Public key algorithm: %s\n", - gpgme_pubkey_algo_name(recipient->pubkey_algo)); - fprintf(stderr, "Key ID: %s\n", recipient->keyid); - fprintf(stderr, "Secret key available: %s\n", - recipient->status == GPG_ERR_NO_SECKEY - ? "No" : "Yes"); - recipient = recipient->next; - } - } - } - } +/* gpgme_decrypt_result_t result; */ +/* result = gpgme_op_decrypt_result(ctx); */ +/* fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm); */ +/* fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage); */ +/* if(result->file_name != NULL){ */ +/* fprintf(stderr, "File name: %s\n", result->file_name); */ +/* } */ +/* gpgme_recipient_t recipient; */ +/* recipient = result->recipients; */ +/* if(recipient){ */ +/* while(recipient != NULL){ */ +/* fprintf(stderr, "Public key algorithm: %s\n", */ +/* gpgme_pubkey_algo_name(recipient->pubkey_algo)); */ +/* fprintf(stderr, "Key ID: %s\n", recipient->keyid); */ +/* fprintf(stderr, "Secret key available: %s\n", */ +/* recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes"); */ +/* recipient = recipient->next; */ +/* } */ +/* } */ + /* Delete the GPGME FILE pointer cryptotext data buffer */ gpgme_data_release(dh_crypto); /* Seek back to the beginning of the GPGME plaintext data buffer */ - gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET); + gpgme_data_seek(dh_plain, 0, SEEK_SET); *new_packet = 0; while(true){ if (new_packet_length + BUFFER_SIZE > new_packet_capacity){ - *new_packet = realloc(*new_packet, - (unsigned int)new_packet_capacity - + BUFFER_SIZE); + *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE); if (*new_packet == NULL){ perror("realloc"); return -1; @@ -208,10 +181,10 @@ new_packet_capacity += BUFFER_SIZE; } - ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, - BUFFER_SIZE); + ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE); /* Print the data, if any */ if (ret == 0){ + /* If password is empty, then a incorrect error will be printed */ break; } if(ret < 0){ @@ -221,15 +194,7 @@ new_packet_length += ret; } - /* FIXME: check characters before printing to screen so to not print - terminal control characters */ - /* if(debug){ */ - /* fprintf(stderr, "decrypted password is: "); */ - /* fwrite(*new_packet, 1, new_packet_length, stderr); */ - /* fprintf(stderr, "\n"); */ - /* } */ - - /* Delete the GPGME plaintext data buffer */ + /* Delete the GPGME plaintext data buffer */ gpgme_data_release(dh_plain); return new_packet_length; } @@ -241,8 +206,7 @@ return ret; } -void debuggnutls(__attribute__((unused)) int level, - const char* string){ +void debuggnutls(int level, const char* string){ fprintf(stderr, "%s", string); } @@ -250,79 +214,67 @@ const char *err; int ret; - if(debug){ - fprintf(stderr, "Initializing GnuTLS\n"); - } - if ((ret = gnutls_global_init ()) != GNUTLS_E_SUCCESS) { fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret)); return -1; } - if (debug){ - gnutls_global_set_log_level(11); - gnutls_global_set_log_function(debuggnutls); - } - + /* Uncomment to enable full debuggin on the gnutls library */ + /* gnutls_global_set_log_level(11); */ + /* gnutls_global_set_log_function(debuggnutls); */ + + /* openpgp credentials */ if ((ret = gnutls_certificate_allocate_credentials (&es->cred)) != GNUTLS_E_SUCCESS) { - fprintf (stderr, "memory error: %s\n", - safer_gnutls_strerror(ret)); + fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret)); return -1; } - - if(debug){ - fprintf(stderr, "Attempting to use OpenPGP certificate %s" - " and keyfile %s as GnuTLS credentials\n", CERTFILE, - KEYFILE); - } - + ret = gnutls_certificate_set_openpgp_key_file (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64); if (ret != GNUTLS_E_SUCCESS) { fprintf - (stderr, "Error[%d] while reading the OpenPGP key pair ('%s'," - " '%s')\n", + (stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n", ret, CERTFILE, KEYFILE); fprintf(stdout, "The Error is: %s\n", safer_gnutls_strerror(ret)); return -1; } - - //GnuTLS server initialization + + //Gnutls server initialization if ((ret = gnutls_dh_params_init (&es->dh_params)) != GNUTLS_E_SUCCESS) { fprintf (stderr, "Error in dh parameter initialization: %s\n", safer_gnutls_strerror(ret)); return -1; } - + if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS)) != GNUTLS_E_SUCCESS) { fprintf (stderr, "Error in prime generation: %s\n", safer_gnutls_strerror(ret)); return -1; } - + gnutls_certificate_set_dh_params (es->cred, es->dh_params); - - // GnuTLS session creation + + // Gnutls session creation if ((ret = gnutls_init (&es->session, GNUTLS_SERVER)) != GNUTLS_E_SUCCESS){ - fprintf(stderr, "Error in GnuTLS session initialization: %s\n", + fprintf(stderr, "Error in gnutls session initialization: %s\n", safer_gnutls_strerror(ret)); } - + if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err)) != GNUTLS_E_SUCCESS) { fprintf(stderr, "Syntax error at: %s\n", err); - fprintf(stderr, "GnuTLS error: %s\n", + fprintf(stderr, "Gnutls error: %s\n", safer_gnutls_strerror(ret)); return -1; } - + if ((ret = gnutls_credentials_set (es->session, GNUTLS_CRD_CERTIFICATE, es->cred)) != GNUTLS_E_SUCCESS) { @@ -330,36 +282,29 @@ safer_gnutls_strerror(ret)); return -1; } - + /* ignore client certificate if any. */ - gnutls_certificate_server_set_request (es->session, - GNUTLS_CERT_IGNORE); + gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE); gnutls_dh_set_prime_bits (es->session, DH_BITS); return 0; } -void empty_log(__attribute__((unused)) AvahiLogLevel level, - __attribute__((unused)) const char *txt){} +void empty_log(AvahiLogLevel level, const char *txt){} -int start_mandos_communication(const char *ip, uint16_t port, - unsigned int if_index){ +int start_mandos_communcation(char *ip, uint16_t port){ int ret, tcp_sd; struct sockaddr_in6 to; + struct in6_addr ip_addr; encrypted_session es; char *buffer = NULL; char *decrypted_buffer; size_t buffer_length = 0; size_t buffer_capacity = 0; ssize_t decrypted_buffer_size; - size_t written = 0; int retval = 0; - char interface[IF_NAMESIZE]; - - if(debug){ - fprintf(stderr, "Setting up a tcp connection to %s\n", ip); - } + tcp_sd = socket(PF_INET6, SOCK_STREAM, 0); if(tcp_sd < 0) { @@ -367,20 +312,15 @@ return -1; } - if(if_indextoname(if_index, interface) == NULL){ - if(debug){ - perror("if_indextoname"); - } + ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5); + if(tcp_sd < 0) { + perror("setsockopt bindtodevice"); return -1; } - if(debug){ - fprintf(stderr, "Binding to interface %s\n", interface); - } - - memset(&to,0,sizeof(to)); /* Spurious warning */ + memset(&to,0,sizeof(to)); to.sin6_family = AF_INET6; - ret = inet_pton(AF_INET6, ip, &to.sin6_addr); + ret = inet_pton(AF_INET6, ip, &ip_addr); if (ret < 0 ){ perror("inet_pton"); return -1; @@ -389,13 +329,8 @@ fprintf(stderr, "Bad address: %s\n", ip); return -1; } - to.sin6_port = htons(port); /* Spurious warning */ - - to.sin6_scope_id = (uint32_t)if_index; - - if(debug){ - fprintf(stderr, "Connection to: %s\n", ip); - } + to.sin6_port = htons(port); + to.sin6_scope_id = if_nametoindex("eth0"); ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to)); if (ret < 0){ @@ -408,14 +343,10 @@ retval = -1; return -1; } - - gnutls_transport_set_ptr (es.session, - (gnutls_transport_ptr_t) tcp_sd); - - if(debug){ - fprintf(stderr, "Establishing TLS session with %s\n", ip); - } - + + + gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd); + ret = gnutls_handshake (es.session); if (ret != GNUTLS_E_SUCCESS){ @@ -424,14 +355,8 @@ retval = -1; goto exit; } - - //Retrieve OpenPGP packet that contains the wanted password - - if(debug){ - fprintf(stderr, "Retrieving pgp encrypted password from %s\n", - ip); - } + //retrive password while(true){ if (buffer_length + BUFFER_SIZE > buffer_capacity){ buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE); @@ -462,50 +387,28 @@ } break; default: - fprintf(stderr, "Unknown error while reading data from" - " encrypted session with mandos server\n"); + fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n"); retval = -1; gnutls_bye (es.session, GNUTLS_SHUT_RDWR); goto exit; } } else { - buffer_length += (size_t) ret; + buffer_length += ret; } } - + if (buffer_length > 0){ - decrypted_buffer_size = pgp_packet_decrypt(buffer, - buffer_length, - &decrypted_buffer, - CERT_ROOT); - if (decrypted_buffer_size >= 0){ - while(written < decrypted_buffer_size){ - ret = (int)fwrite (decrypted_buffer + written, 1, - (size_t)decrypted_buffer_size - written, - stdout); - if(ret == 0 and ferror(stdout)){ - if(debug){ - fprintf(stderr, "Error writing encrypted data: %s\n", - strerror(errno)); - } - retval = -1; - break; - } - written += (size_t)ret; - } + if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) == 0){ + retval = -1; + } else { + fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout); free(decrypted_buffer); - } else { - retval = -1; } } + free(buffer); + //shutdown procedure - - if(debug){ - fprintf(stderr, "Closing TLS session\n"); - } - - free(buffer); gnutls_bye (es.session, GNUTLS_SHUT_RDWR); exit: close(tcp_sd); @@ -520,7 +423,7 @@ static void resolve_callback( AvahiSServiceResolver *r, - AvahiIfIndex interface, + AVAHI_GCC_UNUSED AvahiIfIndex interface, AVAHI_GCC_UNUSED AvahiProtocol protocol, AvahiResolverEvent event, const char *name, @@ -529,41 +432,31 @@ const char *host_name, const AvahiAddress *address, uint16_t port, - AVAHI_GCC_UNUSED AvahiStringList *txt, - AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, + AvahiStringList *txt, + AvahiLookupResultFlags flags, AVAHI_GCC_UNUSED void* userdata) { - assert(r); /* Spurious warning */ - - /* Called whenever a service has been resolved successfully or - timed out */ - - switch (event) { - default: - case AVAHI_RESOLVER_FAILURE: - fprintf(stderr, "(Resolver) Failed to resolve service '%s' of" - " type '%s' in domain '%s': %s\n", name, type, domain, - avahi_strerror(avahi_server_errno(server))); - break; - - case AVAHI_RESOLVER_FOUND: - { - char ip[AVAHI_ADDRESS_STR_MAX]; - avahi_address_snprint(ip, sizeof(ip), address); - if(debug){ - fprintf(stderr, "Mandos server found on %s (%s) on port %d\n", - host_name, ip, port); - } - int ret = start_mandos_communication(ip, port, - (unsigned int) interface); - if (ret == 0){ - exit(EXIT_SUCCESS); - } else { - exit(EXIT_FAILURE); - } + assert(r); + + /* Called whenever a service has been resolved successfully or timed out */ + + switch (event) { + case AVAHI_RESOLVER_FAILURE: + fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_server_errno(server))); + break; + + case AVAHI_RESOLVER_FOUND: { + char ip[AVAHI_ADDRESS_STR_MAX]; + avahi_address_snprint(ip, sizeof(ip), address); + int ret = start_mandos_communcation(ip, port); + if (ret == 0){ + exit(EXIT_SUCCESS); + } else { + exit(EXIT_FAILURE); + } + } } - } - avahi_s_service_resolver_free(r); + avahi_s_service_resolver_free(r); } static void browse_callback( @@ -578,40 +471,35 @@ void* userdata) { AvahiServer *s = userdata; - assert(b); /* Spurious warning */ - - /* Called whenever a new services becomes available on the LAN or - is removed from the LAN */ - + assert(b); + + /* Called whenever a new services becomes available on the LAN or is removed from the LAN */ + switch (event) { - default: - case AVAHI_BROWSER_FAILURE: - - fprintf(stderr, "(Browser) %s\n", - avahi_strerror(avahi_server_errno(server))); - avahi_simple_poll_quit(simple_poll); - return; - - case AVAHI_BROWSER_NEW: - /* We ignore the returned resolver object. In the callback - function we free it. If the server is terminated before - the callback function is called the server will free - the resolver for us. */ - - if (!(avahi_s_service_resolver_new(s, interface, protocol, name, - type, domain, - AVAHI_PROTO_INET6, 0, - resolve_callback, s))) - fprintf(stderr, "Failed to resolve service '%s': %s\n", name, - avahi_strerror(avahi_server_errno(s))); - break; - - case AVAHI_BROWSER_REMOVE: - break; - - case AVAHI_BROWSER_ALL_FOR_NOW: - case AVAHI_BROWSER_CACHE_EXHAUSTED: - break; + + case AVAHI_BROWSER_FAILURE: + + fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server))); + avahi_simple_poll_quit(simple_poll); + return; + + case AVAHI_BROWSER_NEW: + /* We ignore the returned resolver object. In the callback + function we free it. If the server is terminated before + the callback function is called the server will free + the resolver for us. */ + + if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s))) + fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s))); + + break; + + case AVAHI_BROWSER_REMOVE: + break; + + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + break; } } @@ -619,47 +507,17 @@ AvahiServerConfig config; AvahiSServiceBrowser *sb = NULL; int error; - int ret; - int returncode = EXIT_SUCCESS; - const char *interface = "eth0"; - - while (true){ - static struct option long_options[] = { - {"debug", no_argument, (int *)&debug, 1}, - {"interface", required_argument, 0, 'i'}, - {0, 0, 0, 0} }; - - int option_index = 0; - ret = getopt_long (argc, argv, "i:", long_options, - &option_index); - - if (ret == -1){ - break; - } - - switch(ret){ - case 0: - break; - case 'i': - interface = optarg; - break; - default: - exit(EXIT_FAILURE); - } - } - - if (not debug){ - avahi_set_log_function(empty_log); - } + int ret = 1; + + avahi_set_log_function(empty_log); /* Initialize the psuedo-RNG */ - srand((unsigned int) time(NULL)); + srand(time(NULL)); /* Allocate main loop object */ if (!(simple_poll = avahi_simple_poll_new())) { fprintf(stderr, "Failed to create simple poll object.\n"); - - goto exit; + goto fail; } /* Do not publish any local records */ @@ -669,48 +527,35 @@ config.publish_workstation = 0; config.publish_domain = 0; +/* /\* Set a unicast DNS server for wide area DNS-SD *\/ */ +/* avahi_address_parse("193.11.177.11", AVAHI_PROTO_UNSPEC, &config.wide_area_servers[0]); */ +/* config.n_wide_area_servers = 1; */ +/* config.enable_wide_area = 1; */ + /* Allocate a new server */ - server = avahi_server_new(avahi_simple_poll_get(simple_poll), - &config, NULL, NULL, &error); + server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error); /* Free the configuration data */ avahi_server_config_free(&config); - /* Check if creating the server object succeeded */ + /* Check wether creating the server object succeeded */ if (!server) { - fprintf(stderr, "Failed to create server: %s\n", - avahi_strerror(error)); - returncode = EXIT_FAILURE; - goto exit; + fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error)); + goto fail; } /* Create the service browser */ - sb = avahi_s_service_browser_new(server, - (AvahiIfIndex) - if_nametoindex(interface), - AVAHI_PROTO_INET6, - "_mandos._tcp", NULL, 0, - browse_callback, server); - if (!sb) { - fprintf(stderr, "Failed to create service browser: %s\n", - avahi_strerror(avahi_server_errno(server))); - returncode = EXIT_FAILURE; - goto exit; + if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) { + fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server))); + goto fail; } /* Run the main loop */ - - if (debug){ - fprintf(stderr, "Starting avahi loop search\n"); - } - avahi_simple_poll_loop(simple_poll); - exit: - - if (debug){ - fprintf(stderr, "%s exiting\n", argv[0]); - } + ret = 0; + +fail: /* Cleanup things */ if (sb) @@ -722,5 +567,5 @@ if (simple_poll) avahi_simple_poll_free(simple_poll); - return returncode; + return ret; } === modified file 'plugins.d/passprompt.c' --- plugins.d/passprompt.c 2008-07-21 15:34:44 +0000 +++ plugins.d/passprompt.c 2008-07-20 02:52:20 +0000 @@ -1,30 +1,5 @@ -/* -*- coding: utf-8 -*- */ -/* - * Passprompt - Read a password from the terminal and print it - * - * Copyright © 2007-2008 Teddy Hogeborn and Björn Påhlsson. - * - * This program is free software: you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see - * . - * - * Contact the authors at and - * . - */ - #define _GNU_SOURCE /* getline() */ #define _FORTIFY_SOURCE 2 - #include /* struct termios, tcsetattr(), TCSAFLUSH, tcgetattr(), ECHO */ #include /* struct termios, tcsetattr(), @@ -36,66 +11,29 @@ SIGQUIT, SIGHUP, SIGTERM */ #include /* NULL, size_t */ #include /* ssize_t */ -#include /* EXIT_SUCCESS, EXIT_FAILURE, - getopt_long */ +#include /* EXIT_SUCCESS, EXIT_FAILURE */ #include /* fprintf(), stderr, getline(), stdin, feof(), perror(), fputc(), - stdout, getopt_long */ + stdout */ #include /* errno, EINVAL */ #include /* or, not */ #include /* bool, false, true */ -#include /* strlen, rindex, strncmp, strcmp */ -#include /* getopt_long */ volatile bool quit_now = false; -bool debug = false; -void termination_handler(__attribute__((unused))int signum){ +void termination_handler(int signum){ quit_now = true; } int main(int argc, char **argv){ - ssize_t ret; + ssize_t ret = -1; size_t n; struct termios t_new, t_old; char *buffer = NULL; - char *prefix = NULL; int status = EXIT_SUCCESS; struct sigaction old_action, new_action = { .sa_handler = termination_handler, .sa_flags = 0 }; - - while (true){ - static struct option long_options[] = { - {"debug", no_argument, (int *)&debug, 1}, - {"prefix", required_argument, 0, 'p'}, - {0, 0, 0, 0} }; - - int option_index = 0; - ret = getopt_long (argc, argv, "p:", long_options, &option_index); - - if (ret == -1){ - break; - } - - switch(ret){ - case 0: - break; - case 'p': - prefix = optarg; - break; - default: - fprintf(stderr, "bad arguments\n"); - exit(EXIT_FAILURE); - } - } - - if (debug){ - fprintf(stderr, "Starting %s\n", argv[0]); - } - if (debug){ - fprintf(stderr, "Storing current terminal attributes\n"); - } if (tcgetattr(STDIN_FILENO, &t_old) != 0){ return EXIT_FAILURE; @@ -118,11 +56,6 @@ sigaction(SIGTERM, NULL, &old_action); if (old_action.sa_handler != SIG_IGN) sigaction(SIGTERM, &new_action, NULL); - - - if (debug){ - fprintf(stderr, "Removing echo flag from terminal attributes\n"); - } t_new = t_old; t_new.c_lflag &= ~ECHO; @@ -130,21 +63,13 @@ perror("tcsetattr-echo"); return EXIT_FAILURE; } - - if (debug){ - fprintf(stderr, "Waiting for input from stdin \n"); - } + while(true){ if (quit_now){ status = EXIT_FAILURE; break; } - - if(prefix){ - fprintf(stderr, "%s Password: ", prefix); - } else { - fprintf(stderr, "Password: "); - } + fprintf(stderr, "Password: "); ret = getline(&buffer, &n, stdin); if (ret > 0){ fprintf(stdout, "%s", buffer); @@ -162,16 +87,9 @@ fputc('\n', stderr); } - if (debug){ - fprintf(stderr, "Restoring terminal attributes\n"); - } if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){ perror("tcsetattr+echo"); } - - if (debug){ - fprintf(stderr, "%s is exiting\n", argv[0]); - } return status; } === modified file 'server.py' --- server.py 2008-07-21 01:50:31 +0000 +++ server.py 2008-07-20 06:33:48 +0000 @@ -1,34 +1,5 @@ #!/usr/bin/python # -*- mode: python; coding: utf-8 -*- -# -# Mandos server - give out binary blobs to connecting clients. -# -# This program is partly derived from an example program for an Avahi -# service publisher, downloaded from -# . This includes the -# following functions: "add_service", "remove_service", -# "server_state_changed", "entry_group_state_changed", and some lines -# in "main". -# -# Everything else is Copyright © 2007-2008 Teddy Hogeborn and Björn -# Påhlsson. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -# -# Contact the authors at and -# . -# from __future__ import division @@ -53,8 +24,6 @@ import subprocess import atexit import stat -import logging -import logging.handlers import dbus import gobject @@ -62,17 +31,8 @@ from dbus.mainloop.glib import DBusGMainLoop import ctypes -# Brief description of the operation of this program: -# -# This server announces itself as a Zeroconf service. Connecting -# clients use the TLS protocol, with the unusual quirk that this -# server program acts as a TLS "client" while the connecting clients -# acts as a TLS "server". The clients (acting as a TLS "server") must -# supply an OpenPGP certificate, and the fingerprint of this -# certificate is used by this server to look up (in a list read from a -# file at start time) which binary blob to give the client. No other -# authentication or authorization is done by this server. - +import logging +import logging.handlers logger = logging.Logger('mandos') syslogger = logging.handlers.SysLogHandler\ @@ -84,9 +44,9 @@ # This variable is used to optionally bind to a specified interface. # It is a global variable to fit in with the other variables from the -# Avahi example code. +# Avahi server example code. serviceInterface = avahi.IF_UNSPEC -# From the Avahi example code: +# From the Avahi server example code: serviceName = "Mandos" serviceType = "_mandos._tcp" # http://www.dns-sd.org/ServiceTypes.html servicePort = None # Not known at startup @@ -155,8 +115,6 @@ def __init__(self, name=None, options=None, stop_hook=None, fingerprint=None, secret=None, secfile=None, fqdn=None, timeout=None, interval=-1, checker=None): - """Note: the 'checker' argument sets the 'checker_command' - attribute and not the 'checker' attribute..""" self.name = name # Uppercase and remove spaces from fingerprint # for later comparison purposes with return value of @@ -189,7 +147,7 @@ self.checker_callback_tag = None self.check_command = checker def start(self): - """Start this client's checker and timeout hooks""" + """Start this clients checker and timeout hooks""" # Schedule a new checker to be started an 'interval' from now, # and every interval from then on. self.checker_initiator_tag = gobject.timeout_add\ @@ -205,18 +163,12 @@ """Stop this client. The possibility that this client might be restarted is left open, but not currently used.""" - # If this client doesn't have a secret, it is already stopped. - if self.secret: - logger.debug(u"Stopping client %s", self.name) - self.secret = None - else: - return False - if hasattr(self, "stop_initiator_tag") \ - and self.stop_initiator_tag: + logger.debug(u"Stopping client %s", self.name) + self.secret = None + if self.stop_initiator_tag: gobject.source_remove(self.stop_initiator_tag) self.stop_initiator_tag = None - if hasattr(self, "checker_initiator_tag") \ - and self.checker_initiator_tag: + if self.checker_initiator_tag: gobject.source_remove(self.checker_initiator_tag) self.checker_initiator_tag = None self.stop_checker() @@ -225,13 +177,19 @@ # Do not run this again if called by a gobject.timeout_add return False def __del__(self): - self.stop_hook = None - self.stop() + # Some code duplication here and in stop() + if hasattr(self, "stop_initiator_tag") \ + and self.stop_initiator_tag: + gobject.source_remove(self.stop_initiator_tag) + self.stop_initiator_tag = None + if hasattr(self, "checker_initiator_tag") \ + and self.checker_initiator_tag: + gobject.source_remove(self.checker_initiator_tag) + self.checker_initiator_tag = None + self.stop_checker() def checker_callback(self, pid, condition): """The checker has completed, so take appropriate actions.""" now = datetime.datetime.now() - self.checker_callback_tag = None - self.checker = None if os.WIFEXITED(condition) \ and (os.WEXITSTATUS(condition) == 0): logger.debug(u"Checker for %(name)s succeeded", @@ -247,18 +205,12 @@ else: logger.debug(u"Checker for %(name)s failed", vars(self)) + self.checker = None + self.checker_callback_tag = None def start_checker(self): """Start a new checker subprocess if one is not running. If a checker already exists, leave it running and do nothing.""" - # The reason for not killing a running checker is that if we - # did that, then if a checker (for some reason) started - # running slowly and taking more than 'interval' time, the - # client would inevitably timeout, since no checker would get - # a chance to run to completion. If we instead leave running - # checkers alone, the checker would have to take more time - # than 'timeout' for the client to be declared invalid, which - # is as it should be. if self.checker is None: try: command = self.check_command % self.fqdn @@ -289,20 +241,13 @@ return True def stop_checker(self): """Force the checker process, if any, to stop.""" - if self.checker_callback_tag: - gobject.source_remove(self.checker_callback_tag) - self.checker_callback_tag = None if not hasattr(self, "checker") or self.checker is None: return - logger.debug("Stopping checker for %(name)s", vars(self)) - try: - os.kill(self.checker.pid, signal.SIGTERM) - #os.sleep(0.5) - #if self.checker.poll() is None: - # os.kill(self.checker.pid, signal.SIGKILL) - except OSError, error: - if error.errno != errno.ESRCH: - raise + gobject.source_remove(self.checker_callback_tag) + self.checker_callback_tag = None + os.kill(self.checker.pid, signal.SIGTERM) + if self.checker.poll() is None: + os.kill(self.checker.pid, signal.SIGKILL) self.checker = None def still_valid(self, now=None): """Has the timeout not yet passed for this client?""" @@ -315,7 +260,7 @@ def peer_certificate(session): - "Return the peer's OpenPGP certificate as a bytestring" + "Return an OpenPGP data packet string for the peer's certificate" # If not an OpenPGP certificate... if gnutls.library.functions.gnutls_certificate_type_get\ (session._c_object) \ @@ -332,7 +277,7 @@ def fingerprint(openpgp): - "Convert an OpenPGP bytestring to a hexdigit fingerprint string" + "Convert an OpenPGP data string to a hexdigit fingerprint string" # New empty GnuTLS certificate crt = gnutls.library.types.gnutls_openpgp_crt_t() gnutls.library.functions.gnutls_openpgp_crt_init\ @@ -397,7 +342,7 @@ return logger.debug(u"Fingerprint: %s", fpr) client = None - for c in self.server.clients: + for c in clients: if c.fingerprint == fpr: client = c break @@ -504,7 +449,7 @@ def add_service(): - """Derived from the Avahi example code""" + """From the Avahi server example code""" global group, serviceName, serviceType, servicePort, serviceTXT, \ domain, host if group is None: @@ -529,7 +474,7 @@ def remove_service(): - """From the Avahi example code""" + """From the Avahi server example code""" global group if not group is None: @@ -537,7 +482,7 @@ def server_state_changed(state): - """Derived from the Avahi example code""" + """From the Avahi server example code""" if state == avahi.SERVER_COLLISION: logger.warning(u"Server name collision") remove_service() @@ -546,7 +491,7 @@ def entry_group_state_changed(state, error): - """Derived from the Avahi example code""" + """From the Avahi server example code""" global serviceName, server, rename_count logger.debug(u"state change: %i", state) @@ -622,18 +567,13 @@ sys.exit(status) -def main(): - global exitstatus +if __name__ == '__main__': exitstatus = 0 - global main_loop_started main_loop_started = False - parser = OptionParser() parser.add_option("-i", "--interface", type="string", default=None, metavar="IF", help="Bind to interface IF") - parser.add_option("-a", "--address", type="string", default=None, - help="Address to listen for requests on") parser.add_option("-p", "--port", type="int", default=None, help="Port number to receive requests on") parser.add_option("--timeout", type="string", # Parsed later @@ -666,13 +606,10 @@ # Parse config file defaults = { "checker": "fping -q -- %%(fqdn)s" } client_config = ConfigParser.SafeConfigParser(defaults) - #client_config.readfp(open("global.conf"), "global.conf") + #client_config.readfp(open("secrets.conf"), "secrets.conf") client_config.read("mandos-clients.conf") - global main_loop - global bus - global server - # From the Avahi example code + # From the Avahi server example code DBusGMainLoop(set_as_default=True ) main_loop = gobject.MainLoop() bus = dbus.SystemBus() @@ -710,14 +647,13 @@ def cleanup(): "Cleanup function; run on exit" global group - # From the Avahi example code + # From the Avahi server example code if not group is None: group.Free() group = None # End of Avahi example code - while clients: - client = clients.pop() + for client in clients: client.stop_hook = None client.stop() @@ -731,20 +667,18 @@ for client in clients: client.start() - tcp_server = IPv6_TCPServer((options.address, options.port), + tcp_server = IPv6_TCPServer((None, options.port), tcp_handler, options=options, clients=clients) # Find out what random port we got - global servicePort servicePort = tcp_server.socket.getsockname()[1] logger.debug(u"Now listening on port %d", servicePort) if options.interface is not None: - global serviceInterface serviceInterface = if_nametoindex(options.interface) - # From the Avahi example code + # From the Avahi server example code server.connect_to_signal("StateChanged", server_state_changed) try: server_state_changed(server.GetState()) @@ -758,7 +692,6 @@ tcp_server.handle_request(*args[2:], **kwargs) or True) try: - logger.debug("Starting main loop") main_loop_started = True main_loop.run() except KeyboardInterrupt: @@ -766,6 +699,3 @@ print sys.exit(exitstatus) - -if __name__ == '__main__': - main()