288
116
/* Create new empty GPGME data buffer for the plaintext */
289
117
rc = gpgme_data_new(&dh_plain);
290
if(rc != GPG_ERR_NO_ERROR){
118
if (rc != GPG_ERR_NO_ERROR){
291
119
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
292
120
gpgme_strsource(rc), gpgme_strerror(rc));
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){
124
/* Create new GPGME "context" */
125
rc = gpgme_new(&ctx);
126
if (rc != GPG_ERR_NO_ERROR){
127
fprintf(stderr, "bad gpgme_new: %s: %s\n",
128
gpgme_strsource(rc), gpgme_strerror(rc));
132
/* Decrypt data from the FILE pointer to the plaintext data buffer */
133
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
134
if (rc != GPG_ERR_NO_ERROR){
301
135
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
302
136
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;
141
fprintf(stderr, "decryption of gpg packet succeeded\n");
145
gpgme_decrypt_result_t result;
146
result = gpgme_op_decrypt_result(ctx);
148
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
150
fprintf(stderr, "Unsupported algorithm: %s\n", result->unsupported_algorithm);
151
fprintf(stderr, "Wrong key usage: %d\n", result->wrong_key_usage);
152
if(result->file_name != NULL){
153
fprintf(stderr, "File name: %s\n", result->file_name);
155
gpgme_recipient_t recipient;
156
recipient = result->recipients;
319
158
while(recipient != NULL){
320
159
fprintf(stderr, "Public key algorithm: %s\n",
321
160
gpgme_pubkey_algo_name(recipient->pubkey_algo));
322
161
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
323
162
fprintf(stderr, "Secret key available: %s\n",
324
recipient->status == GPG_ERR_NO_SECKEY
163
recipient->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
326
164
recipient = recipient->next;
334
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
170
/* Delete the GPGME FILE pointer cryptotext data buffer */
171
gpgme_data_release(dh_crypto);
337
173
/* Seek back to the beginning of the GPGME plaintext data buffer */
338
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
339
perror("gpgme_data_seek");
340
plaintext_length = -1;
174
gpgme_data_seek(dh_plain, 0, SEEK_SET);
346
plaintext_capacity = incbuffer(plaintext,
347
(size_t)plaintext_length,
349
if(plaintext_capacity == 0){
351
plaintext_length = -1;
178
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
179
*new_packet = realloc(*new_packet, new_packet_capacity + BUFFER_SIZE);
180
if (*new_packet == NULL){
184
new_packet_capacity += BUFFER_SIZE;
355
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
187
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length, BUFFER_SIZE);
357
188
/* Print the data, if any */
190
/* If password is empty, then a incorrect error will be printed */
363
194
perror("gpgme_data_read");
364
plaintext_length = -1;
367
plaintext_length += ret;
197
new_packet_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");
201
fprintf(stderr, "decrypted password is: %s\n", *new_packet);
380
/* Delete the GPGME cryptotext data buffer */
381
gpgme_data_release(dh_crypto);
383
/* Delete the GPGME plaintext data buffer */
204
/* Delete the GPGME plaintext data buffer */
384
205
gpgme_data_release(dh_plain);
385
return plaintext_length;
206
return new_packet_length;
388
static const char * safer_gnutls_strerror(int value){
389
const char *ret = gnutls_strerror(value); /* Spurious warning from
390
-Wunreachable-code */
209
static const char * safer_gnutls_strerror (int value) {
210
const char *ret = gnutls_strerror (value);
392
212
ret = "(unknown)";
396
/* GnuTLS log function callback */
397
static void debuggnutls(__attribute__((unused)) int level,
399
fprintf(stderr, "GnuTLS: %s", string);
216
void debuggnutls(int level, const char* string){
217
fprintf(stderr, "%s", string);
402
static int init_gnutls_global(const char *pubkeyfilename,
403
const char *seckeyfilename){
220
int initgnutls(encrypted_session *es){
407
fprintf(stderr, "Initializing GnuTLS\n");
225
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));
229
if ((ret = gnutls_global_init ())
230
!= GNUTLS_E_SUCCESS) {
231
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
418
/* "Use a log level over 10 to enable all debugging options."
421
236
gnutls_global_set_log_level(11);
422
237
gnutls_global_set_log_function(debuggnutls);
425
/* OpenPGP credentials */
426
gnutls_certificate_allocate_credentials(&mc.cred);
427
if(ret != GNUTLS_E_SUCCESS){
428
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
432
safer_gnutls_strerror(ret));
433
gnutls_global_deinit();
241
/* openpgp credentials */
242
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
243
!= GNUTLS_E_SUCCESS) {
244
fprintf (stderr, "memory error: %s\n", safer_gnutls_strerror(ret));
438
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
439
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
249
fprintf(stderr, "Attempting to use openpgp certificate %s"
250
" and keyfile %s as gnutls credentials\n", CERTFILE, KEYFILE);
443
253
ret = gnutls_certificate_set_openpgp_key_file
444
(mc.cred, pubkeyfilename, seckeyfilename,
445
GNUTLS_OPENPGP_FMT_BASE64);
446
if(ret != GNUTLS_E_SUCCESS){
448
"Error[%d] while reading the OpenPGP key pair ('%s',"
449
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
450
fprintf(stderr, "The GnuTLS error is: %s\n",
451
safer_gnutls_strerror(ret));
455
/* GnuTLS server initialization */
456
ret = gnutls_dh_params_init(&mc.dh_params);
457
if(ret != GNUTLS_E_SUCCESS){
458
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
459
" %s\n", safer_gnutls_strerror(ret));
462
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
463
if(ret != GNUTLS_E_SUCCESS){
464
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
465
safer_gnutls_strerror(ret));
469
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
475
gnutls_certificate_free_credentials(mc.cred);
476
gnutls_global_deinit();
477
gnutls_dh_params_deinit(mc.dh_params);
481
static int init_gnutls_session(gnutls_session_t *session){
483
/* GnuTLS session creation */
485
ret = gnutls_init(session, GNUTLS_SERVER);
489
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
490
if(ret != GNUTLS_E_SUCCESS){
491
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
492
safer_gnutls_strerror(ret));
498
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
500
gnutls_deinit(*session);
503
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
504
if(ret != GNUTLS_E_SUCCESS){
505
fprintf(stderr, "Syntax error at: %s\n", err);
506
fprintf(stderr, "GnuTLS error: %s\n",
507
safer_gnutls_strerror(ret));
508
gnutls_deinit(*session);
514
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
517
gnutls_deinit(*session);
520
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
521
if(ret != GNUTLS_E_SUCCESS){
522
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
523
safer_gnutls_strerror(ret));
524
gnutls_deinit(*session);
254
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
255
if (ret != GNUTLS_E_SUCCESS) {
257
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s', '%s')\n",
258
ret, CERTFILE, KEYFILE);
259
fprintf(stdout, "The Error is: %s\n",
260
safer_gnutls_strerror(ret));
264
//Gnutls server initialization
265
if ((ret = gnutls_dh_params_init (&es->dh_params))
266
!= GNUTLS_E_SUCCESS) {
267
fprintf (stderr, "Error in dh parameter initialization: %s\n",
268
safer_gnutls_strerror(ret));
272
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
273
!= GNUTLS_E_SUCCESS) {
274
fprintf (stderr, "Error in prime generation: %s\n",
275
safer_gnutls_strerror(ret));
279
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
281
// Gnutls session creation
282
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
283
!= GNUTLS_E_SUCCESS){
284
fprintf(stderr, "Error in gnutls session initialization: %s\n",
285
safer_gnutls_strerror(ret));
288
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
289
!= GNUTLS_E_SUCCESS) {
290
fprintf(stderr, "Syntax error at: %s\n", err);
291
fprintf(stderr, "Gnutls error: %s\n",
292
safer_gnutls_strerror(ret));
296
if ((ret = gnutls_credentials_set
297
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
298
!= GNUTLS_E_SUCCESS) {
299
fprintf(stderr, "Error setting a credentials set: %s\n",
300
safer_gnutls_strerror(ret));
528
304
/* ignore client certificate if any. */
529
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
305
gnutls_certificate_server_set_request (es->session, GNUTLS_CERT_IGNORE);
531
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
307
gnutls_dh_set_prime_bits (es->session, DH_BITS);
536
/* Avahi log function callback */
537
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
538
__attribute__((unused)) const char *txt){}
312
void empty_log(AvahiLogLevel level, const char *txt){}
540
/* Called when a Mandos server is found */
541
static int start_mandos_communication(const char *ip, uint16_t port,
542
AvahiIfIndex if_index,
544
int ret, tcp_sd = -1;
547
struct sockaddr_in in;
548
struct sockaddr_in6 in6;
314
int start_mandos_communcation(char *ip, uint16_t port){
316
struct sockaddr_in6 to;
317
struct in6_addr ip_addr;
318
encrypted_session es;
550
319
char *buffer = NULL;
551
char *decrypted_buffer = NULL;
320
char *decrypted_buffer;
552
321
size_t buffer_length = 0;
553
322
size_t buffer_capacity = 0;
556
gnutls_session_t session;
557
int pf; /* Protocol family */
574
fprintf(stderr, "Bad address family: %d\n", af);
579
ret = init_gnutls_session(&session);
323
ssize_t decrypted_buffer_size;
325
const char interface[] = "eth0";
585
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
328
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
589
tcp_sd = socket(pf, SOCK_STREAM, 0);
331
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
592
333
perror("socket");
602
memset(&to, 0, sizeof(to));
604
to.in6.sin6_family = (sa_family_t)af;
605
ret = inet_pton(af, ip, &to.in6.sin6_addr);
607
to.in.sin_family = (sa_family_t)af;
608
ret = inet_pton(af, ip, &to.in.sin_addr);
338
fprintf(stderr, "Binding to interface %s\n", interface);
341
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
343
perror("setsockopt bindtodevice");
347
memset(&to,0,sizeof(to));
348
to.sin6_family = AF_INET6;
349
ret = inet_pton(AF_INET6, ip, &ip_addr);
612
351
perror("inet_pton");
618
355
fprintf(stderr, "Bad address: %s\n", ip);
623
to.in6.sin6_port = htons(port); /* Spurious warnings from
625
-Wunreachable-code */
627
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
628
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
630
if(if_index == AVAHI_IF_UNSPEC){
631
fprintf(stderr, "An IPv6 link-local address is incomplete"
632
" without a network interface\n");
636
/* Set the network interface number as scope */
637
to.in6.sin6_scope_id = (uint32_t)if_index;
640
to.in.sin_port = htons(port); /* Spurious warnings from
642
-Wunreachable-code */
651
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
652
char interface[IF_NAMESIZE];
653
if(if_indextoname((unsigned int)if_index, interface) == NULL){
654
perror("if_indextoname");
656
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
657
ip, interface, port);
660
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
663
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
664
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
667
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
670
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
676
if(strcmp(addrstr, ip) != 0){
677
fprintf(stderr, "Canonical address form: %s\n", addrstr);
688
ret = connect(tcp_sd, &to.in6, sizeof(to));
690
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
693
if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
706
const char *out = mandos_protocol_version;
709
size_t out_size = strlen(out);
710
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
711
out_size - written));
718
written += (size_t)ret;
719
if(written < out_size){
722
if(out == mandos_protocol_version){
737
fprintf(stderr, "Establishing TLS session with %s\n", ip);
745
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
753
ret = gnutls_handshake(session);
758
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
760
if(ret != GNUTLS_E_SUCCESS){
762
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
769
/* Read OpenPGP packet that contains the wanted password */
772
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
783
buffer_capacity = incbuffer(&buffer, buffer_length,
785
if(buffer_capacity == 0){
797
sret = gnutls_record_recv(session, buffer+buffer_length,
358
to.sin6_port = htons(port);
359
to.sin6_scope_id = if_nametoindex(interface);
362
fprintf(stderr, "Connection to: %s\n", ip);
365
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
371
ret = initgnutls (&es);
378
gnutls_transport_set_ptr (es.session, (gnutls_transport_ptr_t) tcp_sd);
381
fprintf(stderr, "Establishing tls session with %s\n", ip);
385
ret = gnutls_handshake (es.session);
387
if (ret != GNUTLS_E_SUCCESS){
388
fprintf(stderr, "\n*** Handshake failed ***\n");
394
//Retrieve gpg packet that contains the wanted password
397
fprintf(stderr, "Retrieving pgp encrypted password from %s\n", ip);
401
if (buffer_length + BUFFER_SIZE > buffer_capacity){
402
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
407
buffer_capacity += BUFFER_SIZE;
410
ret = gnutls_record_recv
411
(es.session, buffer+buffer_length, BUFFER_SIZE);
804
417
case GNUTLS_E_INTERRUPTED:
805
418
case GNUTLS_E_AGAIN:
807
420
case GNUTLS_E_REHANDSHAKE:
809
ret = gnutls_handshake(session);
815
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
817
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
421
ret = gnutls_handshake (es.session);
423
fprintf(stderr, "\n*** Handshake failed ***\n");
824
fprintf(stderr, "Unknown error while reading data from"
825
" encrypted session with Mandos server\n");
826
gnutls_bye(session, GNUTLS_SHUT_RDWR);
831
buffer_length += (size_t) sret;
836
fprintf(stderr, "Closing TLS session\n");
845
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
850
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
852
if(buffer_length > 0){
853
ssize_t decrypted_buffer_size;
854
decrypted_buffer_size = pgp_packet_decrypt(buffer,
857
if(decrypted_buffer_size >= 0){
860
while(written < (size_t) decrypted_buffer_size){
866
ret = (int)fwrite(decrypted_buffer + written, 1,
867
(size_t)decrypted_buffer_size - written,
869
if(ret == 0 and ferror(stdout)){
872
fprintf(stderr, "Error writing encrypted data: %s\n",
878
written += (size_t)ret;
884
/* Shutdown procedure */
889
free(decrypted_buffer);
892
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
900
gnutls_deinit(session);
430
fprintf(stderr, "Unknown error while reading data from encrypted session with mandos server\n");
432
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
436
buffer_length += ret;
440
if (buffer_length > 0){
441
if ((decrypted_buffer_size = gpg_packet_decrypt(buffer, buffer_length, &decrypted_buffer, CERT_ROOT)) >= 0){
442
fwrite (decrypted_buffer, 1, decrypted_buffer_size, stdout);
443
free(decrypted_buffer);
452
fprintf(stderr, "Closing tls session\n");
456
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
459
gnutls_deinit (es.session);
460
gnutls_certificate_free_credentials (es.cred);
461
gnutls_global_deinit ();
910
static void resolve_callback(AvahiSServiceResolver *r,
911
AvahiIfIndex interface,
913
AvahiResolverEvent event,
917
const char *host_name,
918
const AvahiAddress *address,
920
AVAHI_GCC_UNUSED AvahiStringList *txt,
921
AVAHI_GCC_UNUSED AvahiLookupResultFlags
923
AVAHI_GCC_UNUSED void* userdata){
926
/* Called whenever a service has been resolved successfully or
935
case AVAHI_RESOLVER_FAILURE:
936
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
937
" of type '%s' in domain '%s': %s\n", name, type, domain,
938
avahi_strerror(avahi_server_errno(mc.server)));
941
case AVAHI_RESOLVER_FOUND:
943
char ip[AVAHI_ADDRESS_STR_MAX];
944
avahi_address_snprint(ip, sizeof(ip), address);
946
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
947
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
948
ip, (intmax_t)interface, port);
950
int ret = start_mandos_communication(ip, port, interface,
951
avahi_proto_to_af(proto));
953
avahi_simple_poll_quit(mc.simple_poll);
957
avahi_s_service_resolver_free(r);
960
static void browse_callback(AvahiSServiceBrowser *b,
961
AvahiIfIndex interface,
962
AvahiProtocol protocol,
963
AvahiBrowserEvent event,
967
AVAHI_GCC_UNUSED AvahiLookupResultFlags
969
AVAHI_GCC_UNUSED void* userdata){
972
/* Called whenever a new services becomes available on the LAN or
973
is removed from the LAN */
981
case AVAHI_BROWSER_FAILURE:
983
fprintf(stderr, "(Avahi browser) %s\n",
984
avahi_strerror(avahi_server_errno(mc.server)));
985
avahi_simple_poll_quit(mc.simple_poll);
988
case AVAHI_BROWSER_NEW:
989
/* We ignore the returned Avahi resolver object. In the callback
990
function we free it. If the Avahi server is terminated before
991
the callback function is called the Avahi server will free the
994
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
995
name, type, domain, protocol, 0,
996
resolve_callback, NULL) == NULL)
997
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
998
name, avahi_strerror(avahi_server_errno(mc.server)));
1001
case AVAHI_BROWSER_REMOVE:
1004
case AVAHI_BROWSER_ALL_FOR_NOW:
1005
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1007
fprintf(stderr, "No Mandos server found, still searching...\n");
1013
/* stop main loop after sigterm has been called */
1014
static void handle_sigterm(int sig){
1019
signal_received = sig;
1020
int old_errno = errno;
1021
if(mc.simple_poll != NULL){
1022
avahi_simple_poll_quit(mc.simple_poll);
1028
* This function determines if a directory entry in /sys/class/net
1029
* corresponds to an acceptable network device.
1030
* (This function is passed to scandir(3) as a filter function.)
1032
int good_interface(const struct dirent *if_entry){
1034
char *flagname = NULL;
1035
if(if_entry->d_name[0] == '.'){
1038
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
1044
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1051
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1052
/* read line from flags_fd */
1053
ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
1054
char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1055
flagstring[(size_t)to_read] = '\0';
1056
if(flagstring == NULL){
1062
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1079
tmpmax = strtoimax(flagstring, &tmp, 0);
1080
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1081
and not (isspace(*tmp)))
1082
or tmpmax != (ifreq_flags)tmpmax){
1084
fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1085
flagstring, if_entry->d_name);
1091
ifreq_flags flags = (ifreq_flags)tmpmax;
1092
/* Reject the loopback device */
1093
if(flags & IFF_LOOPBACK){
1095
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1100
/* Accept point-to-point devices only if connect_to is specified */
1101
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1103
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1108
/* Otherwise, reject non-broadcast-capable devices */
1109
if(not (flags & IFF_BROADCAST)){
1111
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1116
/* Accept this device */
1118
fprintf(stderr, "Interface \"%s\" is acceptable\n",
1124
int main(int argc, char *argv[]){
1125
AvahiSServiceBrowser *sb = NULL;
1130
int exitcode = EXIT_SUCCESS;
1131
const char *interface = "";
1132
struct ifreq network;
1134
bool take_down_interface = false;
1137
char tempdir[] = "/tmp/mandosXXXXXX";
1138
bool tempdir_created = false;
1139
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1140
const char *seckey = PATHDIR "/" SECKEY;
1141
const char *pubkey = PATHDIR "/" PUBKEY;
1143
bool gnutls_initialized = false;
1144
bool gpgme_initialized = false;
1147
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1148
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1153
/* Lower any group privileges we might have, just to be safe */
1160
/* Lower user privileges (temporarily) */
1172
struct argp_option options[] = {
1173
{ .name = "debug", .key = 128,
1174
.doc = "Debug mode", .group = 3 },
1175
{ .name = "connect", .key = 'c',
1176
.arg = "ADDRESS:PORT",
1177
.doc = "Connect directly to a specific Mandos server",
1179
{ .name = "interface", .key = 'i',
1181
.doc = "Network interface that will be used to search for"
1184
{ .name = "seckey", .key = 's',
1186
.doc = "OpenPGP secret key file base name",
1188
{ .name = "pubkey", .key = 'p',
1190
.doc = "OpenPGP public key file base name",
1192
{ .name = "dh-bits", .key = 129,
1194
.doc = "Bit length of the prime number used in the"
1195
" Diffie-Hellman key exchange",
1197
{ .name = "priority", .key = 130,
1199
.doc = "GnuTLS priority string for the TLS handshake",
1201
{ .name = "delay", .key = 131,
1203
.doc = "Maximum delay to wait for interface startup",
1206
* These reproduce what we would get without ARGP_NO_HELP
1208
{ .name = "help", .key = '?',
1209
.doc = "Give this help list", .group = -1 },
1210
{ .name = "usage", .key = -3,
1211
.doc = "Give a short usage message", .group = -1 },
1212
{ .name = "version", .key = 'V',
1213
.doc = "Print program version", .group = -1 },
1217
error_t parse_opt(int key, char *arg,
1218
struct argp_state *state){
1221
case 128: /* --debug */
1224
case 'c': /* --connect */
1227
case 'i': /* --interface */
1230
case 's': /* --seckey */
1233
case 'p': /* --pubkey */
1236
case 129: /* --dh-bits */
1238
tmpmax = strtoimax(arg, &tmp, 10);
1239
if(errno != 0 or tmp == arg or *tmp != '\0'
1240
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1241
argp_error(state, "Bad number of DH bits");
1243
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1245
case 130: /* --priority */
1248
case 131: /* --delay */
1250
delay = strtof(arg, &tmp);
1251
if(errno != 0 or tmp == arg or *tmp != '\0'){
1252
argp_error(state, "Bad delay");
1256
* These reproduce what we would get without ARGP_NO_HELP
1258
case '?': /* --help */
1259
argp_state_help(state, state->out_stream,
1260
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1261
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1262
case -3: /* --usage */
1263
argp_state_help(state, state->out_stream,
1264
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1265
case 'V': /* --version */
1266
fprintf(state->out_stream, "%s\n", argp_program_version);
1267
exit(argp_err_exit_status);
1270
return ARGP_ERR_UNKNOWN;
1275
struct argp argp = { .options = options, .parser = parse_opt,
1277
.doc = "Mandos client -- Get and decrypt"
1278
" passwords from a Mandos server" };
1279
ret = argp_parse(&argp, argc, argv,
1280
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
1287
perror("argp_parse");
1288
exitcode = EX_OSERR;
1291
exitcode = EX_USAGE;
1297
avahi_set_log_function(empty_log);
1300
if(interface[0] == '\0'){
1301
struct dirent **direntries;
1302
ret = scandir(sys_class_net, &direntries, good_interface,
1305
/* Pick the first good interface */
1306
interface = strdup(direntries[0]->d_name);
1308
fprintf(stderr, "Using interface \"%s\"\n", interface);
1310
if(interface == NULL){
1313
exitcode = EXIT_FAILURE;
1319
fprintf(stderr, "Could not find a network interface\n");
1320
exitcode = EXIT_FAILURE;
1325
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1326
from the signal handler */
1327
/* Initialize the pseudo-RNG for Avahi */
1328
srand((unsigned int) time(NULL));
1329
mc.simple_poll = avahi_simple_poll_new();
1330
if(mc.simple_poll == NULL){
1331
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1332
exitcode = EX_UNAVAILABLE;
1336
sigemptyset(&sigterm_action.sa_mask);
1337
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1339
perror("sigaddset");
1340
exitcode = EX_OSERR;
1343
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1345
perror("sigaddset");
1346
exitcode = EX_OSERR;
1349
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1351
perror("sigaddset");
1352
exitcode = EX_OSERR;
1355
/* Need to check if the handler is SIG_IGN before handling:
1356
| [[info:libc:Initial Signal Actions]] |
1357
| [[info:libc:Basic Signal Handling]] |
1359
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1361
perror("sigaction");
1364
if(old_sigterm_action.sa_handler != SIG_IGN){
1365
ret = sigaction(SIGINT, &sigterm_action, NULL);
1367
perror("sigaction");
1368
exitcode = EX_OSERR;
1372
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1374
perror("sigaction");
1377
if(old_sigterm_action.sa_handler != SIG_IGN){
1378
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1380
perror("sigaction");
1381
exitcode = EX_OSERR;
1385
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1387
perror("sigaction");
1390
if(old_sigterm_action.sa_handler != SIG_IGN){
1391
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1393
perror("sigaction");
1394
exitcode = EX_OSERR;
1399
/* If the interface is down, bring it up */
1400
if(strcmp(interface, "none") != 0){
1401
if_index = (AvahiIfIndex) if_nametoindex(interface);
1403
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1404
exitcode = EX_UNAVAILABLE;
1412
/* Re-raise priviliges */
1420
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1421
messages about the network interface to mess up the prompt */
1422
ret = klogctl(8, NULL, 5);
1423
bool restore_loglevel = true;
1425
restore_loglevel = false;
1428
#endif /* __linux__ */
1430
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1433
exitcode = EX_OSERR;
1435
if(restore_loglevel){
1436
ret = klogctl(7, NULL, 0);
1441
#endif /* __linux__ */
1442
/* Lower privileges */
1450
strcpy(network.ifr_name, interface);
1451
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1453
perror("ioctl SIOCGIFFLAGS");
1455
if(restore_loglevel){
1456
ret = klogctl(7, NULL, 0);
1461
#endif /* __linux__ */
1462
exitcode = EX_OSERR;
1463
/* Lower privileges */
1471
if((network.ifr_flags & IFF_UP) == 0){
1472
network.ifr_flags |= IFF_UP;
1473
take_down_interface = true;
1474
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1476
take_down_interface = false;
1477
perror("ioctl SIOCSIFFLAGS +IFF_UP");
1478
exitcode = EX_OSERR;
1480
if(restore_loglevel){
1481
ret = klogctl(7, NULL, 0);
1486
#endif /* __linux__ */
1487
/* Lower privileges */
1496
/* sleep checking until interface is running */
1497
for(int i=0; i < delay * 4; i++){
1498
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1500
perror("ioctl SIOCGIFFLAGS");
1501
} else if(network.ifr_flags & IFF_RUNNING){
1504
struct timespec sleeptime = { .tv_nsec = 250000000 };
1505
ret = nanosleep(&sleeptime, NULL);
1506
if(ret == -1 and errno != EINTR){
1507
perror("nanosleep");
1510
if(not take_down_interface){
1511
/* We won't need the socket anymore */
1512
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1518
if(restore_loglevel){
1519
/* Restores kernel loglevel to default */
1520
ret = klogctl(7, NULL, 0);
1525
#endif /* __linux__ */
1526
/* Lower privileges */
1528
if(take_down_interface){
1529
/* Lower privileges */
1535
/* Lower privileges permanently */
1547
ret = init_gnutls_global(pubkey, seckey);
1549
fprintf(stderr, "init_gnutls_global failed\n");
1550
exitcode = EX_UNAVAILABLE;
1553
gnutls_initialized = true;
1560
tempdir_created = true;
1561
if(mkdtemp(tempdir) == NULL){
1562
tempdir_created = false;
1571
if(not init_gpgme(pubkey, seckey, tempdir)){
1572
fprintf(stderr, "init_gpgme failed\n");
1573
exitcode = EX_UNAVAILABLE;
1576
gpgme_initialized = true;
1583
if(connect_to != NULL){
1584
/* Connect directly, do not use Zeroconf */
1585
/* (Mainly meant for debugging) */
1586
char *address = strrchr(connect_to, ':');
1587
if(address == NULL){
1588
fprintf(stderr, "No colon in address\n");
1589
exitcode = EX_USAGE;
1599
tmpmax = strtoimax(address+1, &tmp, 10);
1600
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1601
or tmpmax != (uint16_t)tmpmax){
1602
fprintf(stderr, "Bad port number\n");
1603
exitcode = EX_USAGE;
1611
port = (uint16_t)tmpmax;
1613
address = connect_to;
1614
/* Colon in address indicates IPv6 */
1616
if(strchr(address, ':') != NULL){
1626
while(not quit_now){
1627
ret = start_mandos_communication(address, port, if_index, af);
1628
if(quit_now or ret == 0){
1635
exitcode = EXIT_SUCCESS;
465
static AvahiSimplePoll *simple_poll = NULL;
466
static AvahiServer *server = NULL;
468
static void resolve_callback(
469
AvahiSServiceResolver *r,
470
AVAHI_GCC_UNUSED AvahiIfIndex interface,
471
AVAHI_GCC_UNUSED AvahiProtocol protocol,
472
AvahiResolverEvent event,
476
const char *host_name,
477
const AvahiAddress *address,
479
AvahiStringList *txt,
480
AvahiLookupResultFlags flags,
481
AVAHI_GCC_UNUSED void* userdata) {
485
/* Called whenever a service has been resolved successfully or timed out */
488
case AVAHI_RESOLVER_FAILURE:
489
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)));
492
case AVAHI_RESOLVER_FOUND: {
493
char ip[AVAHI_ADDRESS_STR_MAX];
494
avahi_address_snprint(ip, sizeof(ip), address);
496
fprintf(stderr, "Mandos server found at %s on port %d\n", ip, port);
498
int ret = start_mandos_communcation(ip, port);
506
avahi_s_service_resolver_free(r);
509
static void browse_callback(
510
AvahiSServiceBrowser *b,
511
AvahiIfIndex interface,
512
AvahiProtocol protocol,
513
AvahiBrowserEvent event,
517
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
520
AvahiServer *s = userdata;
523
/* Called whenever a new services becomes available on the LAN or is removed from the LAN */
527
case AVAHI_BROWSER_FAILURE:
529
fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
530
avahi_simple_poll_quit(simple_poll);
533
case AVAHI_BROWSER_NEW:
534
/* We ignore the returned resolver object. In the callback
535
function we free it. If the server is terminated before
536
the callback function is called the server will free
537
the resolver for us. */
539
if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET6, 0, resolve_callback, s)))
540
fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
544
case AVAHI_BROWSER_REMOVE:
547
case AVAHI_BROWSER_ALL_FOR_NOW:
548
case AVAHI_BROWSER_CACHE_EXHAUSTED:
553
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
1646
554
AvahiServerConfig config;
1647
/* Do not publish any local Zeroconf records */
555
AvahiSServiceBrowser *sb = NULL;
556
const char db[] = "--debug";
559
int returncode = EXIT_SUCCESS;
560
char *basename = rindex(argv[0], '/');
561
if(basename == NULL){
567
char *program_name = malloc(strlen(basename) + sizeof(db));
569
if (program_name == NULL){
574
program_name[0] = '\0';
576
for (int i = 1; i < argc; i++){
577
if (not strncmp(argv[i], db, 5)){
578
strcat(strcat(strcat(program_name, db ), "="), basename);
579
if(not strcmp(argv[i], db) or not strcmp(argv[i], program_name)){
587
avahi_set_log_function(empty_log);
590
/* Initialize the psuedo-RNG */
593
/* Allocate main loop object */
594
if (!(simple_poll = avahi_simple_poll_new())) {
595
fprintf(stderr, "Failed to create simple poll object.\n");
600
/* Do not publish any local records */
1648
601
avahi_server_config_init(&config);
1649
602
config.publish_hinfo = 0;
1650
603
config.publish_addresses = 0;
1651
604
config.publish_workstation = 0;
1652
605
config.publish_domain = 0;
1654
607
/* Allocate a new server */
1655
mc.server = avahi_server_new(avahi_simple_poll_get
1656
(mc.simple_poll), &config, NULL,
1659
/* Free the Avahi configuration data */
608
server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
610
/* Free the configuration data */
1660
611
avahi_server_config_free(&config);
1663
/* Check if creating the Avahi server object succeeded */
1664
if(mc.server == NULL){
1665
fprintf(stderr, "Failed to create Avahi server: %s\n",
1666
avahi_strerror(error));
1667
exitcode = EX_UNAVAILABLE;
1675
/* Create the Avahi service browser */
1676
sb = avahi_s_service_browser_new(mc.server, if_index,
1677
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1678
NULL, 0, browse_callback, NULL);
1680
fprintf(stderr, "Failed to create service browser: %s\n",
1681
avahi_strerror(avahi_server_errno(mc.server)));
1682
exitcode = EX_UNAVAILABLE;
1690
/* Run the main loop */
1693
fprintf(stderr, "Starting Avahi loop search\n");
1696
avahi_simple_poll_loop(mc.simple_poll);
1701
fprintf(stderr, "%s exiting\n", argv[0]);
1704
/* Cleanup things */
1706
avahi_s_service_browser_free(sb);
1708
if(mc.server != NULL)
1709
avahi_server_free(mc.server);
1711
if(mc.simple_poll != NULL)
1712
avahi_simple_poll_free(mc.simple_poll);
1714
if(gnutls_initialized){
1715
gnutls_certificate_free_credentials(mc.cred);
1716
gnutls_global_deinit();
1717
gnutls_dh_params_deinit(mc.dh_params);
1720
if(gpgme_initialized){
1721
gpgme_release(mc.ctx);
1724
/* Take down the network interface */
1725
if(take_down_interface){
1726
/* Re-raise priviliges */
1733
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1735
perror("ioctl SIOCGIFFLAGS");
1736
} else if(network.ifr_flags & IFF_UP) {
1737
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1738
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1740
perror("ioctl SIOCSIFFLAGS -IFF_UP");
1743
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1747
/* Lower privileges permanently */
1756
/* Removes the temp directory used by GPGME */
1757
if(tempdir_created){
1759
struct dirent *direntry;
1760
d = opendir(tempdir);
1762
if(errno != ENOENT){
1767
direntry = readdir(d);
1768
if(direntry == NULL){
1771
/* Skip "." and ".." */
1772
if(direntry->d_name[0] == '.'
1773
and (direntry->d_name[1] == '\0'
1774
or (direntry->d_name[1] == '.'
1775
and direntry->d_name[2] == '\0'))){
1778
char *fullname = NULL;
1779
ret = asprintf(&fullname, "%s/%s", tempdir,
1785
ret = remove(fullname);
1787
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1794
ret = rmdir(tempdir);
1795
if(ret == -1 and errno != ENOENT){
1801
sigemptyset(&old_sigterm_action.sa_mask);
1802
old_sigterm_action.sa_handler = SIG_DFL;
1803
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
1804
&old_sigterm_action,
1807
perror("sigaction");
1810
ret = raise(signal_received);
1811
} while(ret != 0 and errno == EINTR);
1816
TEMP_FAILURE_RETRY(pause());
613
/* Check if creating the server object succeeded */
615
fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
616
returncode = EXIT_FAILURE;
620
/* Create the service browser */
621
if (!(sb = avahi_s_service_browser_new(server, if_nametoindex("eth0"), AVAHI_PROTO_INET6, "_mandos._tcp", NULL, 0, browse_callback, server))) {
622
fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
623
returncode = EXIT_FAILURE;
627
/* Run the main loop */
630
fprintf(stderr, "Starting avahi loop search\n");
633
avahi_simple_poll_loop(simple_poll);
638
fprintf(stderr, "%s exiting\n", argv[0]);
643
avahi_s_service_browser_free(sb);
646
avahi_server_free(server);
649
avahi_simple_poll_free(simple_poll);