2
This file is part of avahi.
4
avahi is free software; you can redistribute it and/or modify it
5
under the terms of the GNU Lesser General Public License as
6
published by the Free Software Foundation; either version 2.1 of the
7
License, or (at your option) any later version.
9
avahi is distributed in the hope that it will be useful, but WITHOUT
10
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12
Public License for more details.
14
You should have received a copy of the GNU Lesser General Public
15
License along with avahi; if not, write to the Free Software
16
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
1
/* -*- coding: utf-8 -*- */
3
* Mandos client - get and decrypt data from a Mandos server
5
* This program is partly derived from an example program for an Avahi
6
* service browser, downloaded from
7
* <http://avahi.org/browser/examples/core-browse-services.c>. This
8
* includes the following functions: "resolve_callback",
9
* "browse_callback", and parts of "main".
12
* Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
14
* This program is free software: you can redistribute it and/or
15
* modify it under the terms of the GNU General Public License as
16
* published by the Free Software Foundation, either version 3 of the
17
* License, or (at your option) any later version.
19
* This program is distributed in the hope that it will be useful, but
20
* WITHOUT ANY WARRANTY; without even the implied warranty of
21
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22
* General Public License for more details.
24
* You should have received a copy of the GNU General Public License
25
* along with this program. If not, see
26
* <http://www.gnu.org/licenses/>.
28
* Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
29
* <https://www.fukt.bsnet.se/~teddy/>.
32
/* Needed by GPGME, specifically gpgme_data_seek() */
20
33
#define _LARGEFILE_SOURCE
21
34
#define _FILE_OFFSET_BITS 64
34
47
#include <avahi-common/error.h>
36
49
//mandos client part
37
#include <sys/types.h> /* socket(), setsockopt(), inet_pton() */
38
#include <sys/socket.h> /* socket(), setsockopt(), struct sockaddr_in6, struct in6_addr, inet_pton() */
39
#include <gnutls/gnutls.h> /* ALL GNUTLS STUFF */
40
#include <gnutls/openpgp.h> /* gnutls with openpgp stuff */
50
#include <sys/types.h> /* socket(), inet_pton() */
51
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
52
struct in6_addr, inet_pton() */
53
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
54
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
42
56
#include <unistd.h> /* close() */
43
57
#include <netinet/in.h>
71
84
} encrypted_session;
74
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
87
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
char **new_packet, const char *homedir){
75
89
gpgme_data_t dh_crypto, dh_plain;
79
size_t new_packet_capacity = 0;
80
size_t new_packet_length = 0;
93
ssize_t new_packet_capacity = 0;
94
ssize_t new_packet_length = 0;
81
95
gpgme_engine_info_t engine_info;
84
fprintf(stderr, "Attempting to decrypt password from gpg packet\n");
98
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
150
165
if (result == NULL){
151
166
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
153
fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
154
fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage);
168
fprintf(stderr, "Unsupported algorithm: %s\n",
169
result->unsupported_algorithm);
170
fprintf(stderr, "Wrong key usage: %d\n",
171
result->wrong_key_usage);
155
172
if(result->file_name != NULL){
156
173
fprintf(stderr, "File name: %s\n", result->file_name);
174
192
gpgme_data_release(dh_crypto);
176
194
/* Seek back to the beginning of the GPGME plaintext data buffer */
177
gpgme_data_seek(dh_plain, 0, SEEK_SET);
195
gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
181
199
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
182
*new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
200
*new_packet = realloc(*new_packet,
201
(unsigned int)new_packet_capacity
183
203
if (*new_packet == NULL){
184
204
perror("realloc");
223
void debuggnutls(int level, const char* string){
243
void debuggnutls(__attribute__((unused)) int level,
224
245
fprintf(stderr, "%s", string);
227
248
int initgnutls(encrypted_session *es){
232
fprintf(stderr, "Initializing gnutls\n");
253
fprintf(stderr, "Initializing GnuTLS\n");
236
256
if ((ret = gnutls_global_init ())
237
257
!= GNUTLS_E_SUCCESS) {
244
264
gnutls_global_set_log_function(debuggnutls);
248
267
/* openpgp credentials */
249
268
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
250
269
!= GNUTLS_E_SUCCESS) {
251
fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
270
fprintf (stderr, "memory error: %s\n",
271
safer_gnutls_strerror(ret));
256
fprintf(stderr, "Attempting to use openpgp certificate %s"
257
" and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
276
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
277
" and keyfile %s as GnuTLS credentials\n", CERTFILE,
260
281
ret = gnutls_certificate_set_openpgp_key_file
261
282
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
262
283
if (ret != GNUTLS_E_SUCCESS) {
264
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
285
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
265
287
ret, CERTFILE, KEYFILE);
266
288
fprintf(stdout, "The Error is: %s\n",
267
289
safer_gnutls_strerror(ret));
271
//Gnutls server initialization
293
//GnuTLS server initialization
272
294
if ((ret = gnutls_dh_params_init (&es->dh_params))
273
295
!= GNUTLS_E_SUCCESS) {
274
296
fprintf (stderr, "Error in dh parameter initialization: %s\n",
275
297
safer_gnutls_strerror(ret));
279
301
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
280
302
!= GNUTLS_E_SUCCESS) {
281
303
fprintf (stderr, "Error in prime generation: %s\n",
282
304
safer_gnutls_strerror(ret));
286
308
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
288
// Gnutls session creation
310
// GnuTLS session creation
289
311
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
290
312
!= GNUTLS_E_SUCCESS){
291
fprintf(stderr, "Error in gnutls session initialization: %s\n",
313
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
292
314
safer_gnutls_strerror(ret));
295
317
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
296
318
!= GNUTLS_E_SUCCESS) {
297
319
fprintf(stderr, "Syntax error at: %s\n", err);
298
fprintf(stderr, "Gnutls error: %s\n",
320
fprintf(stderr, "GnuTLS error: %s\n",
299
321
safer_gnutls_strerror(ret));
303
325
if ((ret = gnutls_credentials_set
304
326
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
305
327
!= GNUTLS_E_SUCCESS) {
307
329
safer_gnutls_strerror(ret));
311
333
/* ignore client certificate if any. */
312
gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
334
gnutls_certificate_server_set_request (es->session,
314
337
gnutls_dh_set_prime_bits (es->session, DH_BITS);
319
void empty_log(AvahiLogLevel level, const char *txt){}
342
void empty_log(__attribute__((unused)) AvahiLogLevel level,
343
__attribute__((unused)) const char *txt){}
321
int start_mandos_communication(char *ip, uint16_t port){
345
int start_mandos_communication(const char *ip, uint16_t port,
346
AvahiIfIndex if_index){
323
348
struct sockaddr_in6 to;
324
349
encrypted_session es;
327
352
size_t buffer_length = 0;
328
353
size_t buffer_capacity = 0;
329
354
ssize_t decrypted_buffer_size;
357
char interface[IF_NAMESIZE];
333
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
360
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
336
364
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
338
366
perror("socket");
370
if(if_indextoname((unsigned int)if_index, interface) == NULL){
372
perror("if_indextoname");
343
378
fprintf(stderr, "Binding to interface %s\n", interface);
346
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
348
perror("setsockopt bindtodevice");
352
memset(&to,0,sizeof(to));
381
memset(&to,0,sizeof(to)); /* Spurious warning */
353
382
to.sin6_family = AF_INET6;
354
383
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
360
389
fprintf(stderr, "Bad address: %s\n", ip);
363
to.sin6_port = htons(port);
364
to.sin6_scope_id = if_nametoindex(interface);
392
to.sin6_port = htons(port); /* Spurious warning */
394
to.sin6_scope_id = (uint32_t)if_index;
367
fprintf(stderr, "Connection to: %s\n", ip);
397
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
398
/* char addrstr[INET6_ADDRSTRLEN]; */
399
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
400
/* sizeof(addrstr)) == NULL){ */
401
/* perror("inet_ntop"); */
403
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
404
/* addrstr, ntohs(to.sin6_port)); */
370
408
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
383
gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
420
gnutls_transport_set_ptr (es.session,
421
(gnutls_transport_ptr_t) tcp_sd);
386
fprintf(stderr, "Establishing tls session with %s\n", ip);
424
fprintf(stderr, "Establishing TLS session with %s\n", ip);
390
427
ret = gnutls_handshake (es.session);
392
429
if (ret != GNUTLS_E_SUCCESS){
393
fprintf(stderr, "\n*** Handshake failed ***\n");
431
fprintf(stderr, "\n*** Handshake failed ***\n");
399
//Retrieve gpg packet that contains the wanted password
438
//Retrieve OpenPGP packet that contains the wanted password
402
fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
441
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
435
fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
475
fprintf(stderr, "Unknown error while reading data from"
476
" encrypted session with mandos server\n");
437
478
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
441
buffer_length += ret;
482
buffer_length += (size_t) ret;
445
486
if (buffer_length > 0){
446
if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) >= 0){
447
fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
487
decrypted_buffer_size = pgp_packet_decrypt(buffer,
491
if (decrypted_buffer_size >= 0){
492
while(written < (size_t) decrypted_buffer_size){
493
ret = (int)fwrite (decrypted_buffer + written, 1,
494
(size_t)decrypted_buffer_size - written,
496
if(ret == 0 and ferror(stdout)){
498
fprintf(stderr, "Error writing encrypted data: %s\n",
504
written += (size_t)ret;
448
506
free(decrypted_buffer);
481
539
const char *host_name,
482
540
const AvahiAddress *address,
484
AvahiStringList *txt,
485
AvahiLookupResultFlags flags,
542
AVAHI_GCC_UNUSED AvahiStringList *txt,
543
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
486
544
AVAHI_GCC_UNUSED void* userdata) {
490
/* Called whenever a service has been resolved successfully or timed out */
493
case AVAHI_RESOLVER_FAILURE:
494
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)));
497
case AVAHI_RESOLVER_FOUND: {
498
char ip[AVAHI_ADDRESS_STR_MAX];
499
avahi_address_snprint(ip, sizeof(ip), address);
501
fprintf(stderr, "Mandos server found at %s on port %d\n", ip, port);
503
int ret = start_mandos_communication(ip, port);
546
assert(r); /* Spurious warning */
548
/* Called whenever a service has been resolved successfully or
553
case AVAHI_RESOLVER_FAILURE:
554
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
555
" type '%s' in domain '%s': %s\n", name, type, domain,
556
avahi_strerror(avahi_server_errno(server)));
559
case AVAHI_RESOLVER_FOUND:
561
char ip[AVAHI_ADDRESS_STR_MAX];
562
avahi_address_snprint(ip, sizeof(ip), address);
564
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
565
" port %d\n", name, host_name, ip, port);
567
int ret = start_mandos_communication(ip, port, interface);
511
avahi_s_service_resolver_free(r);
573
avahi_s_service_resolver_free(r);
514
576
static void browse_callback(
523
585
void* userdata) {
525
587
AvahiServer *s = userdata;
528
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
588
assert(b); /* Spurious warning */
590
/* Called whenever a new services becomes available on the LAN or
591
is removed from the LAN */
532
case AVAHI_BROWSER_FAILURE:
534
fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
535
avahi_simple_poll_quit(simple_poll);
538
case AVAHI_BROWSER_NEW:
539
/* We ignore the returned resolver object. In the callback
540
function we free it. If the server is terminated before
541
the callback function is called the server will free
542
the resolver for us. */
544
if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
545
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
549
case AVAHI_BROWSER_REMOVE:
552
case AVAHI_BROWSER_ALL_FOR_NOW:
553
case AVAHI_BROWSER_CACHE_EXHAUSTED:
595
case AVAHI_BROWSER_FAILURE:
597
fprintf(stderr, "(Browser) %s\n",
598
avahi_strerror(avahi_server_errno(server)));
599
avahi_simple_poll_quit(simple_poll);
602
case AVAHI_BROWSER_NEW:
603
/* We ignore the returned resolver object. In the callback
604
function we free it. If the server is terminated before
605
the callback function is called the server will free
606
the resolver for us. */
608
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
610
AVAHI_PROTO_INET6, 0,
611
resolve_callback, s)))
612
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
613
avahi_strerror(avahi_server_errno(s)));
616
case AVAHI_BROWSER_REMOVE:
619
case AVAHI_BROWSER_ALL_FOR_NOW:
620
case AVAHI_BROWSER_CACHE_EXHAUSTED:
563
630
int returncode = EXIT_SUCCESS;
631
const char *interface = NULL;
632
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
633
char *connect_to = NULL;
566
636
static struct option long_options[] = {
567
637
{"debug", no_argument, (int *)&debug, 1},
638
{"connect", required_argument, 0, 'c'},
568
639
{"interface", required_argument, 0, 'i'},
571
642
int option_index = 0;
572
ret = getopt_long (argc, argv, "i:", long_options, &option_index);
643
ret = getopt_long (argc, argv, "i:", long_options,
582
654
interface = optarg;
585
660
exit(EXIT_FAILURE);
664
if(interface != NULL){
665
if_index = (AvahiIfIndex) if_nametoindex(interface);
667
fprintf(stderr, "No such interface: \"%s\"\n", interface);
672
if(connect_to != NULL){
673
/* Connect directly, do not use Zeroconf */
674
/* (Mainly meant for debugging) */
675
char *address = strrchr(connect_to, ':');
677
fprintf(stderr, "No colon in address\n");
681
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
683
perror("Bad port number");
687
address = connect_to;
688
ret = start_mandos_communication(address, port, if_index);
590
697
avahi_set_log_function(empty_log);
593
700
/* Initialize the psuedo-RNG */
701
srand((unsigned int) time(NULL));
596
703
/* Allocate main loop object */
597
704
if (!(simple_poll = avahi_simple_poll_new())) {
608
715
config.publish_domain = 0;
610
717
/* Allocate a new server */
611
server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
718
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
719
&config, NULL, NULL, &error);
613
721
/* Free the configuration data */
614
722
avahi_server_config_free(&config);
616
724
/* Check if creating the server object succeeded */
618
fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
726
fprintf(stderr, "Failed to create server: %s\n",
727
avahi_strerror(error));
619
728
returncode = EXIT_FAILURE;
623
732
/* Create the service browser */
624
if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
625
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
733
sb = avahi_s_service_browser_new(server, if_index,
735
"_mandos._tcp", NULL, 0,
736
browse_callback, server);
738
fprintf(stderr, "Failed to create service browser: %s\n",
739
avahi_strerror(avahi_server_errno(server)));
626
740
returncode = EXIT_FAILURE;