1
/* -*- coding: utf-8 -*- */
3
* Mandos client - get and decrypt data from a Mandos server
4
* This file demonstrates how to use Avahi's core API, this is
5
* the embeddable mDNS stack for embedded applications.
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".
11
* Everything else is Copyright © 2007-2008 Teddy Hogeborn and Björn
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/>.
7
* End user applications should *not* use this API and should use
8
* the D-Bus or C APIs, please see
9
* client-browse-services.c and glib-integration.c
11
* I repeat, you probably do *not* want to use this example.
32
#define _FORTIFY_SOURCE 2
15
This file is part of avahi.
17
avahi is free software; you can redistribute it and/or modify it
18
under the terms of the GNU Lesser General Public License as
19
published by the Free Software Foundation; either version 2.1 of the
20
License, or (at your option) any later version.
22
avahi is distributed in the hope that it will be useful, but WITHOUT
23
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
25
Public License for more details.
27
You should have received a copy of the GNU Lesser General Public
28
License along with avahi; if not, write to the Free Software
29
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
34
33
#define _LARGEFILE_SOURCE
35
34
#define _FILE_OFFSET_BITS 64
48
47
#include <avahi-common/error.h>
50
49
//mandos client part
51
#include <sys/types.h> /* socket(), setsockopt(),
53
#include <sys/socket.h> /* socket(), setsockopt(),
55
struct in6_addr, inet_pton() */
56
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
57
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
50
#include <sys/types.h> /* socket(), setsockopt(), inet_pton() */
51
#include <sys/socket.h> /* socket(), setsockopt(), struct sockaddr_in6, struct in6_addr, inet_pton() */
52
#include <gnutls/gnutls.h> /* ALL GNUTLS STUFF */
53
#include <gnutls/openpgp.h> /* gnutls with openpgp stuff */
59
55
#include <unistd.h> /* close() */
60
56
#include <netinet/in.h>
87
79
} encrypted_session;
90
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
91
char **new_packet, const char *homedir){
82
ssize_t gpg_packet_decrypt (char *packet, size_t packet_size, char **new_packet, char *homedir){
92
83
gpgme_data_t dh_crypto, dh_plain;
96
ssize_t new_packet_capacity = 0;
97
ssize_t new_packet_length = 0;
87
size_t new_packet_capacity = 0;
88
size_t new_packet_length = 0;
98
89
gpgme_engine_info_t engine_info;
101
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
105
92
gpgme_check_version(NULL);
106
93
gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
152
/* Decrypt data from the FILE pointer to the plaintext data
139
/* Decrypt data from the FILE pointer to the plaintext data buffer */
154
140
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
155
141
if (rc != GPG_ERR_NO_ERROR){
156
142
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
157
143
gpgme_strsource(rc), gpgme_strerror(rc));
162
fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
166
gpgme_decrypt_result_t result;
167
result = gpgme_op_decrypt_result(ctx);
169
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
171
fprintf(stderr, "Unsupported algorithm: %s\n",
172
result->unsupported_algorithm);
173
fprintf(stderr, "Wrong key usage: %d\n",
174
result->wrong_key_usage);
175
if(result->file_name != NULL){
176
fprintf(stderr, "File name: %s\n", result->file_name);
178
gpgme_recipient_t recipient;
179
recipient = result->recipients;
181
while(recipient != NULL){
182
fprintf(stderr, "Public key algorithm: %s\n",
183
gpgme_pubkey_algo_name(recipient->pubkey_algo));
184
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
185
fprintf(stderr, "Secret key available: %s\n",
186
recipient->status == GPG_ERR_NO_SECKEY
188
recipient = recipient->next;
147
/* gpgme_decrypt_result_t result; */
148
/* result = gpgme_op_decrypt_result(ctx); */
149
/* fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm); */
150
/* fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage); */
151
/* if(result->file_name != NULL){ */
152
/* fprintf(stderr, "File name: %s\n", result->file_name); */
154
/* gpgme_recipient_t recipient; */
155
/* recipient = result->recipients; */
157
/* while(recipient != NULL){ */
158
/* fprintf(stderr, "Public key algorithm: %s\n", */
159
/* gpgme_pubkey_algo_name(recipient->pubkey_algo)); */
160
/* fprintf(stderr, "Key ID: %s\n", recipient->keyid); */
161
/* fprintf(stderr, "Secret key available: %s\n", */
162
/* recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes"); */
163
/* recipient = recipient->next; */
194
167
/* Delete the GPGME FILE pointer cryptotext data buffer */
195
168
gpgme_data_release(dh_crypto);
223
194
new_packet_length += ret;
226
/* FIXME: check characters before printing to screen so to not print
227
terminal control characters */
229
/* fprintf(stderr, "decrypted password is: "); */
230
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
231
/* fprintf(stderr, "\n"); */
234
/* Delete the GPGME plaintext data buffer */
197
/* Delete the GPGME plaintext data buffer */
235
198
gpgme_data_release(dh_plain);
236
199
return new_packet_length;
256
fprintf(stderr, "Initializing GnuTLS\n");
259
217
if ((ret = gnutls_global_init ())
260
218
!= GNUTLS_E_SUCCESS) {
261
219
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
266
gnutls_global_set_log_level(11);
267
gnutls_global_set_log_function(debuggnutls);
223
/* Uncomment to enable full debuggin on the gnutls library */
224
/* gnutls_global_set_log_level(11); */
225
/* gnutls_global_set_log_function(debuggnutls); */
270
228
/* openpgp credentials */
271
229
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
272
230
!= GNUTLS_E_SUCCESS) {
273
fprintf (stderr, "memory error: %s\n",
274
safer_gnutls_strerror(ret));
231
fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
279
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
280
" and keyfile %s as GnuTLS credentials\n", CERTFILE,
284
235
ret = gnutls_certificate_set_openpgp_key_file
285
236
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
286
237
if (ret != GNUTLS_E_SUCCESS) {
288
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
239
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
290
240
ret, CERTFILE, KEYFILE);
291
241
fprintf(stdout, "The Error is: %s\n",
292
242
safer_gnutls_strerror(ret));
296
//GnuTLS server initialization
246
//Gnutls server initialization
297
247
if ((ret = gnutls_dh_params_init (&es->dh_params))
298
248
!= GNUTLS_E_SUCCESS) {
299
249
fprintf (stderr, "Error in dh parameter initialization: %s\n",
300
250
safer_gnutls_strerror(ret));
304
254
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
305
255
!= GNUTLS_E_SUCCESS) {
306
256
fprintf (stderr, "Error in prime generation: %s\n",
307
257
safer_gnutls_strerror(ret));
311
261
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
313
// GnuTLS session creation
263
// Gnutls session creation
314
264
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
315
265
!= GNUTLS_E_SUCCESS){
316
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
266
fprintf(stderr, "Error in gnutls session initialization: %s\n",
317
267
safer_gnutls_strerror(ret));
320
270
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
321
271
!= GNUTLS_E_SUCCESS) {
322
272
fprintf(stderr, "Syntax error at: %s\n", err);
323
fprintf(stderr, "GnuTLS error: %s\n",
273
fprintf(stderr, "Gnutls error: %s\n",
324
274
safer_gnutls_strerror(ret));
328
278
if ((ret = gnutls_credentials_set
329
279
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
330
280
!= GNUTLS_E_SUCCESS) {
332
282
safer_gnutls_strerror(ret));
336
286
/* ignore client certificate if any. */
337
gnutls_certificate_server_set_request (es->session,
287
gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
340
289
gnutls_dh_set_prime_bits (es->session, DH_BITS);
345
void empty_log(__attribute__((unused)) AvahiLogLevel level,
346
__attribute__((unused)) const char *txt){}
294
void empty_log(AvahiLogLevel level, const char *txt){}
348
int start_mandos_communication(char *ip, uint16_t port,
349
unsigned int if_index){
296
int start_mandos_communcation(char *ip, uint16_t port){
351
298
struct sockaddr_in6 to;
299
struct in6_addr ip_addr;
352
300
encrypted_session es;
353
301
char *buffer = NULL;
354
302
char *decrypted_buffer;
371
if(if_indextoname(if_index, interface) == NULL){
373
perror("if_indextoname");
379
fprintf(stderr, "Binding to interface %s\n", interface);
382
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
315
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
384
317
perror("setsockopt bindtodevice");
388
321
memset(&to,0,sizeof(to));
389
322
to.sin6_family = AF_INET6;
390
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
323
ret = inet_pton(AF_INET6, ip, &ip_addr);
392
325
perror("inet_pton");
396
329
fprintf(stderr, "Bad address: %s\n", ip);
399
/* Spurious warnings for the next line, see for instance
400
<http://bugs.debian.org/488884> */
401
332
to.sin6_port = htons(port);
403
to.sin6_scope_id = (uint32_t)if_index;
406
fprintf(stderr, "Connection to: %s\n", ip);
333
to.sin6_scope_id = if_nametoindex("eth0");
409
335
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
474
fprintf(stderr, "Unknown error while reading data from"
475
" encrypted session with mandos server\n");
390
fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
477
392
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
481
buffer_length += (size_t) ret;
396
buffer_length += ret;
485
400
if (buffer_length > 0){
486
decrypted_buffer_size = pgp_packet_decrypt(buffer,
490
if (decrypted_buffer_size >= 0){
491
while(decrypted_buffer_size > 0){
492
ret = fwrite (decrypted_buffer, 1, (size_t)decrypted_buffer_size,
494
if(ret == 0 and ferror(stdout)){
496
fprintf(stderr, "Error writing encrypted data: %s\n",
502
decrypted_buffer += ret;
503
decrypted_buffer_size -= ret;
401
if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) == 0){
404
fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
505
405
free(decrypted_buffer);
511
411
//shutdown procedure
514
fprintf(stderr, "Closing TLS session\n");
518
412
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
538
432
const char *host_name,
539
433
const AvahiAddress *address,
541
AVAHI_GCC_UNUSED AvahiStringList *txt,
542
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
435
AvahiStringList *txt,
436
AvahiLookupResultFlags flags,
543
437
AVAHI_GCC_UNUSED void* userdata) {
547
/* Called whenever a service has been resolved successfully or
552
case AVAHI_RESOLVER_FAILURE:
553
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
554
" type '%s' in domain '%s': %s\n", name, type, domain,
555
avahi_strerror(avahi_server_errno(server)));
558
case AVAHI_RESOLVER_FOUND:
560
char ip[AVAHI_ADDRESS_STR_MAX];
561
avahi_address_snprint(ip, sizeof(ip), address);
563
fprintf(stderr, "Mandos server found on %s (%s) on port %d\n",
564
host_name, ip, port);
566
int ret = start_mandos_communication(ip, port,
441
/* Called whenever a service has been resolved successfully or timed out */
444
case AVAHI_RESOLVER_FAILURE:
445
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)));
448
case AVAHI_RESOLVER_FOUND: {
449
char ip[AVAHI_ADDRESS_STR_MAX];
450
avahi_address_snprint(ip, sizeof(ip), address);
451
int ret = start_mandos_communcation(ip, port);
576
avahi_s_service_resolver_free(r);
459
avahi_s_service_resolver_free(r);
579
462
static void browse_callback(
590
473
AvahiServer *s = userdata;
593
/* Called whenever a new services becomes available on the LAN or
594
is removed from the LAN */
476
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
598
case AVAHI_BROWSER_FAILURE:
600
fprintf(stderr, "(Browser) %s\n",
601
avahi_strerror(avahi_server_errno(server)));
602
avahi_simple_poll_quit(simple_poll);
605
case AVAHI_BROWSER_NEW:
606
/* We ignore the returned resolver object. In the callback
607
function we free it. If the server is terminated before
608
the callback function is called the server will free
609
the resolver for us. */
611
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
613
AVAHI_PROTO_INET6, 0,
614
resolve_callback, s)))
615
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
616
avahi_strerror(avahi_server_errno(s)));
619
case AVAHI_BROWSER_REMOVE:
622
case AVAHI_BROWSER_ALL_FOR_NOW:
623
case AVAHI_BROWSER_CACHE_EXHAUSTED:
480
case AVAHI_BROWSER_FAILURE:
482
fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
483
avahi_simple_poll_quit(simple_poll);
486
case AVAHI_BROWSER_NEW:
487
/* We ignore the returned resolver object. In the callback
488
function we free it. If the server is terminated before
489
the callback function is called the server will free
490
the resolver for us. */
492
if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
493
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
497
case AVAHI_BROWSER_REMOVE:
500
case AVAHI_BROWSER_ALL_FOR_NOW:
501
case AVAHI_BROWSER_CACHE_EXHAUSTED:
629
507
AvahiServerConfig config;
630
508
AvahiSServiceBrowser *sb = NULL;
633
int returncode = EXIT_SUCCESS;
634
const char *interface = "eth0";
637
static struct option long_options[] = {
638
{"debug", no_argument, (int *)&debug, 1},
639
{"interface", required_argument, 0, 'i'},
642
int option_index = 0;
643
ret = getopt_long (argc, argv, "i:", long_options,
662
avahi_set_log_function(empty_log);
512
avahi_set_log_function(empty_log);
665
514
/* Initialize the psuedo-RNG */
666
srand((unsigned int) time(NULL));
668
517
/* Allocate main loop object */
669
518
if (!(simple_poll = avahi_simple_poll_new())) {
670
519
fprintf(stderr, "Failed to create simple poll object.\n");
675
523
/* Do not publish any local records */
679
527
config.publish_workstation = 0;
680
528
config.publish_domain = 0;
530
/* /\* Set a unicast DNS server for wide area DNS-SD *\/ */
531
/* avahi_address_parse("193.11.177.11", AVAHI_PROTO_UNSPEC, &config.wide_area_servers[0]); */
532
/* config.n_wide_area_servers = 1; */
533
/* config.enable_wide_area = 1; */
682
535
/* Allocate a new server */
683
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
684
&config, NULL, NULL, &error);
536
server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
686
538
/* Free the configuration data */
687
539
avahi_server_config_free(&config);
689
/* Check if creating the server object succeeded */
541
/* Check wether creating the server object succeeded */
691
fprintf(stderr, "Failed to create server: %s\n",
692
avahi_strerror(error));
693
returncode = EXIT_FAILURE;
543
fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
697
547
/* Create the service browser */
698
sb = avahi_s_service_browser_new(server,
700
if_nametoindex(interface),
702
"_mandos._tcp", NULL, 0,
703
browse_callback, server);
705
fprintf(stderr, "Failed to create service browser: %s\n",
706
avahi_strerror(avahi_server_errno(server)));
707
returncode = EXIT_FAILURE;
548
if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
549
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
711
553
/* Run the main loop */
714
fprintf(stderr, "Starting avahi loop search\n");
717
554
avahi_simple_poll_loop(simple_poll);
722
fprintf(stderr, "%s exiting\n", argv[0]);
725
560
/* Cleanup things */