=== modified file 'Makefile' --- Makefile 2008-09-03 05:04:40 +0000 +++ Makefile 2008-09-03 19:04:05 +0000 @@ -108,7 +108,7 @@ keydir/secring.gpg keydir/pubring.gpg ./plugin-runner --plugin-dir=plugins.d \ --config-file=plugin-runner.conf \ - --options-for=password-request:--keydir=keydir + --options-for=password-request:--seckey=keydir/seckey.txt,--pubkey=keydir/pubkey.txt # Used by run-client keydir/secring.gpg: keydir/seckey.txt === modified file 'TODO' --- TODO 2008-09-03 17:34:29 +0000 +++ TODO 2008-09-03 19:06:25 +0000 @@ -3,9 +3,6 @@ * [#A] README file * plugin-runner -** [#B] Add more comments to code -** [#B] Add more if(debug) calls -** [#B] Seperate more code to function for more readability * password-request ** [#B] Temporarily lower kernel log level @@ -19,11 +16,6 @@ Must create in preinst if not pre-depending on cryptsetup * password-prompt -** [#C] Use getpass(3)? - Man page says "obsolete", but [[info:libc:getpass][GNU LibC Manual: Reading Passwords]] - does not. See also [[http://sources.redhat.com/ml/libc-alpha/2003-05/msg00251.html][Marcus Brinkmann: Re: getpass obsolete?]] and - [[http://article.gmane.org/gmane.comp.lib.glibc.alpha/4906][Petter Reinholdtsen: Re: getpass obsolete?]], and especially also - [[http://www.steve.org.uk/Reference/Unix/faq_4.html#SEC48][Unix Programming FAQ 3.1 How can I make my program not echo input?]] * mandos (server) ** [#A] /etc/init.d/mandos-server :teddy: @@ -46,6 +38,7 @@ ** List clients ** Disable client ** Enable client +** Reboot timer * Man pages ** Use xinclude for common sections === modified file 'mandos-keygen.xml' --- mandos-keygen.xml 2008-08-31 15:06:39 +0000 +++ mandos-keygen.xml 2008-09-03 19:13:50 +0000 @@ -3,7 +3,7 @@ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ - + ]> @@ -402,12 +402,11 @@ - - BUGS - - None are known at this time. - - + + + + + EXAMPLE === modified file 'mandos.xml' --- mandos.xml 2008-09-02 17:42:53 +0000 +++ mandos.xml 2008-09-03 19:13:50 +0000 @@ -3,7 +3,7 @@ "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [ - + ]> @@ -436,6 +436,10 @@ The console log messages does not show a timestamp. + + This server does not check the expire time of clients’ OpenPGP + keys. + === modified file 'plugins.d/password-request.c' --- plugins.d/password-request.c 2008-09-03 17:11:32 +0000 +++ plugins.d/password-request.c 2008-09-03 19:04:05 +0000 @@ -47,21 +47,24 @@ #include /* socket(), inet_pton(), sockaddr, sockaddr_in6, PF_INET6, SOCK_STREAM, INET6_ADDRSTRLEN, - uid_t, gid_t */ -#include /* PRIu16 */ + uid_t, gid_t, open(), opendir(), DIR */ +#include /* open() */ #include /* socket(), struct sockaddr_in6, struct in6_addr, inet_pton(), connect() */ +#include /* open() */ +#include /* opendir(), struct dirent, readdir() */ +#include /* PRIu16 */ #include /* assert() */ #include /* perror(), errno */ #include /* time() */ #include /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS, if_indextoname(), if_nametoindex(), IF_NAMESIZE */ +#include #include /* close(), SEEK_SET, off_t, write(), getuid(), getgid(), setuid(), setgid() */ -#include #include /* inet_pton(), htons */ #include /* not, and */ #include /* struct argp_option, error_t, struct @@ -98,8 +101,15 @@ #define BUFFER_SIZE 256 +/* + #define PATHDIR "/conf/conf.d/mandos" +*/ + +#define PATHDIR "/conf/conf.d/mandos" +#define SECKEY "seckey.txt" +#define PUBKEY "pupkey.txt" + bool debug = false; -static const char *keydir = "/conf/conf.d/mandos"; static const char mandos_protocol_version[] = "1"; const char *argp_program_version = "password-request 1.0"; const char *argp_program_bug_address = ""; @@ -112,6 +122,7 @@ unsigned int dh_bits; gnutls_dh_params_t dh_params; const char *priority; + gpgme_ctx_t ctx; } mandos_context; /* @@ -132,52 +143,114 @@ } /* - * Decrypt OpenPGP data using keyrings in HOMEDIR. - * Returns -1 on error + * Initialize GPGME. */ -static ssize_t pgp_packet_decrypt (const char *cryptotext, - size_t crypto_size, - char **plaintext, - const char *homedir){ - gpgme_data_t dh_crypto, dh_plain; - gpgme_ctx_t ctx; +static bool init_gpgme(mandos_context *mc, const char *seckey, + const char *pubkey, const char *tempdir){ + int ret; gpgme_error_t rc; - ssize_t ret; - size_t plaintext_capacity = 0; - ssize_t plaintext_length = 0; gpgme_engine_info_t engine_info; + + + /* + * Helper function to insert pub and seckey to the enigne keyring. + */ + bool import_key(const char *filename){ + int fd; + gpgme_data_t pgp_data; + + fd = TEMP_FAILURE_RETRY(open(filename, O_RDONLY)); + if(fd == -1){ + perror("open"); + return false; + } + + rc = gpgme_data_new_from_fd(&pgp_data, fd); + if (rc != GPG_ERR_NO_ERROR){ + fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n", + gpgme_strsource(rc), gpgme_strerror(rc)); + return false; + } + + rc = gpgme_op_import(mc->ctx, pgp_data); + if (rc != GPG_ERR_NO_ERROR){ + fprintf(stderr, "bad gpgme_op_import: %s: %s\n", + gpgme_strsource(rc), gpgme_strerror(rc)); + return false; + } + + ret = TEMP_FAILURE_RETRY(close(fd)); + if(ret == -1){ + perror("close"); + } + gpgme_data_release(pgp_data); + return true; + } if (debug){ - fprintf(stderr, "Trying to decrypt OpenPGP data\n"); + fprintf(stderr, "Initialize gpgme\n"); } - + /* Init GPGME */ gpgme_check_version(NULL); rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP); if (rc != GPG_ERR_NO_ERROR){ fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n", gpgme_strsource(rc), gpgme_strerror(rc)); - return -1; + return false; } - - /* Set GPGME home directory for the OpenPGP engine only */ + + /* Set GPGME home directory for the OpenPGP engine only */ 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; + return false; } while(engine_info != NULL){ if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){ gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP, - engine_info->file_name, homedir); + engine_info->file_name, tempdir); break; } engine_info = engine_info->next; } if(engine_info == NULL){ - fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir); - return -1; + fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir); + return false; + } + + /* Create new GPGME "context" */ + rc = gpgme_new(&(mc->ctx)); + if (rc != GPG_ERR_NO_ERROR){ + fprintf(stderr, "bad gpgme_new: %s: %s\n", + gpgme_strsource(rc), gpgme_strerror(rc)); + return false; + } + + if (not import_key(pubkey) or not import_key(seckey)){ + return false; + } + + return true; +} + +/* + * Decrypt OpenPGP data. + * Returns -1 on error + */ +static ssize_t pgp_packet_decrypt (const mandos_context *mc, + const char *cryptotext, + size_t crypto_size, + char **plaintext){ + gpgme_data_t dh_crypto, dh_plain; + gpgme_error_t rc; + ssize_t ret; + size_t plaintext_capacity = 0; + ssize_t plaintext_length = 0; + + if (debug){ + fprintf(stderr, "Trying to decrypt OpenPGP data\n"); } /* Create new GPGME data buffer from memory cryptotext */ @@ -198,25 +271,16 @@ 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)); - plaintext_length = -1; - goto decrypt_end; - } - /* Decrypt data from the cryptotext data buffer to the plaintext data buffer */ - rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain); + rc = gpgme_op_decrypt(mc->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)); plaintext_length = -1; if (debug){ gpgme_decrypt_result_t result; - result = gpgme_op_decrypt_result(ctx); + result = gpgme_op_decrypt_result(mc->ctx); if (result == NULL){ fprintf(stderr, "gpgme_op_decrypt_result failed\n"); } else { @@ -610,10 +674,9 @@ gnutls_bye (session, GNUTLS_SHUT_RDWR); if (buffer_length > 0){ - decrypted_buffer_size = pgp_packet_decrypt(buffer, + decrypted_buffer_size = pgp_packet_decrypt(mc, buffer, buffer_length, - &decrypted_buffer, - keydir); + &decrypted_buffer); if (decrypted_buffer_size >= 0){ written = 0; while(written < (size_t) decrypted_buffer_size){ @@ -642,7 +705,10 @@ mandos_end: free(buffer); - close(tcp_sd); + ret = TEMP_FAILURE_RETRY(close(tcp_sd)); + if(ret == -1){ + perror("close"); + } gnutls_deinit (session); return retval; } @@ -744,18 +810,6 @@ } } -/* Combines file name and path and returns the malloced new - string. some sane checks could/should be added */ -static char *combinepath(const char *first, const char *second){ - char *tmp; - int ret = asprintf(&tmp, "%s/%s", first, second); - if(ret < 0){ - return NULL; - } - return tmp; -} - - int main(int argc, char *argv[]){ AvahiSServiceBrowser *sb = NULL; int error; @@ -767,15 +821,16 @@ uid_t uid; gid_t gid; char *connect_to = NULL; + char tempdir[] = "/tmp/mandosXXXXXX"; AvahiIfIndex if_index = AVAHI_IF_UNSPEC; - char *pubkeyfilename = NULL; - char *seckeyfilename = NULL; - const char *pubkeyname = "pubkey.txt"; - const char *seckeyname = "seckey.txt"; + const char *seckey = PATHDIR "/" SECKEY; + const char *pubkey = PATHDIR "/" PUBKEY; + mandos_context mc = { .simple_poll = NULL, .server = NULL, .dh_bits = 1024, .priority = "SECURE256" ":!CTYPE-X.509:+CTYPE-OPENPGP" }; bool gnutls_initalized = false; + bool pgpme_initalized = false; { struct argp_option options[] = { @@ -790,10 +845,6 @@ .doc = "Interface that will be used to search for Mandos" " servers", .group = 1 }, - { .name = "keydir", .key = 'd', - .arg = "DIRECTORY", - .doc = "Directory to read the OpenPGP key files from", - .group = 1 }, { .name = "seckey", .key = 's', .arg = "FILE", .doc = "OpenPGP secret key file base name", @@ -828,14 +879,11 @@ case 'i': /* --interface */ interface = arg; break; - case 'd': /* --keydir */ - keydir = arg; - break; case 's': /* --seckey */ - seckeyname = arg; + seckey = arg; break; case 'p': /* --pubkey */ - pubkeyname = arg; + pubkey = arg; break; case 129: /* --dh-bits */ errno = 0; @@ -870,21 +918,7 @@ } } - pubkeyfilename = combinepath(keydir, pubkeyname); - if (pubkeyfilename == NULL){ - perror("combinepath"); - exitcode = EXIT_FAILURE; - goto end; - } - - seckeyfilename = combinepath(keydir, seckeyname); - if (seckeyfilename == NULL){ - perror("combinepath"); - exitcode = EXIT_FAILURE; - goto end; - } - - ret = init_gnutls_global(&mc, pubkeyfilename, seckeyfilename); + ret = init_gnutls_global(&mc, pubkey, seckey); if (ret == -1){ fprintf(stderr, "init_gnutls_global failed\n"); exitcode = EXIT_FAILURE; @@ -892,6 +926,20 @@ } else { gnutls_initalized = true; } + + if(mkdtemp(tempdir) == NULL){ + perror("mkdtemp"); + tempdir[0] = '\0'; + goto end; + } + + if(not init_gpgme(&mc, pubkey, seckey, tempdir)){ + fprintf(stderr, "pgpme_initalized failed\n"); + exitcode = EXIT_FAILURE; + goto end; + } else { + pgpme_initalized = true; + } /* If the interface is down, bring it up */ { @@ -917,7 +965,10 @@ goto end; } } - close(sd); + ret = TEMP_FAILURE_RETRY(close(sd)); + if(ret == -1){ + perror("close"); + } } uid = getuid(); @@ -1043,13 +1094,51 @@ if (mc.simple_poll != NULL) avahi_simple_poll_free(mc.simple_poll); - free(pubkeyfilename); - free(seckeyfilename); if (gnutls_initalized){ gnutls_certificate_free_credentials(mc.cred); gnutls_global_deinit (); } - + + if(pgpme_initalized){ + gpgme_release(mc.ctx); + } + + /* Removes the temp directory used by GPGME */ + if(tempdir[0] != '\0'){ + DIR *d; + struct dirent *direntry; + d = opendir(tempdir); + if(d == NULL){ + perror("opendir"); + } else { + while(true){ + direntry = readdir(d); + if(direntry == NULL){ + break; + } + if (direntry->d_type == DT_REG){ + char *fullname = NULL; + ret = asprintf(&fullname, "%s/%s", tempdir, + direntry->d_name); + if(ret < 0){ + perror("asprintf"); + continue; + } + ret = unlink(fullname); + if(ret == -1){ + fprintf(stderr, "unlink(\"%s\"): %s", + fullname, strerror(errno)); + } + free(fullname); + } + } + } + ret = rmdir(tempdir); + if(ret == -1){ + perror("rmdir"); + } + } + return exitcode; }