123
288
/* Create new empty GPGME data buffer for the plaintext */
124
289
rc = gpgme_data_new(&dh_plain);
125
if (rc != GPG_ERR_NO_ERROR){
290
if(rc != GPG_ERR_NO_ERROR){
126
291
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
127
292
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){
293
gpgme_data_release(dh_crypto);
297
/* Decrypt data from the cryptotext data buffer to the plaintext
299
rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
300
if(rc != GPG_ERR_NO_ERROR){
142
301
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
143
302
gpgme_strsource(rc), gpgme_strerror(rc));
303
plaintext_length = -1;
305
gpgme_decrypt_result_t result;
306
result = gpgme_op_decrypt_result(mc.ctx);
308
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
310
fprintf(stderr, "Unsupported algorithm: %s\n",
311
result->unsupported_algorithm);
312
fprintf(stderr, "Wrong key usage: %u\n",
313
result->wrong_key_usage);
314
if(result->file_name != NULL){
315
fprintf(stderr, "File name: %s\n", result->file_name);
317
gpgme_recipient_t recipient;
318
recipient = result->recipients;
319
while(recipient != NULL){
320
fprintf(stderr, "Public key algorithm: %s\n",
321
gpgme_pubkey_algo_name(recipient->pubkey_algo));
322
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
323
fprintf(stderr, "Secret key available: %s\n",
324
recipient->status == GPG_ERR_NO_SECKEY
326
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);
334
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
170
337
/* Seek back to the beginning of the GPGME plaintext data buffer */
171
gpgme_data_seek(dh_plain, 0, SEEK_SET);
338
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
339
perror("gpgme_data_seek");
340
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;
346
plaintext_capacity = incbuffer(plaintext,
347
(size_t)plaintext_length,
349
if(plaintext_capacity == 0){
351
plaintext_length = -1;
184
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
355
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
185
357
/* Print the data, if any */
187
/* If password is empty, then a incorrect error will be printed */
191
363
perror("gpgme_data_read");
194
new_packet_length += ret;
197
/* Delete the GPGME plaintext data buffer */
364
plaintext_length = -1;
367
plaintext_length += ret;
371
fprintf(stderr, "Decrypted password is: ");
372
for(ssize_t i = 0; i < plaintext_length; i++){
373
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
375
fprintf(stderr, "\n");
380
/* Delete the GPGME cryptotext data buffer */
381
gpgme_data_release(dh_crypto);
383
/* Delete the GPGME plaintext data buffer */
198
384
gpgme_data_release(dh_plain);
199
return new_packet_length;
385
return plaintext_length;
202
static const char * safer_gnutls_strerror (int value) {
203
const char *ret = gnutls_strerror (value);
388
static const char * safer_gnutls_strerror(int value){
389
const char *ret = gnutls_strerror(value); /* Spurious warning from
390
-Wunreachable-code */
205
392
ret = "(unknown)";
209
void debuggnutls(int level, const char* string){
210
fprintf(stderr, "%s", string);
396
/* GnuTLS log function callback */
397
static void debuggnutls(__attribute__((unused)) int level,
399
fprintf(stderr, "GnuTLS: %s", string);
213
int initgnutls(encrypted_session *es){
402
static int init_gnutls_global(const char *pubkeyfilename,
403
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));
407
fprintf(stderr, "Initializing GnuTLS\n");
410
ret = gnutls_global_init();
411
if(ret != GNUTLS_E_SUCCESS){
412
fprintf(stderr, "GnuTLS global_init: %s\n",
413
safer_gnutls_strerror(ret));
418
/* "Use a log level over 10 to enable all debugging options."
421
gnutls_global_set_log_level(11);
422
gnutls_global_set_log_function(debuggnutls);
425
/* OpenPGP credentials */
426
ret = gnutls_certificate_allocate_credentials(&mc.cred);
427
if(ret != GNUTLS_E_SUCCESS){
428
fprintf(stderr, "GnuTLS memory error: %s\n",
429
safer_gnutls_strerror(ret));
430
gnutls_global_deinit();
435
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
436
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
235
440
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));
441
(mc.cred, pubkeyfilename, seckeyfilename,
442
GNUTLS_OPENPGP_FMT_BASE64);
443
if(ret != GNUTLS_E_SUCCESS){
445
"Error[%d] while reading the OpenPGP key pair ('%s',"
446
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
447
fprintf(stderr, "The GnuTLS error is: %s\n",
448
safer_gnutls_strerror(ret));
452
/* GnuTLS server initialization */
453
ret = gnutls_dh_params_init(&mc.dh_params);
454
if(ret != GNUTLS_E_SUCCESS){
455
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
456
" %s\n", safer_gnutls_strerror(ret));
459
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
460
if(ret != GNUTLS_E_SUCCESS){
461
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
462
safer_gnutls_strerror(ret));
466
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
472
gnutls_certificate_free_credentials(mc.cred);
473
gnutls_global_deinit();
474
gnutls_dh_params_deinit(mc.dh_params);
478
static int init_gnutls_session(gnutls_session_t *session){
480
/* GnuTLS session creation */
482
ret = gnutls_init(session, GNUTLS_SERVER);
486
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
487
if(ret != GNUTLS_E_SUCCESS){
488
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
489
safer_gnutls_strerror(ret));
495
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
497
gnutls_deinit(*session);
500
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
501
if(ret != GNUTLS_E_SUCCESS){
502
fprintf(stderr, "Syntax error at: %s\n", err);
503
fprintf(stderr, "GnuTLS error: %s\n",
504
safer_gnutls_strerror(ret));
505
gnutls_deinit(*session);
511
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
514
gnutls_deinit(*session);
517
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
518
if(ret != GNUTLS_E_SUCCESS){
519
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
520
safer_gnutls_strerror(ret));
521
gnutls_deinit(*session);
286
525
/* ignore client certificate if any. */
287
gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
526
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
289
gnutls_dh_set_prime_bits (es->session, DH_BITS);
528
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
294
void empty_log(AvahiLogLevel level, const char *txt){}
533
/* Avahi log function callback */
534
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
535
__attribute__((unused)) const char *txt){}
296
int start_mandos_communcation(char *ip, uint16_t port){
298
struct sockaddr_in6 to;
299
struct in6_addr ip_addr;
300
encrypted_session es;
537
/* Called when a Mandos server is found */
538
static int start_mandos_communication(const char *ip, uint16_t port,
539
AvahiIfIndex if_index,
541
int ret, tcp_sd = -1;
544
struct sockaddr_in in;
545
struct sockaddr_in6 in6;
301
547
char *buffer = NULL;
302
char *decrypted_buffer;
548
char *decrypted_buffer = NULL;
303
549
size_t buffer_length = 0;
304
550
size_t buffer_capacity = 0;
305
ssize_t decrypted_buffer_size;
309
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
553
gnutls_session_t session;
554
int pf; /* Protocol family */
571
fprintf(stderr, "Bad address family: %d\n", af);
576
ret = init_gnutls_session(&session);
582
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
586
tcp_sd = socket(pf, SOCK_STREAM, 0);
311
589
perror("socket");
315
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, "eth0", 5);
317
perror("setsockopt bindtodevice");
321
memset(&to,0,sizeof(to));
322
to.sin6_family = AF_INET6;
323
ret = inet_pton(AF_INET6, ip, &ip_addr);
599
memset(&to, 0, sizeof(to));
601
to.in6.sin6_family = (sa_family_t)af;
602
ret = inet_pton(af, ip, &to.in6.sin6_addr);
604
to.in.sin_family = (sa_family_t)af;
605
ret = inet_pton(af, ip, &to.in.sin_addr);
325
609
perror("inet_pton");
329
615
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));
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");
361
if (buffer_length + BUFFER_SIZE > buffer_capacity){
362
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
367
buffer_capacity += BUFFER_SIZE;
370
ret = gnutls_record_recv
371
(es.session, buffer+buffer_length, BUFFER_SIZE);
620
to.in6.sin6_port = htons(port); /* Spurious warnings from
622
-Wunreachable-code */
624
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
625
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
627
if(if_index == AVAHI_IF_UNSPEC){
628
fprintf(stderr, "An IPv6 link-local address is incomplete"
629
" without a network interface\n");
633
/* Set the network interface number as scope */
634
to.in6.sin6_scope_id = (uint32_t)if_index;
637
to.in.sin_port = htons(port); /* Spurious warnings from
639
-Wunreachable-code */
648
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
649
char interface[IF_NAMESIZE];
650
if(if_indextoname((unsigned int)if_index, interface) == NULL){
651
perror("if_indextoname");
653
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
654
ip, interface, port);
657
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
660
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
661
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
664
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
667
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
673
if(strcmp(addrstr, ip) != 0){
674
fprintf(stderr, "Canonical address form: %s\n", addrstr);
685
ret = connect(tcp_sd, &to.in6, sizeof(to));
687
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
690
if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
703
const char *out = mandos_protocol_version;
706
size_t out_size = strlen(out);
707
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
708
out_size - written));
715
written += (size_t)ret;
716
if(written < out_size){
719
if(out == mandos_protocol_version){
734
fprintf(stderr, "Establishing TLS session with %s\n", ip);
742
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
750
ret = gnutls_handshake(session);
755
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
757
if(ret != GNUTLS_E_SUCCESS){
759
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
766
/* Read OpenPGP packet that contains the wanted password */
769
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
780
buffer_capacity = incbuffer(&buffer, buffer_length,
782
if(buffer_capacity == 0){
794
sret = gnutls_record_recv(session, buffer+buffer_length,
377
801
case GNUTLS_E_INTERRUPTED:
378
802
case GNUTLS_E_AGAIN:
380
804
case GNUTLS_E_REHANDSHAKE:
381
ret = gnutls_handshake (es.session);
383
fprintf(stderr, "\n*** Handshake failed ***\n");
806
ret = gnutls_handshake(session);
812
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
814
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
390
fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
392
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
821
fprintf(stderr, "Unknown error while reading data from"
822
" encrypted session with Mandos server\n");
823
gnutls_bye(session, GNUTLS_SHUT_RDWR);
396
buffer_length += ret;
400
if (buffer_length > 0){
401
if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) == 0){
828
buffer_length += (size_t) sret;
833
fprintf(stderr, "Closing TLS session\n");
842
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
847
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
849
if(buffer_length > 0){
850
ssize_t decrypted_buffer_size;
851
decrypted_buffer_size = pgp_packet_decrypt(buffer,
854
if(decrypted_buffer_size >= 0){
857
while(written < (size_t) decrypted_buffer_size){
863
ret = (int)fwrite(decrypted_buffer + written, 1,
864
(size_t)decrypted_buffer_size - written,
866
if(ret == 0 and ferror(stdout)){
869
fprintf(stderr, "Error writing encrypted data: %s\n",
875
written += (size_t)ret;
881
/* Shutdown procedure */
886
free(decrypted_buffer);
889
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
897
gnutls_deinit(session);
404
fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
405
free(decrypted_buffer);
412
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
415
gnutls_deinit (es.session);
416
gnutls_certificate_free_credentials (es.cred);
417
gnutls_global_deinit ();
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[]) {
907
static void resolve_callback(AvahiSServiceResolver *r,
908
AvahiIfIndex interface,
910
AvahiResolverEvent event,
914
const char *host_name,
915
const AvahiAddress *address,
917
AVAHI_GCC_UNUSED AvahiStringList *txt,
918
AVAHI_GCC_UNUSED AvahiLookupResultFlags
920
AVAHI_GCC_UNUSED void* userdata){
923
/* Called whenever a service has been resolved successfully or
932
case AVAHI_RESOLVER_FAILURE:
933
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
934
" of type '%s' in domain '%s': %s\n", name, type, domain,
935
avahi_strerror(avahi_server_errno(mc.server)));
938
case AVAHI_RESOLVER_FOUND:
940
char ip[AVAHI_ADDRESS_STR_MAX];
941
avahi_address_snprint(ip, sizeof(ip), address);
943
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
944
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
945
ip, (intmax_t)interface, port);
947
int ret = start_mandos_communication(ip, port, interface,
948
avahi_proto_to_af(proto));
950
avahi_simple_poll_quit(mc.simple_poll);
954
avahi_s_service_resolver_free(r);
957
static void browse_callback(AvahiSServiceBrowser *b,
958
AvahiIfIndex interface,
959
AvahiProtocol protocol,
960
AvahiBrowserEvent event,
964
AVAHI_GCC_UNUSED AvahiLookupResultFlags
966
AVAHI_GCC_UNUSED void* userdata){
969
/* Called whenever a new services becomes available on the LAN or
970
is removed from the LAN */
978
case AVAHI_BROWSER_FAILURE:
980
fprintf(stderr, "(Avahi browser) %s\n",
981
avahi_strerror(avahi_server_errno(mc.server)));
982
avahi_simple_poll_quit(mc.simple_poll);
985
case AVAHI_BROWSER_NEW:
986
/* We ignore the returned Avahi resolver object. In the callback
987
function we free it. If the Avahi server is terminated before
988
the callback function is called the Avahi server will free the
991
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
992
name, type, domain, protocol, 0,
993
resolve_callback, NULL) == NULL)
994
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
995
name, avahi_strerror(avahi_server_errno(mc.server)));
998
case AVAHI_BROWSER_REMOVE:
1001
case AVAHI_BROWSER_ALL_FOR_NOW:
1002
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1004
fprintf(stderr, "No Mandos server found, still searching...\n");
1010
/* stop main loop after sigterm has been called */
1011
static void handle_sigterm(int sig){
1016
signal_received = sig;
1017
int old_errno = errno;
1018
if(mc.simple_poll != NULL){
1019
avahi_simple_poll_quit(mc.simple_poll);
1025
* This function determines if a directory entry in /sys/class/net
1026
* corresponds to an acceptable network device.
1027
* (This function is passed to scandir(3) as a filter function.)
1029
int good_interface(const struct dirent *if_entry){
1031
char *flagname = NULL;
1032
if(if_entry->d_name[0] == '.'){
1035
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
1041
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1048
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1049
/* read line from flags_fd */
1050
ssize_t to_read = 2+(sizeof(ifreq_flags)*2)+1; /* "0x1003\n" */
1051
char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1052
flagstring[(size_t)to_read] = '\0';
1053
if(flagstring == NULL){
1059
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1076
tmpmax = strtoimax(flagstring, &tmp, 0);
1077
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1078
and not (isspace(*tmp)))
1079
or tmpmax != (ifreq_flags)tmpmax){
1081
fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1082
flagstring, if_entry->d_name);
1088
ifreq_flags flags = (ifreq_flags)tmpmax;
1089
/* Reject the loopback device */
1090
if(flags & IFF_LOOPBACK){
1092
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1097
/* Accept point-to-point devices only if connect_to is specified */
1098
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1100
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1105
/* Otherwise, reject non-broadcast-capable devices */
1106
if(not (flags & IFF_BROADCAST)){
1108
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1113
/* Reject non-ARP interfaces (including dummy interfaces) */
1114
if(flags & IFF_NOARP){
1116
fprintf(stderr, "Rejecting non-ARP interface \"%s\"\n",
1121
/* Accept this device */
1123
fprintf(stderr, "Interface \"%s\" is acceptable\n",
1129
int main(int argc, char *argv[]){
1130
AvahiSServiceBrowser *sb = NULL;
1135
int exitcode = EXIT_SUCCESS;
1136
const char *interface = "";
1137
struct ifreq network;
1139
bool take_down_interface = false;
1142
char tempdir[] = "/tmp/mandosXXXXXX";
1143
bool tempdir_created = false;
1144
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1145
const char *seckey = PATHDIR "/" SECKEY;
1146
const char *pubkey = PATHDIR "/" PUBKEY;
1148
bool gnutls_initialized = false;
1149
bool gpgme_initialized = false;
1152
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1153
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1158
/* Lower any group privileges we might have, just to be safe */
1165
/* Lower user privileges (temporarily) */
1177
struct argp_option options[] = {
1178
{ .name = "debug", .key = 128,
1179
.doc = "Debug mode", .group = 3 },
1180
{ .name = "connect", .key = 'c',
1181
.arg = "ADDRESS:PORT",
1182
.doc = "Connect directly to a specific Mandos server",
1184
{ .name = "interface", .key = 'i',
1186
.doc = "Network interface that will be used to search for"
1189
{ .name = "seckey", .key = 's',
1191
.doc = "OpenPGP secret key file base name",
1193
{ .name = "pubkey", .key = 'p',
1195
.doc = "OpenPGP public key file base name",
1197
{ .name = "dh-bits", .key = 129,
1199
.doc = "Bit length of the prime number used in the"
1200
" Diffie-Hellman key exchange",
1202
{ .name = "priority", .key = 130,
1204
.doc = "GnuTLS priority string for the TLS handshake",
1206
{ .name = "delay", .key = 131,
1208
.doc = "Maximum delay to wait for interface startup",
1211
* These reproduce what we would get without ARGP_NO_HELP
1213
{ .name = "help", .key = '?',
1214
.doc = "Give this help list", .group = -1 },
1215
{ .name = "usage", .key = -3,
1216
.doc = "Give a short usage message", .group = -1 },
1217
{ .name = "version", .key = 'V',
1218
.doc = "Print program version", .group = -1 },
1222
error_t parse_opt(int key, char *arg,
1223
struct argp_state *state){
1226
case 128: /* --debug */
1229
case 'c': /* --connect */
1232
case 'i': /* --interface */
1235
case 's': /* --seckey */
1238
case 'p': /* --pubkey */
1241
case 129: /* --dh-bits */
1243
tmpmax = strtoimax(arg, &tmp, 10);
1244
if(errno != 0 or tmp == arg or *tmp != '\0'
1245
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1246
argp_error(state, "Bad number of DH bits");
1248
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1250
case 130: /* --priority */
1253
case 131: /* --delay */
1255
delay = strtof(arg, &tmp);
1256
if(errno != 0 or tmp == arg or *tmp != '\0'){
1257
argp_error(state, "Bad delay");
1261
* These reproduce what we would get without ARGP_NO_HELP
1263
case '?': /* --help */
1264
argp_state_help(state, state->out_stream,
1265
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1266
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1267
case -3: /* --usage */
1268
argp_state_help(state, state->out_stream,
1269
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1270
case 'V': /* --version */
1271
fprintf(state->out_stream, "%s\n", argp_program_version);
1272
exit(argp_err_exit_status);
1275
return ARGP_ERR_UNKNOWN;
1280
struct argp argp = { .options = options, .parser = parse_opt,
1282
.doc = "Mandos client -- Get and decrypt"
1283
" passwords from a Mandos server" };
1284
ret = argp_parse(&argp, argc, argv,
1285
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
1292
perror("argp_parse");
1293
exitcode = EX_OSERR;
1296
exitcode = EX_USAGE;
1302
avahi_set_log_function(empty_log);
1305
if(interface[0] == '\0'){
1306
struct dirent **direntries;
1307
ret = scandir(sys_class_net, &direntries, good_interface,
1310
/* Pick the first good interface */
1311
interface = strdup(direntries[0]->d_name);
1313
fprintf(stderr, "Using interface \"%s\"\n", interface);
1315
if(interface == NULL){
1318
exitcode = EXIT_FAILURE;
1324
fprintf(stderr, "Could not find a network interface\n");
1325
exitcode = EXIT_FAILURE;
1330
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1331
from the signal handler */
1332
/* Initialize the pseudo-RNG for Avahi */
1333
srand((unsigned int) time(NULL));
1334
mc.simple_poll = avahi_simple_poll_new();
1335
if(mc.simple_poll == NULL){
1336
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1337
exitcode = EX_UNAVAILABLE;
1341
sigemptyset(&sigterm_action.sa_mask);
1342
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1344
perror("sigaddset");
1345
exitcode = EX_OSERR;
1348
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1350
perror("sigaddset");
1351
exitcode = EX_OSERR;
1354
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1356
perror("sigaddset");
1357
exitcode = EX_OSERR;
1360
/* Need to check if the handler is SIG_IGN before handling:
1361
| [[info:libc:Initial Signal Actions]] |
1362
| [[info:libc:Basic Signal Handling]] |
1364
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1366
perror("sigaction");
1369
if(old_sigterm_action.sa_handler != SIG_IGN){
1370
ret = sigaction(SIGINT, &sigterm_action, NULL);
1372
perror("sigaction");
1373
exitcode = EX_OSERR;
1377
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1379
perror("sigaction");
1382
if(old_sigterm_action.sa_handler != SIG_IGN){
1383
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1385
perror("sigaction");
1386
exitcode = EX_OSERR;
1390
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1392
perror("sigaction");
1395
if(old_sigterm_action.sa_handler != SIG_IGN){
1396
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1398
perror("sigaction");
1399
exitcode = EX_OSERR;
1404
/* If the interface is down, bring it up */
1405
if(strcmp(interface, "none") != 0){
1406
if_index = (AvahiIfIndex) if_nametoindex(interface);
1408
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1409
exitcode = EX_UNAVAILABLE;
1417
/* Re-raise priviliges */
1425
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1426
messages about the network interface to mess up the prompt */
1427
ret = klogctl(8, NULL, 5);
1428
bool restore_loglevel = true;
1430
restore_loglevel = false;
1433
#endif /* __linux__ */
1435
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1438
exitcode = EX_OSERR;
1440
if(restore_loglevel){
1441
ret = klogctl(7, NULL, 0);
1446
#endif /* __linux__ */
1447
/* Lower privileges */
1455
strcpy(network.ifr_name, interface);
1456
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1458
perror("ioctl SIOCGIFFLAGS");
1460
if(restore_loglevel){
1461
ret = klogctl(7, NULL, 0);
1466
#endif /* __linux__ */
1467
exitcode = EX_OSERR;
1468
/* Lower privileges */
1476
if((network.ifr_flags & IFF_UP) == 0){
1477
network.ifr_flags |= IFF_UP;
1478
take_down_interface = true;
1479
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1481
take_down_interface = false;
1482
perror("ioctl SIOCSIFFLAGS +IFF_UP");
1483
exitcode = EX_OSERR;
1485
if(restore_loglevel){
1486
ret = klogctl(7, NULL, 0);
1491
#endif /* __linux__ */
1492
/* Lower privileges */
1501
/* sleep checking until interface is running */
1502
for(int i=0; i < delay * 4; i++){
1503
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1505
perror("ioctl SIOCGIFFLAGS");
1506
} else if(network.ifr_flags & IFF_RUNNING){
1509
struct timespec sleeptime = { .tv_nsec = 250000000 };
1510
ret = nanosleep(&sleeptime, NULL);
1511
if(ret == -1 and errno != EINTR){
1512
perror("nanosleep");
1515
if(not take_down_interface){
1516
/* We won't need the socket anymore */
1517
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1523
if(restore_loglevel){
1524
/* Restores kernel loglevel to default */
1525
ret = klogctl(7, NULL, 0);
1530
#endif /* __linux__ */
1531
/* Lower privileges */
1533
if(take_down_interface){
1534
/* Lower privileges */
1540
/* Lower privileges permanently */
1552
ret = init_gnutls_global(pubkey, seckey);
1554
fprintf(stderr, "init_gnutls_global failed\n");
1555
exitcode = EX_UNAVAILABLE;
1558
gnutls_initialized = true;
1565
tempdir_created = true;
1566
if(mkdtemp(tempdir) == NULL){
1567
tempdir_created = false;
1576
if(not init_gpgme(pubkey, seckey, tempdir)){
1577
fprintf(stderr, "init_gpgme failed\n");
1578
exitcode = EX_UNAVAILABLE;
1581
gpgme_initialized = true;
1588
if(connect_to != NULL){
1589
/* Connect directly, do not use Zeroconf */
1590
/* (Mainly meant for debugging) */
1591
char *address = strrchr(connect_to, ':');
1592
if(address == NULL){
1593
fprintf(stderr, "No colon in address\n");
1594
exitcode = EX_USAGE;
1604
tmpmax = strtoimax(address+1, &tmp, 10);
1605
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1606
or tmpmax != (uint16_t)tmpmax){
1607
fprintf(stderr, "Bad port number\n");
1608
exitcode = EX_USAGE;
1616
port = (uint16_t)tmpmax;
1618
address = connect_to;
1619
/* Colon in address indicates IPv6 */
1621
if(strchr(address, ':') != NULL){
1631
while(not quit_now){
1632
ret = start_mandos_communication(address, port, if_index, af);
1633
if(quit_now or ret == 0){
1640
exitcode = EXIT_SUCCESS;
507
1651
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 */
1652
/* Do not publish any local Zeroconf records */
524
1653
avahi_server_config_init(&config);
525
1654
config.publish_hinfo = 0;
526
1655
config.publish_addresses = 0;
527
1656
config.publish_workstation = 0;
528
1657
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
1659
/* Allocate a new server */
536
server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
538
/* Free the configuration data */
1660
mc.server = avahi_server_new(avahi_simple_poll_get
1661
(mc.simple_poll), &config, NULL,
1664
/* Free the Avahi configuration data */
539
1665
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);
1668
/* Check if creating the Avahi server object succeeded */
1669
if(mc.server == NULL){
1670
fprintf(stderr, "Failed to create Avahi server: %s\n",
1671
avahi_strerror(error));
1672
exitcode = EX_UNAVAILABLE;
1680
/* Create the Avahi service browser */
1681
sb = avahi_s_service_browser_new(mc.server, if_index,
1682
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1683
NULL, 0, browse_callback, NULL);
1685
fprintf(stderr, "Failed to create service browser: %s\n",
1686
avahi_strerror(avahi_server_errno(mc.server)));
1687
exitcode = EX_UNAVAILABLE;
1695
/* Run the main loop */
1698
fprintf(stderr, "Starting Avahi loop search\n");
1701
avahi_simple_poll_loop(mc.simple_poll);
1706
fprintf(stderr, "%s exiting\n", argv[0]);
1709
/* Cleanup things */
1711
avahi_s_service_browser_free(sb);
1713
if(mc.server != NULL)
1714
avahi_server_free(mc.server);
1716
if(mc.simple_poll != NULL)
1717
avahi_simple_poll_free(mc.simple_poll);
1719
if(gnutls_initialized){
1720
gnutls_certificate_free_credentials(mc.cred);
1721
gnutls_global_deinit();
1722
gnutls_dh_params_deinit(mc.dh_params);
1725
if(gpgme_initialized){
1726
gpgme_release(mc.ctx);
1729
/* Take down the network interface */
1730
if(take_down_interface){
1731
/* Re-raise priviliges */
1738
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1740
perror("ioctl SIOCGIFFLAGS");
1741
} else if(network.ifr_flags & IFF_UP) {
1742
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1743
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1745
perror("ioctl SIOCSIFFLAGS -IFF_UP");
1748
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1752
/* Lower privileges permanently */
1761
/* Removes the temp directory used by GPGME */
1762
if(tempdir_created){
1764
struct dirent *direntry;
1765
d = opendir(tempdir);
1767
if(errno != ENOENT){
1772
direntry = readdir(d);
1773
if(direntry == NULL){
1776
/* Skip "." and ".." */
1777
if(direntry->d_name[0] == '.'
1778
and (direntry->d_name[1] == '\0'
1779
or (direntry->d_name[1] == '.'
1780
and direntry->d_name[2] == '\0'))){
1783
char *fullname = NULL;
1784
ret = asprintf(&fullname, "%s/%s", tempdir,
1790
ret = remove(fullname);
1792
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1799
ret = rmdir(tempdir);
1800
if(ret == -1 and errno != ENOENT){
1806
sigemptyset(&old_sigterm_action.sa_mask);
1807
old_sigterm_action.sa_handler = SIG_DFL;
1808
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
1809
&old_sigterm_action,
1812
perror("sigaction");
1815
ret = raise(signal_received);
1816
} while(ret != 0 and errno == EINTR);
1821
TEMP_FAILURE_RETRY(pause());