=== modified file 'Makefile' --- Makefile 2008-01-19 04:09:06 +0000 +++ Makefile 2008-07-20 02:52:20 +0000 @@ -1,10 +1,10 @@ -CXXFLAGS=-Wall -W -g +CFLAGS="-Wall -std=gnu99" LDFLAGS=-lgnutls -all: client server +all: plugbasedclient clean: - rm -f server client client_debug + rm -f plugbasedclient client_debug: client mv -f client client.tmp === removed file 'client.cpp' --- client.cpp 2008-01-30 17:28:18 +0000 +++ client.cpp 1970-01-01 00:00:00 +0000 @@ -1,213 +0,0 @@ -extern "C" { -#include // getaddrinfo, gai_strerror, socket, inet_pton - // connect -#include // getaddrinfo, gai_strerror, socket, inet_pton - // connect -#include // close, STDIN_FILENO, STDOUT_FILENO -#include // getaddrinfo, gai_strerror -#include // inet_pton -#include // select -#include -#include // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS -#include // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS -#include // struct termios, tcsetattr, tcgetattr, TCSAFLUSH, ECHO -} - -#include // perror -#include // memset -#include // std::string, std::getline -#include // cin, cout, cerr -#include // << - -#define SOCKET_ERR(err,s) if(err<0) {perror(s); status = 1; goto quit;} -#define PORT 49001 - -#ifndef CERT_ROOT -#define CERT_ROOT "/conf/conf.d/cryptkeyreq/" -#endif -#define CERTFILE CERT_ROOT "client-cert.pem" -#define KEYFILE CERT_ROOT "client-key.pem" -#define CAFILE CERT_ROOT "ca.pem" - -gnutls_certificate_credentials_t x509_cred; - -gnutls_session_t -initgnutls(){ - gnutls_session_t session; - -#ifdef DEBUG - std::cerr << "Initiate certificates\n"; -#endif - - gnutls_global_init (); - - /* X509 stuff */ - gnutls_certificate_allocate_credentials (&x509_cred); - gnutls_certificate_set_x509_trust_file (x509_cred, CAFILE, GNUTLS_X509_FMT_PEM); - gnutls_certificate_set_x509_key_file (x509_cred, CERTFILE, KEYFILE, - GNUTLS_X509_FMT_PEM); - - //Gnutls stuff - gnutls_init (&session, GNUTLS_CLIENT); - gnutls_set_default_priority (session); - gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred); - return session; -} - - -int main (){ - int udp_sd, tcp_sd, ret; - char buffer[4096]; - struct sockaddr_in6 to; - struct sockaddr_in6 from; - gnutls_session_t session; - fd_set rfds_orig; - struct timeval timeout; - - struct termios t_old, t_new; - int status = 0; - - if (tcgetattr (STDIN_FILENO, &t_old) != 0){ - return 1; - } - - session = initgnutls (); - -#ifdef DEBUG - std::cerr << "Open ipv6 UDP\n"; -#endif - - udp_sd = socket(PF_INET6, SOCK_DGRAM, 0); - SOCKET_ERR(udp_sd,"socket"); - -#ifdef DEBUG - std::cerr << "Open socket with socket nr: " << udp_sd << '\n'; -#endif - - { - int flag = 1; - ret = setsockopt(udp_sd, SOL_SOCKET, SO_BROADCAST, & flag, sizeof(flag)); - SOCKET_ERR(ret,"setsockopt broadcast"); - } - - ret = setsockopt(udp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5); - SOCKET_ERR(ret,"setsockopt bindtodevice"); - - memset (&to, '\0', sizeof (to)); - to.sin6_family = AF_INET6; - ret = inet_pton(AF_INET6, "ff02::1" , &to.sin6_addr); - SOCKET_ERR(ret,"inet_pton"); - to.sin6_port = htons (PORT); // Server Port number - - struct ifreq network; - - strcpy(network.ifr_name, "eth0"); - - ret = ioctl(udp_sd, SIOCGIFFLAGS, &network); - SOCKET_ERR(ret,"ioctl SIOCGIFFLAGS"); - - network.ifr_flags |= IFF_UP; - - ret = ioctl(udp_sd, SIOCSIFFLAGS, &network); - SOCKET_ERR(ret,"ioctl SIOCSIFFLAGS"); - - FD_ZERO(&rfds_orig); - FD_SET(udp_sd, &rfds_orig); - FD_SET(STDIN_FILENO, &rfds_orig); - - t_new = t_old; - t_new.c_lflag &= ~ECHO; - if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &t_new) != 0){ - return 1; - } - - for(;;){ - for(;;){ - -#ifdef DEBUG - std::cerr << "Sending Marco on UDP\n"; -#endif - ret = sendto(udp_sd, "Marco", 5, 0, reinterpret_cast(&to), sizeof(to)); - if (ret < 0){ - perror("sendto"); - } - - fd_set rfds = rfds_orig; - timeout.tv_sec = 10; - timeout.tv_usec = 0; - - std::cerr << "Password: "; - - ret = select(udp_sd+1, &rfds, 0, 0, & timeout); - SOCKET_ERR(udp_sd,"select"); - - if (ret){ - if (FD_ISSET(STDIN_FILENO, &rfds)){ - std::string buffer; - std::getline(std::cin, buffer); - std::cerr << '\n'; - std::cout << buffer; - goto quit; - } - - socklen_t from_len = sizeof(from); - ret = recvfrom(udp_sd,buffer,512,0, reinterpret_cast(& from), - & from_len); - SOCKET_ERR(ret,"recv"); - - if (strncmp(buffer,"Polo", 4) == 0){ - break; - } - } - std::cerr << '\r'; - } - - - tcp_sd = socket(PF_INET6, SOCK_STREAM, 0); - SOCKET_ERR(tcp_sd,"socket"); - - setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5); - SOCKET_ERR(ret,"setsockopt bindtodevice"); - - memset(&to,0,sizeof(to)); - to.sin6_family = from.sin6_family; - to.sin6_port = from.sin6_port; - to.sin6_addr = from.sin6_addr; - to.sin6_scope_id = from.sin6_scope_id; - - ret = connect(tcp_sd,reinterpret_cast(&to),sizeof(to)); - if (ret < 0){ - perror("connect"); - continue; - } - - gnutls_transport_set_ptr (session, reinterpret_cast (tcp_sd)); - - ret = gnutls_handshake (session); - - if (ret < 0) - { - std::cerr << "\n*** Handshake failed ***\n"; - gnutls_perror (ret); - continue; - } - - //retrive password - ret = gnutls_record_recv (session, buffer, sizeof(buffer)); - - write(STDOUT_FILENO,buffer,ret); - - //shutdown procedure - gnutls_bye (session, GNUTLS_SHUT_RDWR); - close(tcp_sd); - gnutls_deinit (session); - gnutls_certificate_free_credentials (x509_cred); - gnutls_global_deinit (); - break; - } - close(udp_sd); - - quit: - tcsetattr (STDIN_FILENO, TCSAFLUSH, &t_old); - return status; -} === modified file 'mandos-clients.conf' --- mandos-clients.conf 2008-07-19 18:43:24 +0000 +++ mandos-clients.conf 2008-07-20 02:52:20 +0000 @@ -1,10 +1,10 @@ # Example -[foo] -fingerprint = 3e393aeaefb84c7e89e2f547b3a107558fca3a27 -secfile = openpgp/secret.txt.asc -fqdn = foo.example.org -checker = echo %%(fqdn)s >&2; false - +#[foo] +#fingerprint = 3e393aeaefb84c7e89e2f547b3a107558fca3a27 +#secfile = openpgp/secret.txt.asc +#fqdn = foo.example.org +#checker = echo %%(fqdn)s >&2; false +# [braxen_client] fingerprint = 7788 2722 5BA7 DE53 9C5A 7CFA 59CF F7CD BD9A 5920 secret = === added file 'plugbasedclient.c' --- plugbasedclient.c 1970-01-01 00:00:00 +0000 +++ plugbasedclient.c 2008-07-20 02:52:20 +0000 @@ -0,0 +1,182 @@ +#include /* popen, fileno */ +#include /* and, or, not */ +#include /* DIR, opendir, stat, struct stat, waitpid, + WIFEXITED, WEXITSTATUS, wait */ +#include /* wait */ +#include /* DIR, opendir */ +#include /* stat, struct stat */ +#include /* stat, struct stat, chdir */ +#include /* EXIT_FAILURE */ +#include /* fd_set, select, FD_ZERO, FD_SET, FD_ISSET */ +#include /* strlen, strcpy, strcat */ +#include /* true */ +#include /* waitpid, WIFEXITED, WEXITSTATUS */ +#include /* errno */ + +struct process; + +typedef struct process{ + pid_t pid; + int fd; + char *buffer; + int buffer_size; + int buffer_length; + struct process *next; +} process; + +#define BUFFER_SIZE 256 + +int main(int argc, char *argv[]){ + char plugindir[] = "plugins.d"; + size_t d_name_len, plugindir_len = sizeof(plugindir)-1; + DIR *dir; + struct dirent *dirst; + struct stat st; + fd_set rfds_orig; + int ret, maxfd = 0; + process *process_list = NULL; + + dir = opendir(plugindir); + + if(dir == NULL){ + fprintf(stderr, "Can not open directory\n"); + return EXIT_FAILURE; + } + + FD_ZERO(&rfds_orig); + + while(true){ + dirst = readdir(dir); + + // All directory entries have been processed + if(dirst == NULL){ + break; + } + + d_name_len = strlen(dirst->d_name); + + // Ignore dotfiles and backup files + if (dirst->d_name[0] == '.' + or dirst->d_name[d_name_len - 1] == '~'){ + continue; + } + + char *filename = malloc(d_name_len + plugindir_len + 1); + strcpy(filename, plugindir); + strcat(filename, "/"); + strcat(filename, dirst->d_name); + + stat(filename, &st); + + if (S_ISREG(st.st_mode) and (access(filename, X_OK) == 0)){ + // Starting a new process to be watched + process *new_process = malloc(sizeof(process)); + int pipefd[2]; + pipe(pipefd); + new_process->pid = fork(); + if(new_process->pid == 0){ + /* this is the child process */ + closedir(dir); + 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 *) * argc + 1); + new_argv[0] = filename; + for(int i = 1; i < argc; i++){ + new_argv[i] = argv[i]; + } + new_argv[argc] = NULL; + if(execv(filename, new_argv) < 0){ + perror(argv[0]); + close(pipefd[1]); + exit(EXIT_FAILURE); + } + /* no return */ + } + close(pipefd[1]); /* close unused write end of pipe */ + new_process->fd = pipefd[0]; + new_process->buffer = malloc(BUFFER_SIZE); + if (new_process->buffer == NULL){ + perror(argv[0]); + goto end; + } + new_process->buffer_size = BUFFER_SIZE; + new_process->buffer_length = 0; + FD_SET(new_process->fd, &rfds_orig); + + if (maxfd < new_process->fd){ + maxfd = new_process->fd; + } + + //List handling + new_process->next = process_list; + process_list = new_process; + } + } + + closedir(dir); + + if (process_list != NULL){ + while(true){ + fd_set rfds = rfds_orig; + int select_ret = select(maxfd+1, &rfds, NULL, NULL, NULL); + if (select_ret == -1){ + perror(argv[0]); + goto end; + }else{ + for(process *process_itr = process_list; process_itr != NULL; + process_itr = process_itr->next){ + if(FD_ISSET(process_itr->fd, &rfds)){ + if(process_itr->buffer_length + BUFFER_SIZE + > process_itr->buffer_size){ + process_itr->buffer = realloc(process_itr->buffer, + process_itr->buffer_size + + BUFFER_SIZE); + if (process_itr->buffer == NULL){ + perror(argv[0]); + goto end; + } + process_itr->buffer_size += BUFFER_SIZE; + } + ret = read(process_itr->fd, process_itr->buffer + + process_itr->buffer_length, BUFFER_SIZE); + process_itr->buffer_length+=ret; + if(ret == 0){ + /* got EOF */ + /* wait for process exit */ + int status; + waitpid(process_itr->pid, &status, 0); + if(WIFEXITED(status) and WEXITSTATUS(status) == 0){ + write(STDOUT_FILENO, process_itr->buffer, + process_itr->buffer_length); + goto end; + } else { + FD_CLR(process_itr->fd, &rfds_orig); + } + } + } + } + } + } + } + + end: + for(process *process_itr = process_list; process_itr != NULL; + process_itr = process_itr->next){ + close(process_itr->fd); + kill(process_itr->pid, SIGTERM); + free(process_itr->buffer); + } + + while(true){ + int status; + ret = wait(&status); + if (ret == -1){ + if(errno != ECHILD){ + perror("wait"); + } + break; + } + } + return EXIT_SUCCESS; +} === added directory 'plugins.d' === 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 === added file 'plugins.d/mandosclient.c' --- plugins.d/mandosclient.c 1970-01-01 00:00:00 +0000 +++ plugins.d/mandosclient.c 2008-07-20 02:52:20 +0000 @@ -0,0 +1,571 @@ +/* $Id$ */ + +/* PLEASE NOTE * + * This file demonstrates how to use Avahi's core API, this is + * the embeddable mDNS stack for embedded applications. + * + * 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. + */ + +/*** + 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 + +#include +#include +#include +#include +#include /* if_nametoindex */ + +#include +#include +#include +#include +#include +#include + +//mandos client part +#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 +#include /* true */ +#include /* memset */ +#include /* inet_pton() */ +#include /* not */ + +// gpgme +#include /* perror() */ +#include + + +#ifndef CERT_ROOT +#define CERT_ROOT "/conf/conf.d/cryptkeyreq/" +#endif +#define CERTFILE CERT_ROOT "openpgp-client.txt" +#define KEYFILE CERT_ROOT "openpgp-client-key.txt" +#define BUFFER_SIZE 256 +#define DH_BITS 1024 + +typedef struct { + gnutls_session_t session; + gnutls_certificate_credentials_t cred; + gnutls_dh_params_t dh_params; +} encrypted_session; + + +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; + size_t new_packet_capacity = 0; + size_t new_packet_length = 0; + gpgme_engine_info_t engine_info; + + /* Init GPGME */ + gpgme_check_version(NULL); + gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP); + + /* Set GPGME home directory */ + rc = gpgme_get_engine_info (&engine_info); + if (rc != GPG_ERR_NO_ERROR){ + fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n", + gpgme_strsource(rc), gpgme_strerror(rc)); + return -1; + } + while(engine_info != NULL){ + if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){ + gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP, + engine_info->file_name, homedir); + break; + } + engine_info = engine_info->next; + } + if(engine_info == NULL){ + fprintf(stderr, "Could not set home dir to %s\n", homedir); + return -1; + } + + /* Create new GPGME data buffer from packet buffer */ + rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0); + if (rc != GPG_ERR_NO_ERROR){ + fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n", + gpgme_strsource(rc), gpgme_strerror(rc)); + return -1; + } + + /* Create new empty GPGME data buffer for the plaintext */ + rc = gpgme_data_new(&dh_plain); + if (rc != GPG_ERR_NO_ERROR){ + fprintf(stderr, "bad gpgme_data_new: %s: %s\n", + gpgme_strsource(rc), gpgme_strerror(rc)); + return -1; + } + + /* Create new GPGME "context" */ + rc = gpgme_new(&ctx); + if (rc != GPG_ERR_NO_ERROR){ + fprintf(stderr, "bad gpgme_new: %s: %s\n", + gpgme_strsource(rc), gpgme_strerror(rc)); + return -1; + } + + /* 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; + } + +/* 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, 0, SEEK_SET); + + *new_packet = 0; + while(true){ + if (new_packet_length + BUFFER_SIZE > new_packet_capacity){ + *new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE); + if (*new_packet == NULL){ + perror("realloc"); + return -1; + } + new_packet_capacity += 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){ + perror("gpgme_data_read"); + return -1; + } + new_packet_length += ret; + } + + /* Delete the GPGME plaintext data buffer */ + gpgme_data_release(dh_plain); + return new_packet_length; +} + +static const char * safer_gnutls_strerror (int value) { + const char *ret = gnutls_strerror (value); + if (ret == NULL) + ret = "(unknown)"; + return ret; +} + +void debuggnutls(int level, const char* string){ + fprintf(stderr, "%s", string); +} + +int initgnutls(encrypted_session *es){ + const char *err; + int ret; + + if ((ret = gnutls_global_init ()) + != GNUTLS_E_SUCCESS) { + fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret)); + return -1; + } + + /* 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)); + return -1; + } + + 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", + ret, CERTFILE, KEYFILE); + fprintf(stdout, "The Error is: %s\n", + safer_gnutls_strerror(ret)); + return -1; + } + + //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 + if ((ret = gnutls_init (&es->session, GNUTLS_SERVER)) + != GNUTLS_E_SUCCESS){ + 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", + safer_gnutls_strerror(ret)); + return -1; + } + + if ((ret = gnutls_credentials_set + (es->session, GNUTLS_CRD_CERTIFICATE, es->cred)) + != GNUTLS_E_SUCCESS) { + fprintf(stderr, "Error setting a credentials set: %s\n", + safer_gnutls_strerror(ret)); + return -1; + } + + /* ignore client certificate if any. */ + gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE); + + gnutls_dh_set_prime_bits (es->session, DH_BITS); + + return 0; +} + +void empty_log(AvahiLogLevel level, const char *txt){} + +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; + int retval = 0; + + + tcp_sd = socket(PF_INET6, SOCK_STREAM, 0); + if(tcp_sd < 0) { + perror("socket"); + return -1; + } + + ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5); + if(tcp_sd < 0) { + perror("setsockopt bindtodevice"); + return -1; + } + + memset(&to,0,sizeof(to)); + to.sin6_family = AF_INET6; + ret = inet_pton(AF_INET6, ip, &ip_addr); + if (ret < 0 ){ + perror("inet_pton"); + return -1; + } + if(ret == 0){ + fprintf(stderr, "Bad address: %s\n", ip); + return -1; + } + to.sin6_port = htons(port); + to.sin6_scope_id = if_nametoindex("eth0"); + + ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to)); + if (ret < 0){ + perror("connect"); + return -1; + } + + ret = initgnutls (&es); + if (ret != 0){ + retval = -1; + return -1; + } + + + gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd); + + ret = gnutls_handshake (es.session); + + if (ret != GNUTLS_E_SUCCESS){ + fprintf(stderr, "\n*** Handshake failed ***\n"); + gnutls_perror (ret); + retval = -1; + goto exit; + } + + //retrive password + while(true){ + if (buffer_length + BUFFER_SIZE > buffer_capacity){ + buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE); + if (buffer == NULL){ + perror("realloc"); + goto exit; + } + buffer_capacity += BUFFER_SIZE; + } + + ret = gnutls_record_recv + (es.session, buffer+buffer_length, BUFFER_SIZE); + if (ret == 0){ + break; + } + if (ret < 0){ + switch(ret){ + case GNUTLS_E_INTERRUPTED: + case GNUTLS_E_AGAIN: + break; + case GNUTLS_E_REHANDSHAKE: + ret = gnutls_handshake (es.session); + if (ret < 0){ + fprintf(stderr, "\n*** Handshake failed ***\n"); + gnutls_perror (ret); + retval = -1; + goto exit; + } + break; + default: + 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 += ret; + } + } + + if (buffer_length > 0){ + 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); + } + } + + free(buffer); + + //shutdown procedure + gnutls_bye (es.session, GNUTLS_SHUT_RDWR); + exit: + close(tcp_sd); + gnutls_deinit (es.session); + gnutls_certificate_free_credentials (es.cred); + gnutls_global_deinit (); + return retval; +} + +static AvahiSimplePoll *simple_poll = NULL; +static AvahiServer *server = NULL; + +static void resolve_callback( + AvahiSServiceResolver *r, + AVAHI_GCC_UNUSED AvahiIfIndex interface, + AVAHI_GCC_UNUSED AvahiProtocol protocol, + AvahiResolverEvent event, + const char *name, + const char *type, + const char *domain, + const char *host_name, + const AvahiAddress *address, + uint16_t port, + AvahiStringList *txt, + AvahiLookupResultFlags flags, + AVAHI_GCC_UNUSED void* userdata) { + + 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); +} + +static void browse_callback( + AvahiSServiceBrowser *b, + AvahiIfIndex interface, + AvahiProtocol protocol, + AvahiBrowserEvent event, + const char *name, + const char *type, + const char *domain, + AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, + void* userdata) { + + AvahiServer *s = userdata; + assert(b); + + /* Called whenever a new services becomes available on the LAN or is removed from the LAN */ + + switch (event) { + + 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; + } +} + +int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) { + AvahiServerConfig config; + AvahiSServiceBrowser *sb = NULL; + int error; + int ret = 1; + + avahi_set_log_function(empty_log); + + /* Initialize the psuedo-RNG */ + srand(time(NULL)); + + /* Allocate main loop object */ + if (!(simple_poll = avahi_simple_poll_new())) { + fprintf(stderr, "Failed to create simple poll object.\n"); + goto fail; + } + + /* Do not publish any local records */ + avahi_server_config_init(&config); + config.publish_hinfo = 0; + config.publish_addresses = 0; + 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); + + /* Free the configuration data */ + avahi_server_config_free(&config); + + /* Check wether creating the server object succeeded */ + if (!server) { + fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error)); + goto fail; + } + + /* Create the service browser */ + 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 */ + avahi_simple_poll_loop(simple_poll); + + ret = 0; + +fail: + + /* Cleanup things */ + if (sb) + avahi_s_service_browser_free(sb); + + if (server) + avahi_server_free(server); + + if (simple_poll) + avahi_simple_poll_free(simple_poll); + + return ret; +} === added file 'plugins.d/passprompt.c' --- plugins.d/passprompt.c 1970-01-01 00:00:00 +0000 +++ plugins.d/passprompt.c 2008-07-20 02:52:20 +0000 @@ -0,0 +1,95 @@ +#define _GNU_SOURCE /* getline() */ +#define _FORTIFY_SOURCE 2 +#include /* struct termios, tcsetattr(), + TCSAFLUSH, tcgetattr(), ECHO */ +#include /* struct termios, tcsetattr(), + STDIN_FILENO, TCSAFLUSH, + tcgetattr(), ECHO */ +#include /* sig_atomic_t, raise(), struct + sigaction, sigemptyset(), + sigaction(), sigaddset(), SIGINT, + SIGQUIT, SIGHUP, SIGTERM */ +#include /* NULL, size_t */ +#include /* ssize_t */ +#include /* EXIT_SUCCESS, EXIT_FAILURE */ +#include /* fprintf(), stderr, getline(), + stdin, feof(), perror(), fputc(), + stdout */ +#include /* errno, EINVAL */ +#include /* or, not */ +#include /* bool, false, true */ + +volatile bool quit_now = false; + +void termination_handler(int signum){ + quit_now = true; +} + +int main(int argc, char **argv){ + ssize_t ret = -1; + size_t n; + struct termios t_new, t_old; + char *buffer = NULL; + int status = EXIT_SUCCESS; + struct sigaction old_action, + new_action = { .sa_handler = termination_handler, + .sa_flags = 0 }; + + if (tcgetattr(STDIN_FILENO, &t_old) != 0){ + return EXIT_FAILURE; + } + + sigemptyset(&new_action.sa_mask); + sigaddset(&new_action.sa_mask, SIGINT); + sigaddset(&new_action.sa_mask, SIGQUIT); + sigaddset(&new_action.sa_mask, SIGHUP); + sigaddset(&new_action.sa_mask, SIGTERM); + sigaction(SIGINT, NULL, &old_action); + if (old_action.sa_handler != SIG_IGN) + sigaction(SIGINT, &new_action, NULL); + sigaction(SIGQUIT, NULL, &old_action); + if (old_action.sa_handler != SIG_IGN) + sigaction(SIGQUIT, &new_action, NULL); + sigaction(SIGHUP, NULL, &old_action); + if (old_action.sa_handler != SIG_IGN) + sigaction(SIGHUP, &new_action, NULL); + sigaction(SIGTERM, NULL, &old_action); + if (old_action.sa_handler != SIG_IGN) + sigaction(SIGTERM, &new_action, NULL); + + t_new = t_old; + t_new.c_lflag &= ~ECHO; + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_new) != 0){ + perror("tcsetattr-echo"); + return EXIT_FAILURE; + } + + while(true){ + if (quit_now){ + status = EXIT_FAILURE; + break; + } + fprintf(stderr, "Password: "); + ret = getline(&buffer, &n, stdin); + if (ret > 0){ + fprintf(stdout, "%s", buffer); + status = EXIT_SUCCESS; + break; + } + // ret == 0 makes no other sence than to retry to read from stdin + if (ret < 0){ + if (errno != EINTR and not feof(stdin)){ + perror("getline"); + status = EXIT_FAILURE; + break; + } + } + fputc('\n', stderr); + } + + if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &t_old) != 0){ + perror("tcsetattr+echo"); + } + + return status; +} === modified file 'server.py' --- server.py 2008-07-19 18:43:24 +0000 +++ server.py 2008-07-20 02:52:20 +0000 @@ -28,6 +28,14 @@ from dbus.mainloop.glib import DBusGMainLoop import ctypes +import logging +import logging.handlers + +# logghandler.setFormatter(logging.Formatter('%(levelname)s %(message)s') + +logger = logging.Logger('mandos') +logger.addHandler(logging.handlers.SysLogHandler(facility = logging.handlers.SysLogHandler.LOG_DAEMON)) + # 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 server example code. @@ -149,8 +157,7 @@ """Stop this client. The possibility that this client might be restarted is left open, but not currently used.""" - if debug: - sys.stderr.write(u"Stopping client %s\n" % self.name) + logger.debug(u"Stopping client %s", self.name) self.secret = None if self.stop_initiator_tag: gobject.source_remove(self.stop_initiator_tag) @@ -179,38 +186,40 @@ now = datetime.datetime.now() if os.WIFEXITED(condition) \ and (os.WEXITSTATUS(condition) == 0): - if debug: - sys.stderr.write(u"Checker for %(name)s succeeded\n" - % vars(self)) + logger.debug(u"Checker for %(name)s succeeded", + vars(self)) self.last_seen = now gobject.source_remove(self.stop_initiator_tag) self.stop_initiator_tag = gobject.timeout_add\ (self._timeout_milliseconds, self.stop) - elif debug: - if not os.WIFEXITED(condition): - sys.stderr.write(u"Checker for %(name)s crashed?\n" - % vars(self)) - else: - sys.stderr.write(u"Checker for %(name)s failed\n" - % vars(self)) - self.checker = None + if not os.WIFEXITED(condition): + logger.warning(u"Checker for %(name)s crashed?", + vars(self)) + 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.""" if self.checker is None: - if debug: - sys.stderr.write(u"Starting checker for %s\n" - % self.name) + logger.debug(u"Starting checker for %s", + self.name) try: command = self.check_command % self.fqdn except TypeError: escaped_attrs = dict((key, re.escape(str(val))) for key, val in vars(self).iteritems()) - command = self.check_command % escaped_attrs + try: + command = self.check_command % escaped_attrs + except TypeError, error: + logger.critical(u'Could not format string "%s": %s', + self.check_command, error) + return True # Try again later try: self.checker = subprocess.\ Popen(command, @@ -222,8 +231,8 @@ self.\ checker_callback) except subprocess.OSError, error: - sys.stderr.write(u"Failed to start subprocess: %s\n" - % error) + logger.error(u"Failed to start subprocess: %s", + error) # Re-run this periodically if run by gobject.timeout_add return True def stop_checker(self): @@ -298,12 +307,8 @@ Note: This will run in its own forked process.""" def handle(self): - if debug: - sys.stderr.write(u"TCP request came\n") - sys.stderr.write(u"Request: %s\n" % self.request) - sys.stderr.write(u"Client Address: %s\n" - % unicode(self.client_address)) - sys.stderr.write(u"Server: %s\n" % self.server) + logger.debug(u"TCP connection from: %s", + unicode(self.client_address)) session = gnutls.connection.ClientSession(self.request, gnutls.connection.\ X509Credentials()) @@ -319,20 +324,17 @@ try: session.handshake() except gnutls.errors.GNUTLSError, error: - if debug: - sys.stderr.write(u"Handshake failed: %s\n" % error) + logger.debug(u"Handshake failed: %s", error) # Do not run session.bye() here: the session is not # established. Just abandon the request. return try: fpr = fingerprint(peer_certificate(session)) except (TypeError, gnutls.errors.GNUTLSError), error: - if debug: - sys.stderr.write(u"Bad certificate: %s\n" % error) + logger.debug(u"Bad certificate: %s", error) session.bye() return - if debug: - sys.stderr.write(u"Fingerprint: %s\n" % fpr) + logger.debug(u"Fingerprint: %s", fpr) client = None for c in clients: if c.fingerprint == fpr: @@ -342,22 +344,20 @@ # that the client timed out while establishing the GnuTLS # session. if (not client) or (not client.still_valid()): - if debug: - if client: - sys.stderr.write(u"Client %(name)s is invalid\n" - % vars(client)) - else: - sys.stderr.write(u"Client not found for " - u"fingerprint: %s\n" % fpr) + if client: + logger.debug(u"Client %(name)s is invalid", + vars(client)) + else: + logger.debug(u"Client not found for fingerprint: %s", + fpr) session.bye() return sent_size = 0 while sent_size < len(client.secret): sent = session.send(client.secret[sent_size:]) - if debug: - sys.stderr.write(u"Sent: %d, remaining: %d\n" - % (sent, len(client.secret) - - (sent_size + sent))) + logger.debug(u"Sent: %d, remaining: %d", + sent, len(client.secret) + - (sent_size + sent)) sent_size += sent session.bye() @@ -391,9 +391,9 @@ self.options.interface) except socket.error, error: if error[0] == errno.EPERM: - sys.stderr.write(u"Warning: No permission to" \ - u" bind to interface %s\n" - % self.options.interface) + logger.warning(u"No permission to" + u" bind to interface %s", + self.options.interface) else: raise error # Only bind(2) the socket if we really need to. @@ -453,9 +453,8 @@ avahi.DBUS_INTERFACE_ENTRY_GROUP) group.connect_to_signal('StateChanged', entry_group_state_changed) - if debug: - sys.stderr.write(u"Adding service '%s' of type '%s' ...\n" - % (serviceName, serviceType)) + logger.debug(u"Adding service '%s' of type '%s' ...", + serviceName, serviceType) group.AddService( serviceInterface, # interface @@ -479,7 +478,7 @@ def server_state_changed(state): """From the Avahi server example code""" if state == avahi.SERVER_COLLISION: - sys.stderr.write(u"WARNING: Server name collision\n") + logger.warning(u"Server name collision") remove_service() elif state == avahi.SERVER_RUNNING: add_service() @@ -489,30 +488,28 @@ """From the Avahi server example code""" global serviceName, server, rename_count - if debug: - sys.stderr.write(u"state change: %i\n" % state) + logger.debug(u"state change: %i", state) if state == avahi.ENTRY_GROUP_ESTABLISHED: - if debug: - sys.stderr.write(u"Service established.\n") + logger.debug(u"Service established.") elif state == avahi.ENTRY_GROUP_COLLISION: rename_count = rename_count - 1 if rename_count > 0: name = server.GetAlternativeServiceName(name) - sys.stderr.write(u"WARNING: Service name collision, " - u"changing name to '%s' ...\n" % name) + logger.warning(u"Service name collision, " + u"changing name to '%s' ...", name) remove_service() add_service() else: - sys.stderr.write(u"ERROR: No suitable service name found " - u"after %i retries, exiting.\n" - % n_rename) + logger.error(u"No suitable service name found " + u"after %i retries, exiting.", + n_rename) main_loop.quit() elif state == avahi.ENTRY_GROUP_FAILURE: - sys.stderr.write(u"Error in group state changed %s\n" - % unicode(error)) + logger.error(u"Error in group state changed %s", + unicode(error)) main_loop.quit() return @@ -603,8 +600,7 @@ def remove_from_clients(client): clients.remove(client) if not clients: - if debug: - sys.stderr.write(u"No clients left, exiting\n") + logger.debug(u"No clients left, exiting") main_loop.quit() clients.update(Set(Client(name=section, options=options, @@ -621,8 +617,7 @@ clients=clients) # Find out what random port we got servicePort = tcp_server.socket.getsockname()[1] - if debug: - sys.stderr.write(u"Now listening on port %d\n" % servicePort) + logger.debug(u"Now listening on port %d", servicePort) if options.interface is not None: serviceInterface = if_nametoindex(options.interface)