123
274
/* Create new empty GPGME data buffer for the plaintext */
124
275
rc = gpgme_data_new(&dh_plain);
125
if (rc != GPG_ERR_NO_ERROR){
276
if(rc != GPG_ERR_NO_ERROR){
126
277
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
127
278
gpgme_strsource(rc), gpgme_strerror(rc));
131
/* Create new GPGME "context" */
132
rc = gpgme_new(&ctx);
133
if (rc != GPG_ERR_NO_ERROR){
134
fprintf(stderr, "bad gpgme_new: %s: %s\n",
135
gpgme_strsource(rc), gpgme_strerror(rc));
139
/* Decrypt data from the FILE pointer to the plaintext data buffer */
140
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
141
if (rc != GPG_ERR_NO_ERROR){
279
gpgme_data_release(dh_crypto);
283
/* Decrypt data from the cryptotext data buffer to the plaintext
285
rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
286
if(rc != GPG_ERR_NO_ERROR){
142
287
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
143
288
gpgme_strsource(rc), gpgme_strerror(rc));
289
plaintext_length = -1;
291
gpgme_decrypt_result_t result;
292
result = gpgme_op_decrypt_result(mc.ctx);
294
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
296
fprintf(stderr, "Unsupported algorithm: %s\n",
297
result->unsupported_algorithm);
298
fprintf(stderr, "Wrong key usage: %u\n",
299
result->wrong_key_usage);
300
if(result->file_name != NULL){
301
fprintf(stderr, "File name: %s\n", result->file_name);
303
gpgme_recipient_t recipient;
304
recipient = result->recipients;
306
while(recipient != NULL){
307
fprintf(stderr, "Public key algorithm: %s\n",
308
gpgme_pubkey_algo_name(recipient->pubkey_algo));
309
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
310
fprintf(stderr, "Secret key available: %s\n",
311
recipient->status == GPG_ERR_NO_SECKEY
313
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; */
167
/* Delete the GPGME FILE pointer cryptotext data buffer */
168
gpgme_data_release(dh_crypto);
322
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
170
325
/* Seek back to the beginning of the GPGME plaintext data buffer */
171
gpgme_data_seek(dh_plain, 0, SEEK_SET);
326
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
327
perror("gpgme_data_seek");
328
plaintext_length = -1;
175
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
176
*new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
177
if (*new_packet == NULL){
181
new_packet_capacity += BUFFER_SIZE;
334
plaintext_capacity = incbuffer(plaintext,
335
(size_t)plaintext_length,
337
if(plaintext_capacity == 0){
339
plaintext_length = -1;
184
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
343
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
185
345
/* Print the data, if any */
187
/* If password is empty, then a incorrect error will be printed */
191
351
perror("gpgme_data_read");
194
new_packet_length += ret;
197
/* Delete the GPGME plaintext data buffer */
352
plaintext_length = -1;
355
plaintext_length += ret;
359
fprintf(stderr, "Decrypted password is: ");
360
for(ssize_t i = 0; i < plaintext_length; i++){
361
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
363
fprintf(stderr, "\n");
368
/* Delete the GPGME cryptotext data buffer */
369
gpgme_data_release(dh_crypto);
371
/* Delete the GPGME plaintext data buffer */
198
372
gpgme_data_release(dh_plain);
199
return new_packet_length;
373
return plaintext_length;
202
static const char * safer_gnutls_strerror (int value) {
203
const char *ret = gnutls_strerror (value);
376
static const char * safer_gnutls_strerror(int value){
377
const char *ret = gnutls_strerror(value); /* Spurious warning from
378
-Wunreachable-code */
205
380
ret = "(unknown)";
209
void debuggnutls(int level, const char* string){
210
fprintf(stderr, "%s", string);
384
/* GnuTLS log function callback */
385
static void debuggnutls(__attribute__((unused)) int level,
387
fprintf(stderr, "GnuTLS: %s", string);
213
int initgnutls(encrypted_session *es){
390
static int init_gnutls_global(const char *pubkeyfilename,
391
const char *seckeyfilename){
217
if ((ret = gnutls_global_init ())
218
!= GNUTLS_E_SUCCESS) {
219
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
223
/* Uncomment to enable full debuggin on the gnutls library */
224
/* gnutls_global_set_log_level(11); */
225
/* gnutls_global_set_log_function(debuggnutls); */
228
/* openpgp credentials */
229
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
230
!= GNUTLS_E_SUCCESS) {
231
fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
395
fprintf(stderr, "Initializing GnuTLS\n");
398
ret = gnutls_global_init();
399
if(ret != GNUTLS_E_SUCCESS){
400
fprintf(stderr, "GnuTLS global_init: %s\n",
401
safer_gnutls_strerror(ret));
406
/* "Use a log level over 10 to enable all debugging options."
409
gnutls_global_set_log_level(11);
410
gnutls_global_set_log_function(debuggnutls);
413
/* OpenPGP credentials */
414
gnutls_certificate_allocate_credentials(&mc.cred);
415
if(ret != GNUTLS_E_SUCCESS){
416
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
420
safer_gnutls_strerror(ret));
421
gnutls_global_deinit();
426
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
427
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
235
431
ret = gnutls_certificate_set_openpgp_key_file
236
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
237
if (ret != GNUTLS_E_SUCCESS) {
239
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
240
ret, CERTFILE, KEYFILE);
241
fprintf(stdout, "The Error is: %s\n",
242
safer_gnutls_strerror(ret));
246
//Gnutls server initialization
247
if ((ret = gnutls_dh_params_init (&es->dh_params))
248
!= GNUTLS_E_SUCCESS) {
249
fprintf (stderr, "Error in dh parameter initialization: %s\n",
250
safer_gnutls_strerror(ret));
254
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
255
!= GNUTLS_E_SUCCESS) {
256
fprintf (stderr, "Error in prime generation: %s\n",
257
safer_gnutls_strerror(ret));
261
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
263
// Gnutls session creation
264
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
265
!= GNUTLS_E_SUCCESS){
266
fprintf(stderr, "Error in gnutls session initialization: %s\n",
267
safer_gnutls_strerror(ret));
270
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
271
!= GNUTLS_E_SUCCESS) {
272
fprintf(stderr, "Syntax error at: %s\n", err);
273
fprintf(stderr, "Gnutls error: %s\n",
274
safer_gnutls_strerror(ret));
278
if ((ret = gnutls_credentials_set
279
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
280
!= GNUTLS_E_SUCCESS) {
281
fprintf(stderr, "Error setting a credentials set: %s\n",
282
safer_gnutls_strerror(ret));
432
(mc.cred, pubkeyfilename, seckeyfilename,
433
GNUTLS_OPENPGP_FMT_BASE64);
434
if(ret != GNUTLS_E_SUCCESS){
436
"Error[%d] while reading the OpenPGP key pair ('%s',"
437
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
438
fprintf(stderr, "The GnuTLS error is: %s\n",
439
safer_gnutls_strerror(ret));
443
/* GnuTLS server initialization */
444
ret = gnutls_dh_params_init(&mc.dh_params);
445
if(ret != GNUTLS_E_SUCCESS){
446
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
447
" %s\n", safer_gnutls_strerror(ret));
450
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
451
if(ret != GNUTLS_E_SUCCESS){
452
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
453
safer_gnutls_strerror(ret));
457
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
463
gnutls_certificate_free_credentials(mc.cred);
464
gnutls_global_deinit();
465
gnutls_dh_params_deinit(mc.dh_params);
469
static int init_gnutls_session(gnutls_session_t *session){
471
/* GnuTLS session creation */
472
ret = gnutls_init(session, GNUTLS_SERVER);
473
if(ret != GNUTLS_E_SUCCESS){
474
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
475
safer_gnutls_strerror(ret));
480
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
481
if(ret != GNUTLS_E_SUCCESS){
482
fprintf(stderr, "Syntax error at: %s\n", err);
483
fprintf(stderr, "GnuTLS error: %s\n",
484
safer_gnutls_strerror(ret));
485
gnutls_deinit(*session);
490
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
492
if(ret != GNUTLS_E_SUCCESS){
493
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
494
safer_gnutls_strerror(ret));
495
gnutls_deinit(*session);
286
499
/* ignore client certificate if any. */
287
gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
500
gnutls_certificate_server_set_request(*session,
289
gnutls_dh_set_prime_bits (es->session, DH_BITS);
503
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
294
void empty_log(AvahiLogLevel level, const char *txt){}
508
/* Avahi log function callback */
509
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
510
__attribute__((unused)) const char *txt){}
296
int start_mandos_communcation(char *ip, uint16_t port){
512
/* Called when a Mandos server is found */
513
static int start_mandos_communication(const char *ip, uint16_t port,
514
AvahiIfIndex if_index,
298
struct sockaddr_in6 to;
299
struct in6_addr ip_addr;
300
encrypted_session es;
519
struct sockaddr_in in;
520
struct sockaddr_in6 in6;
301
522
char *buffer = NULL;
302
523
char *decrypted_buffer;
303
524
size_t buffer_length = 0;
304
525
size_t buffer_capacity = 0;
305
526
ssize_t decrypted_buffer_size;
309
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
529
gnutls_session_t session;
530
int pf; /* Protocol family */
540
fprintf(stderr, "Bad address family: %d\n", af);
544
ret = init_gnutls_session(&session);
550
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
554
tcp_sd = socket(pf, SOCK_STREAM, 0);
311
556
perror("socket");
315
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
317
perror("setsockopt bindtodevice");
560
memset(&to, 0, sizeof(to));
562
to.in6.sin6_family = (uint16_t)af;
563
ret = inet_pton(af, ip, &to.in6.sin6_addr);
565
to.in.sin_family = (sa_family_t)af;
566
ret = inet_pton(af, ip, &to.in.sin_addr);
321
memset(&to,0,sizeof(to));
322
to.sin6_family = AF_INET6;
323
ret = inet_pton(AF_INET6, ip, &ip_addr);
325
569
perror("inet_pton");
329
573
fprintf(stderr, "Bad address: %s\n", ip);
332
to.sin6_port = htons(port);
333
to.sin6_scope_id = if_nametoindex("eth0");
335
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
577
to.in6.sin6_port = htons(port); /* Spurious warnings from
579
-Wunreachable-code */
581
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
582
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
584
if(if_index == AVAHI_IF_UNSPEC){
585
fprintf(stderr, "An IPv6 link-local address is incomplete"
586
" without a network interface\n");
589
/* Set the network interface number as scope */
590
to.in6.sin6_scope_id = (uint32_t)if_index;
593
to.in.sin_port = htons(port); /* Spurious warnings from
595
-Wunreachable-code */
599
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
600
char interface[IF_NAMESIZE];
601
if(if_indextoname((unsigned int)if_index, interface) == NULL){
602
perror("if_indextoname");
604
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
605
ip, interface, port);
608
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
611
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
612
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
615
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
618
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
624
if(strcmp(addrstr, ip) != 0){
625
fprintf(stderr, "Canonical address form: %s\n", addrstr);
631
ret = connect(tcp_sd, &to.in6, sizeof(to));
633
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
337
636
perror("connect");
341
ret = initgnutls (&es);
348
gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
350
ret = gnutls_handshake (es.session);
352
if (ret != GNUTLS_E_SUCCESS){
353
fprintf(stderr, "\n*** Handshake failed ***\n");
640
const char *out = mandos_protocol_version;
361
if (buffer_length + BUFFER_SIZE > buffer_capacity){
362
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
643
size_t out_size = strlen(out);
644
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
645
out_size - written));
651
written += (size_t)ret;
652
if(written < out_size){
655
if(out == mandos_protocol_version){
367
buffer_capacity += BUFFER_SIZE;
665
fprintf(stderr, "Establishing TLS session with %s\n", ip);
668
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
671
ret = gnutls_handshake(session);
672
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
674
if(ret != GNUTLS_E_SUCCESS){
676
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
683
/* Read OpenPGP packet that contains the wanted password */
686
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
691
buffer_capacity = incbuffer(&buffer, buffer_length,
693
if(buffer_capacity == 0){
370
ret = gnutls_record_recv
371
(es.session, buffer+buffer_length, BUFFER_SIZE);
699
sret = gnutls_record_recv(session, buffer+buffer_length,
377
706
case GNUTLS_E_INTERRUPTED:
378
707
case GNUTLS_E_AGAIN:
380
709
case GNUTLS_E_REHANDSHAKE:
381
ret = gnutls_handshake (es.session);
383
fprintf(stderr, "\n*** Handshake failed ***\n");
711
ret = gnutls_handshake(session);
712
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
714
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
390
fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
721
fprintf(stderr, "Unknown error while reading data from"
722
" encrypted session with Mandos server\n");
392
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
724
gnutls_bye(session, GNUTLS_SHUT_RDWR);
396
buffer_length += ret;
728
buffer_length += (size_t) sret;
400
if (buffer_length > 0){
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);
733
fprintf(stderr, "Closing TLS session\n");
736
gnutls_bye(session, GNUTLS_SHUT_RDWR);
738
if(buffer_length > 0){
739
decrypted_buffer_size = pgp_packet_decrypt(buffer,
742
if(decrypted_buffer_size >= 0){
744
while(written < (size_t) decrypted_buffer_size){
745
ret = (int)fwrite(decrypted_buffer + written, 1,
746
(size_t)decrypted_buffer_size - written,
748
if(ret == 0 and ferror(stdout)){
750
fprintf(stderr, "Error writing encrypted data: %s\n",
756
written += (size_t)ret;
405
758
free(decrypted_buffer);
766
/* Shutdown procedure */
412
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
415
gnutls_deinit (es.session);
416
gnutls_certificate_free_credentials (es.cred);
417
gnutls_global_deinit ();
770
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
774
gnutls_deinit(session);
421
static AvahiSimplePoll *simple_poll = NULL;
422
static AvahiServer *server = NULL;
424
static void resolve_callback(
425
AvahiSServiceResolver *r,
426
AVAHI_GCC_UNUSED AvahiIfIndex interface,
427
AVAHI_GCC_UNUSED AvahiProtocol protocol,
428
AvahiResolverEvent event,
432
const char *host_name,
433
const AvahiAddress *address,
435
AvahiStringList *txt,
436
AvahiLookupResultFlags flags,
437
AVAHI_GCC_UNUSED void* userdata) {
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);
459
avahi_s_service_resolver_free(r);
462
static void browse_callback(
463
AvahiSServiceBrowser *b,
464
AvahiIfIndex interface,
465
AvahiProtocol protocol,
466
AvahiBrowserEvent event,
470
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
473
AvahiServer *s = userdata;
476
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
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:
506
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
778
static void resolve_callback(AvahiSServiceResolver *r,
779
AvahiIfIndex interface,
781
AvahiResolverEvent event,
785
const char *host_name,
786
const AvahiAddress *address,
788
AVAHI_GCC_UNUSED AvahiStringList *txt,
789
AVAHI_GCC_UNUSED AvahiLookupResultFlags
791
AVAHI_GCC_UNUSED void* userdata){
794
/* Called whenever a service has been resolved successfully or
799
case AVAHI_RESOLVER_FAILURE:
800
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
801
" of type '%s' in domain '%s': %s\n", name, type, domain,
802
avahi_strerror(avahi_server_errno(mc.server)));
805
case AVAHI_RESOLVER_FOUND:
807
char ip[AVAHI_ADDRESS_STR_MAX];
808
avahi_address_snprint(ip, sizeof(ip), address);
810
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
811
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
812
ip, (intmax_t)interface, port);
814
int ret = start_mandos_communication(ip, port, interface,
815
avahi_proto_to_af(proto));
817
avahi_simple_poll_quit(mc.simple_poll);
821
avahi_s_service_resolver_free(r);
824
static void browse_callback(AvahiSServiceBrowser *b,
825
AvahiIfIndex interface,
826
AvahiProtocol protocol,
827
AvahiBrowserEvent event,
831
AVAHI_GCC_UNUSED AvahiLookupResultFlags
833
AVAHI_GCC_UNUSED void* userdata){
836
/* Called whenever a new services becomes available on the LAN or
837
is removed from the LAN */
841
case AVAHI_BROWSER_FAILURE:
843
fprintf(stderr, "(Avahi browser) %s\n",
844
avahi_strerror(avahi_server_errno(mc.server)));
845
avahi_simple_poll_quit(mc.simple_poll);
848
case AVAHI_BROWSER_NEW:
849
/* We ignore the returned Avahi resolver object. In the callback
850
function we free it. If the Avahi server is terminated before
851
the callback function is called the Avahi server will free the
854
if(!(avahi_s_service_resolver_new(mc.server, interface,
855
protocol, name, type, domain,
856
AVAHI_PROTO_INET6, 0,
857
resolve_callback, NULL)))
858
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
859
name, avahi_strerror(avahi_server_errno(mc.server)));
862
case AVAHI_BROWSER_REMOVE:
865
case AVAHI_BROWSER_ALL_FOR_NOW:
866
case AVAHI_BROWSER_CACHE_EXHAUSTED:
868
fprintf(stderr, "No Mandos server found, still searching...\n");
874
static void handle_sigterm(__attribute__((unused)) int sig){
875
int old_errno = errno;
876
avahi_simple_poll_quit(mc.simple_poll);
880
int main(int argc, char *argv[]){
881
AvahiSServiceBrowser *sb = NULL;
886
int exitcode = EXIT_SUCCESS;
887
const char *interface = "eth0";
888
struct ifreq network;
892
char *connect_to = NULL;
893
char tempdir[] = "/tmp/mandosXXXXXX";
894
bool tempdir_created = false;
895
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
896
const char *seckey = PATHDIR "/" SECKEY;
897
const char *pubkey = PATHDIR "/" PUBKEY;
899
/* Initialize Mandos context */
900
mc = (mandos_context){ .simple_poll = NULL, .server = NULL,
901
.dh_bits = 1024, .priority = "SECURE256"
902
":!CTYPE-X.509:+CTYPE-OPENPGP" };
903
bool gnutls_initialized = false;
904
bool gpgme_initialized = false;
907
struct sigaction old_sigterm_action;
908
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
911
struct argp_option options[] = {
912
{ .name = "debug", .key = 128,
913
.doc = "Debug mode", .group = 3 },
914
{ .name = "connect", .key = 'c',
915
.arg = "ADDRESS:PORT",
916
.doc = "Connect directly to a specific Mandos server",
918
{ .name = "interface", .key = 'i',
920
.doc = "Network interface that will be used to search for"
923
{ .name = "seckey", .key = 's',
925
.doc = "OpenPGP secret key file base name",
927
{ .name = "pubkey", .key = 'p',
929
.doc = "OpenPGP public key file base name",
931
{ .name = "dh-bits", .key = 129,
933
.doc = "Bit length of the prime number used in the"
934
" Diffie-Hellman key exchange",
936
{ .name = "priority", .key = 130,
938
.doc = "GnuTLS priority string for the TLS handshake",
940
{ .name = "delay", .key = 131,
942
.doc = "Maximum delay to wait for interface startup",
947
error_t parse_opt(int key, char *arg,
948
struct argp_state *state){
950
case 128: /* --debug */
953
case 'c': /* --connect */
956
case 'i': /* --interface */
959
case 's': /* --seckey */
962
case 'p': /* --pubkey */
965
case 129: /* --dh-bits */
966
ret = sscanf(arg, "%" SCNdMAX "%n", &tmpmax, &numchars);
967
if(ret < 1 or tmpmax != (typeof(mc.dh_bits))tmpmax
968
or arg[numchars] != '\0'){
969
fprintf(stderr, "Bad number of DH bits\n");
972
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
974
case 130: /* --priority */
977
case 131: /* --delay */
978
ret = sscanf(arg, "%lf%n", &delay, &numchars);
979
if(ret < 1 or arg[numchars] != '\0'){
980
fprintf(stderr, "Bad delay\n");
989
return ARGP_ERR_UNKNOWN;
994
struct argp argp = { .options = options, .parser = parse_opt,
996
.doc = "Mandos client -- Get and decrypt"
997
" passwords from a Mandos server" };
998
ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
999
if(ret == ARGP_ERR_UNKNOWN){
1000
fprintf(stderr, "Unknown error while parsing arguments\n");
1001
exitcode = EXIT_FAILURE;
1006
/* If the interface is down, bring it up */
1007
if(interface[0] != '\0'){
1009
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1010
messages to mess up the prompt */
1011
ret = klogctl(8, NULL, 5);
1012
bool restore_loglevel = true;
1014
restore_loglevel = false;
1019
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1022
exitcode = EXIT_FAILURE;
1024
if(restore_loglevel){
1025
ret = klogctl(7, NULL, 0);
1033
strcpy(network.ifr_name, interface);
1034
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1036
perror("ioctl SIOCGIFFLAGS");
1038
if(restore_loglevel){
1039
ret = klogctl(7, NULL, 0);
1045
exitcode = EXIT_FAILURE;
1048
if((network.ifr_flags & IFF_UP) == 0){
1049
network.ifr_flags |= IFF_UP;
1050
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1052
perror("ioctl SIOCSIFFLAGS");
1053
exitcode = EXIT_FAILURE;
1055
if(restore_loglevel){
1056
ret = klogctl(7, NULL, 0);
1065
/* sleep checking until interface is running */
1066
for(int i=0; i < delay * 4; i++){
1067
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1069
perror("ioctl SIOCGIFFLAGS");
1070
} else if(network.ifr_flags & IFF_RUNNING){
1073
struct timespec sleeptime = { .tv_nsec = 250000000 };
1074
ret = nanosleep(&sleeptime, NULL);
1075
if(ret == -1 and errno != EINTR){
1076
perror("nanosleep");
1079
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1084
if(restore_loglevel){
1085
/* Restores kernel loglevel to default */
1086
ret = klogctl(7, NULL, 0);
1108
ret = init_gnutls_global(pubkey, seckey);
1110
fprintf(stderr, "init_gnutls_global failed\n");
1111
exitcode = EXIT_FAILURE;
1114
gnutls_initialized = true;
1117
if(mkdtemp(tempdir) == NULL){
1121
tempdir_created = true;
1123
if(not init_gpgme(pubkey, seckey, tempdir)){
1124
fprintf(stderr, "init_gpgme failed\n");
1125
exitcode = EXIT_FAILURE;
1128
gpgme_initialized = true;
1131
if(interface[0] != '\0'){
1132
if_index = (AvahiIfIndex) if_nametoindex(interface);
1134
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1135
exitcode = EXIT_FAILURE;
1140
if(connect_to != NULL){
1141
/* Connect directly, do not use Zeroconf */
1142
/* (Mainly meant for debugging) */
1143
char *address = strrchr(connect_to, ':');
1144
if(address == NULL){
1145
fprintf(stderr, "No colon in address\n");
1146
exitcode = EXIT_FAILURE;
1150
ret = sscanf(address+1, "%" SCNdMAX "%n", &tmpmax, &numchars);
1151
if(ret < 1 or tmpmax != (uint16_t)tmpmax
1152
or address[numchars+1] != '\0'){
1153
fprintf(stderr, "Bad port number\n");
1154
exitcode = EXIT_FAILURE;
1157
port = (uint16_t)tmpmax;
1159
address = connect_to;
1160
/* Colon in address indicates IPv6 */
1162
if(strchr(address, ':') != NULL){
1167
ret = start_mandos_communication(address, port, if_index, af);
1169
exitcode = EXIT_FAILURE;
1171
exitcode = EXIT_SUCCESS;
1177
avahi_set_log_function(empty_log);
1180
/* Initialize the pseudo-RNG for Avahi */
1181
srand((unsigned int) time(NULL));
1183
/* Allocate main Avahi loop object */
1184
mc.simple_poll = avahi_simple_poll_new();
1185
if(mc.simple_poll == NULL){
1186
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1187
exitcode = EXIT_FAILURE;
507
1192
AvahiServerConfig config;
508
AvahiSServiceBrowser *sb = NULL;
512
avahi_set_log_function(empty_log);
514
/* Initialize the psuedo-RNG */
517
/* Allocate main loop object */
518
if (!(simple_poll = avahi_simple_poll_new())) {
519
fprintf(stderr, "Failed to create simple poll object.\n");
523
/* Do not publish any local records */
1193
/* Do not publish any local Zeroconf records */
524
1194
avahi_server_config_init(&config);
525
1195
config.publish_hinfo = 0;
526
1196
config.publish_addresses = 0;
527
1197
config.publish_workstation = 0;
528
1198
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; */
535
1200
/* Allocate a new server */
536
server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
538
/* Free the configuration data */
1201
mc.server = avahi_server_new(avahi_simple_poll_get
1202
(mc.simple_poll), &config, NULL,
1205
/* Free the Avahi configuration data */
539
1206
avahi_server_config_free(&config);
541
/* Check wether creating the server object succeeded */
543
fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
547
/* Create the service browser */
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)));
553
/* Run the main loop */
554
avahi_simple_poll_loop(simple_poll);
562
avahi_s_service_browser_free(sb);
565
avahi_server_free(server);
568
avahi_simple_poll_free(simple_poll);
1209
/* Check if creating the Avahi server object succeeded */
1210
if(mc.server == NULL){
1211
fprintf(stderr, "Failed to create Avahi server: %s\n",
1212
avahi_strerror(error));
1213
exitcode = EXIT_FAILURE;
1217
/* Create the Avahi service browser */
1218
sb = avahi_s_service_browser_new(mc.server, if_index,
1219
AVAHI_PROTO_INET6, "_mandos._tcp",
1220
NULL, 0, browse_callback, NULL);
1222
fprintf(stderr, "Failed to create service browser: %s\n",
1223
avahi_strerror(avahi_server_errno(mc.server)));
1224
exitcode = EXIT_FAILURE;
1228
sigemptyset(&sigterm_action.sa_mask);
1229
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1231
perror("sigaddset");
1232
exitcode = EXIT_FAILURE;
1235
ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
1237
perror("sigaction");
1238
exitcode = EXIT_FAILURE;
1242
/* Run the main loop */
1245
fprintf(stderr, "Starting Avahi loop search\n");
1248
avahi_simple_poll_loop(mc.simple_poll);
1253
fprintf(stderr, "%s exiting\n", argv[0]);
1256
/* Cleanup things */
1258
avahi_s_service_browser_free(sb);
1260
if(mc.server != NULL)
1261
avahi_server_free(mc.server);
1263
if(mc.simple_poll != NULL)
1264
avahi_simple_poll_free(mc.simple_poll);
1266
if(gnutls_initialized){
1267
gnutls_certificate_free_credentials(mc.cred);
1268
gnutls_global_deinit();
1269
gnutls_dh_params_deinit(mc.dh_params);
1272
if(gpgme_initialized){
1273
gpgme_release(mc.ctx);
1276
/* Removes the temp directory used by GPGME */
1277
if(tempdir_created){
1279
struct dirent *direntry;
1280
d = opendir(tempdir);
1282
if(errno != ENOENT){
1287
direntry = readdir(d);
1288
if(direntry == NULL){
1291
/* Skip "." and ".." */
1292
if(direntry->d_name[0] == '.'
1293
and (direntry->d_name[1] == '\0'
1294
or (direntry->d_name[1] == '.'
1295
and direntry->d_name[2] == '\0'))){
1298
char *fullname = NULL;
1299
ret = asprintf(&fullname, "%s/%s", tempdir,
1305
ret = remove(fullname);
1307
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1314
ret = rmdir(tempdir);
1315
if(ret == -1 and errno != ENOENT){