45
98
#include <avahi-common/malloc.h>
46
99
#include <avahi-common/error.h>
49
#include <sys/types.h> /* socket(), inet_pton() */
50
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
51
struct in6_addr, inet_pton() */
52
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
53
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
55
#include <unistd.h> /* close() */
56
#include <netinet/in.h>
57
#include <stdbool.h> /* true */
58
#include <string.h> /* memset */
59
#include <arpa/inet.h> /* inet_pton() */
60
#include <iso646.h> /* not */
63
#include <errno.h> /* perror() */
102
#include <gnutls/gnutls.h> /* All GnuTLS types, constants and
105
init_gnutls_session(),
107
#include <gnutls/openpgp.h>
108
/* gnutls_certificate_set_openpgp_key_file(),
109
GNUTLS_OPENPGP_FMT_BASE64 */
112
#include <gpgme.h> /* All GPGME types, constants and
115
GPGME_PROTOCOL_OpenPGP,
69
118
#define BUFFER_SIZE 256
72
const char *certdir = "/conf/conf.d/cryptkeyreq/";
73
const char *certfile = "openpgp-client.txt";
74
const char *certkey = "openpgp-client-key.txt";
120
#define PATHDIR "/conf/conf.d/mandos"
121
#define SECKEY "seckey.txt"
122
#define PUBKEY "pubkey.txt"
76
124
bool debug = false;
125
static const char mandos_protocol_version[] = "1";
126
const char *argp_program_version = "mandos-client " VERSION;
127
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
129
/* Used for passing in values through the Avahi callback functions */
79
gnutls_session_t session;
131
AvahiSimplePoll *simple_poll;
80
133
gnutls_certificate_credentials_t cred;
134
unsigned int dh_bits;
81
135
gnutls_dh_params_t dh_params;
85
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
86
char **new_packet, const char *homedir){
87
gpgme_data_t dh_crypto, dh_plain;
136
const char *priority;
140
/* global context so signal handler can reach it*/
141
mandos_context mc = { .simple_poll = NULL, .server = NULL,
142
.dh_bits = 1024, .priority = "SECURE256"
143
":!CTYPE-X.509:+CTYPE-OPENPGP" };
146
* Make additional room in "buffer" for at least BUFFER_SIZE more
147
* bytes. "buffer_capacity" is how much is currently allocated,
148
* "buffer_length" is how much is already used.
150
size_t incbuffer(char **buffer, size_t buffer_length,
151
size_t buffer_capacity){
152
if(buffer_length + BUFFER_SIZE > buffer_capacity){
153
*buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
157
buffer_capacity += BUFFER_SIZE;
159
return buffer_capacity;
165
static bool init_gpgme(const char *seckey,
166
const char *pubkey, const char *tempdir){
91
ssize_t new_packet_capacity = 0;
92
ssize_t new_packet_length = 0;
93
169
gpgme_engine_info_t engine_info;
96
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
173
* Helper function to insert pub and seckey to the engine keyring.
175
bool import_key(const char *filename){
177
gpgme_data_t pgp_data;
179
fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
185
rc = gpgme_data_new_from_fd(&pgp_data, fd);
186
if(rc != GPG_ERR_NO_ERROR){
187
fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
188
gpgme_strsource(rc), gpgme_strerror(rc));
192
rc = gpgme_op_import(mc.ctx, pgp_data);
193
if(rc != GPG_ERR_NO_ERROR){
194
fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
195
gpgme_strsource(rc), gpgme_strerror(rc));
199
ret = (int)TEMP_FAILURE_RETRY(close(fd));
203
gpgme_data_release(pgp_data);
208
fprintf(stderr, "Initializing GPGME\n");
100
212
gpgme_check_version(NULL);
101
213
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
102
if (rc != GPG_ERR_NO_ERROR){
214
if(rc != GPG_ERR_NO_ERROR){
103
215
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
104
216
gpgme_strsource(rc), gpgme_strerror(rc));
108
/* Set GPGME home directory */
109
rc = gpgme_get_engine_info (&engine_info);
110
if (rc != GPG_ERR_NO_ERROR){
220
/* Set GPGME home directory for the OpenPGP engine only */
221
rc = gpgme_get_engine_info(&engine_info);
222
if(rc != GPG_ERR_NO_ERROR){
111
223
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
112
224
gpgme_strsource(rc), gpgme_strerror(rc));
115
227
while(engine_info != NULL){
116
228
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
117
229
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
118
engine_info->file_name, homedir);
230
engine_info->file_name, tempdir);
121
233
engine_info = engine_info->next;
123
235
if(engine_info == NULL){
124
fprintf(stderr, "Could not set home dir to %s\n", homedir);
128
/* Create new GPGME data buffer from packet buffer */
129
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
130
if (rc != GPG_ERR_NO_ERROR){
236
fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
240
/* Create new GPGME "context" */
241
rc = gpgme_new(&(mc.ctx));
242
if(rc != GPG_ERR_NO_ERROR){
243
fprintf(stderr, "bad gpgme_new: %s: %s\n",
244
gpgme_strsource(rc), gpgme_strerror(rc));
248
if(not import_key(pubkey) or not import_key(seckey)){
256
* Decrypt OpenPGP data.
257
* Returns -1 on error
259
static ssize_t pgp_packet_decrypt(const char *cryptotext,
262
gpgme_data_t dh_crypto, dh_plain;
265
size_t plaintext_capacity = 0;
266
ssize_t plaintext_length = 0;
269
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
272
/* Create new GPGME data buffer from memory cryptotext */
273
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
275
if(rc != GPG_ERR_NO_ERROR){
131
276
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
132
277
gpgme_strsource(rc), gpgme_strerror(rc));
136
281
/* Create new empty GPGME data buffer for the plaintext */
137
282
rc = gpgme_data_new(&dh_plain);
138
if (rc != GPG_ERR_NO_ERROR){
283
if(rc != GPG_ERR_NO_ERROR){
139
284
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
140
285
gpgme_strsource(rc), gpgme_strerror(rc));
144
/* Create new GPGME "context" */
145
rc = gpgme_new(&ctx);
146
if (rc != GPG_ERR_NO_ERROR){
147
fprintf(stderr, "bad gpgme_new: %s: %s\n",
148
gpgme_strsource(rc), gpgme_strerror(rc));
152
/* Decrypt data from the FILE pointer to the plaintext data
154
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
155
if (rc != GPG_ERR_NO_ERROR){
286
gpgme_data_release(dh_crypto);
290
/* Decrypt data from the cryptotext data buffer to the plaintext
292
rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
293
if(rc != GPG_ERR_NO_ERROR){
156
294
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
157
295
gpgme_strsource(rc), gpgme_strerror(rc));
296
plaintext_length = -1;
298
gpgme_decrypt_result_t result;
299
result = gpgme_op_decrypt_result(mc.ctx);
301
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
303
fprintf(stderr, "Unsupported algorithm: %s\n",
304
result->unsupported_algorithm);
305
fprintf(stderr, "Wrong key usage: %u\n",
306
result->wrong_key_usage);
307
if(result->file_name != NULL){
308
fprintf(stderr, "File name: %s\n", result->file_name);
310
gpgme_recipient_t recipient;
311
recipient = result->recipients;
313
while(recipient != NULL){
314
fprintf(stderr, "Public key algorithm: %s\n",
315
gpgme_pubkey_algo_name(recipient->pubkey_algo));
316
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
317
fprintf(stderr, "Secret key available: %s\n",
318
recipient->status == GPG_ERR_NO_SECKEY
320
recipient = recipient->next;
162
fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
166
gpgme_decrypt_result_t result;
167
result = gpgme_op_decrypt_result(ctx);
169
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
171
fprintf(stderr, "Unsupported algorithm: %s\n",
172
result->unsupported_algorithm);
173
fprintf(stderr, "Wrong key usage: %d\n",
174
result->wrong_key_usage);
175
if(result->file_name != NULL){
176
fprintf(stderr, "File name: %s\n", result->file_name);
178
gpgme_recipient_t recipient;
179
recipient = result->recipients;
181
while(recipient != NULL){
182
fprintf(stderr, "Public key algorithm: %s\n",
183
gpgme_pubkey_algo_name(recipient->pubkey_algo));
184
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
185
fprintf(stderr, "Secret key available: %s\n",
186
recipient->status == GPG_ERR_NO_SECKEY
188
recipient = recipient->next;
194
/* Delete the GPGME FILE pointer cryptotext data buffer */
195
gpgme_data_release(dh_crypto);
329
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
197
332
/* Seek back to the beginning of the GPGME plaintext data buffer */
198
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
199
perror("pgpme_data_seek");
333
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
334
perror("gpgme_data_seek");
335
plaintext_length = -1;
204
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
205
*new_packet = realloc(*new_packet,
206
(unsigned int)new_packet_capacity
208
if (*new_packet == NULL){
212
new_packet_capacity += BUFFER_SIZE;
341
plaintext_capacity = incbuffer(plaintext,
342
(size_t)plaintext_length,
344
if(plaintext_capacity == 0){
346
plaintext_length = -1;
215
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
350
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
217
352
/* Print the data, if any */
222
358
perror("gpgme_data_read");
225
new_packet_length += ret;
228
/* FIXME: check characters before printing to screen so to not print
229
terminal control characters */
231
/* fprintf(stderr, "decrypted password is: "); */
232
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
233
/* fprintf(stderr, "\n"); */
359
plaintext_length = -1;
362
plaintext_length += ret;
366
fprintf(stderr, "Decrypted password is: ");
367
for(ssize_t i = 0; i < plaintext_length; i++){
368
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
370
fprintf(stderr, "\n");
375
/* Delete the GPGME cryptotext data buffer */
376
gpgme_data_release(dh_crypto);
236
378
/* Delete the GPGME plaintext data buffer */
237
379
gpgme_data_release(dh_plain);
238
return new_packet_length;
380
return plaintext_length;
241
static const char * safer_gnutls_strerror (int value) {
242
const char *ret = gnutls_strerror (value);
383
static const char * safer_gnutls_strerror(int value){
384
const char *ret = gnutls_strerror(value); /* Spurious warning from
385
-Wunreachable-code */
244
387
ret = "(unknown)";
248
void debuggnutls(__attribute__((unused)) int level,
250
fprintf(stderr, "%s", string);
391
/* GnuTLS log function callback */
392
static void debuggnutls(__attribute__((unused)) int level,
394
fprintf(stderr, "GnuTLS: %s", string);
253
int initgnutls(encrypted_session *es){
397
static int init_gnutls_global(const char *pubkeyfilename,
398
const char *seckeyfilename){
258
402
fprintf(stderr, "Initializing GnuTLS\n");
261
if ((ret = gnutls_global_init ())
262
!= GNUTLS_E_SUCCESS) {
263
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
405
ret = gnutls_global_init();
406
if(ret != GNUTLS_E_SUCCESS){
407
fprintf(stderr, "GnuTLS global_init: %s\n",
408
safer_gnutls_strerror(ret));
413
/* "Use a log level over 10 to enable all debugging options."
268
416
gnutls_global_set_log_level(11);
269
417
gnutls_global_set_log_function(debuggnutls);
272
/* openpgp credentials */
273
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
274
!= GNUTLS_E_SUCCESS) {
275
fprintf (stderr, "memory error: %s\n",
276
safer_gnutls_strerror(ret));
420
/* OpenPGP credentials */
421
gnutls_certificate_allocate_credentials(&mc.cred);
422
if(ret != GNUTLS_E_SUCCESS){
423
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
427
safer_gnutls_strerror(ret));
428
gnutls_global_deinit();
281
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
282
" and keyfile %s as GnuTLS credentials\n", certfile,
433
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
434
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
286
438
ret = gnutls_certificate_set_openpgp_key_file
287
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
288
if (ret != GNUTLS_E_SUCCESS) {
290
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
292
ret, certfile, certkey);
293
fprintf(stdout, "The Error is: %s\n",
294
safer_gnutls_strerror(ret));
298
//GnuTLS server initialization
299
if ((ret = gnutls_dh_params_init (&es->dh_params))
300
!= GNUTLS_E_SUCCESS) {
301
fprintf (stderr, "Error in dh parameter initialization: %s\n",
302
safer_gnutls_strerror(ret));
306
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
307
!= GNUTLS_E_SUCCESS) {
308
fprintf (stderr, "Error in prime generation: %s\n",
309
safer_gnutls_strerror(ret));
313
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
315
// GnuTLS session creation
316
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
317
!= GNUTLS_E_SUCCESS){
439
(mc.cred, pubkeyfilename, seckeyfilename,
440
GNUTLS_OPENPGP_FMT_BASE64);
441
if(ret != GNUTLS_E_SUCCESS){
443
"Error[%d] while reading the OpenPGP key pair ('%s',"
444
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
445
fprintf(stderr, "The GnuTLS error is: %s\n",
446
safer_gnutls_strerror(ret));
450
/* GnuTLS server initialization */
451
ret = gnutls_dh_params_init(&mc.dh_params);
452
if(ret != GNUTLS_E_SUCCESS){
453
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
454
" %s\n", safer_gnutls_strerror(ret));
457
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
458
if(ret != GNUTLS_E_SUCCESS){
459
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
460
safer_gnutls_strerror(ret));
464
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
470
gnutls_certificate_free_credentials(mc.cred);
471
gnutls_global_deinit();
472
gnutls_dh_params_deinit(mc.dh_params);
476
static int init_gnutls_session(gnutls_session_t *session){
478
/* GnuTLS session creation */
479
ret = gnutls_init(session, GNUTLS_SERVER);
480
if(ret != GNUTLS_E_SUCCESS){
318
481
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
319
482
safer_gnutls_strerror(ret));
322
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
323
!= GNUTLS_E_SUCCESS) {
324
fprintf(stderr, "Syntax error at: %s\n", err);
325
fprintf(stderr, "GnuTLS error: %s\n",
326
safer_gnutls_strerror(ret));
487
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
488
if(ret != GNUTLS_E_SUCCESS){
489
fprintf(stderr, "Syntax error at: %s\n", err);
490
fprintf(stderr, "GnuTLS error: %s\n",
491
safer_gnutls_strerror(ret));
492
gnutls_deinit(*session);
330
if ((ret = gnutls_credentials_set
331
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
332
!= GNUTLS_E_SUCCESS) {
333
fprintf(stderr, "Error setting a credentials set: %s\n",
497
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
499
if(ret != GNUTLS_E_SUCCESS){
500
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
334
501
safer_gnutls_strerror(ret));
502
gnutls_deinit(*session);
338
506
/* ignore client certificate if any. */
339
gnutls_certificate_server_set_request (es->session,
507
gnutls_certificate_server_set_request(*session,
342
gnutls_dh_set_prime_bits (es->session, DH_BITS);
510
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
347
void empty_log(__attribute__((unused)) AvahiLogLevel level,
348
__attribute__((unused)) const char *txt){}
515
/* Avahi log function callback */
516
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
517
__attribute__((unused)) const char *txt){}
350
int start_mandos_communication(const char *ip, uint16_t port,
351
AvahiIfIndex if_index){
519
/* Called when a Mandos server is found */
520
static int start_mandos_communication(const char *ip, uint16_t port,
521
AvahiIfIndex if_index,
353
struct sockaddr_in6 to;
354
encrypted_session es;
526
struct sockaddr_in in;
527
struct sockaddr_in6 in6;
355
529
char *buffer = NULL;
356
530
char *decrypted_buffer;
357
531
size_t buffer_length = 0;
358
532
size_t buffer_capacity = 0;
359
533
ssize_t decrypted_buffer_size;
362
char interface[IF_NAMESIZE];
536
gnutls_session_t session;
537
int pf; /* Protocol family */
547
fprintf(stderr, "Bad address family: %d\n", af);
551
ret = init_gnutls_session(&session);
365
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
557
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
369
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
561
tcp_sd = socket(pf, SOCK_STREAM, 0);
371
563
perror("socket");
375
if(if_indextoname((unsigned int)if_index, interface) == NULL){
377
perror("if_indextoname");
383
fprintf(stderr, "Binding to interface %s\n", interface);
386
memset(&to,0,sizeof(to)); /* Spurious warning */
387
to.sin6_family = AF_INET6;
388
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
567
memset(&to, 0, sizeof(to));
569
to.in6.sin6_family = (sa_family_t)af;
570
ret = inet_pton(af, ip, &to.in6.sin6_addr);
572
to.in.sin_family = (sa_family_t)af;
573
ret = inet_pton(af, ip, &to.in.sin_addr);
390
576
perror("inet_pton");
394
580
fprintf(stderr, "Bad address: %s\n", ip);
397
to.sin6_port = htons(port); /* Spurious warning */
399
to.sin6_scope_id = (uint32_t)if_index;
584
to.in6.sin6_port = htons(port); /* Spurious warnings from
586
-Wunreachable-code */
588
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
589
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
591
if(if_index == AVAHI_IF_UNSPEC){
592
fprintf(stderr, "An IPv6 link-local address is incomplete"
593
" without a network interface\n");
596
/* Set the network interface number as scope */
597
to.in6.sin6_scope_id = (uint32_t)if_index;
600
to.in.sin_port = htons(port); /* Spurious warnings from
602
-Wunreachable-code */
402
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
403
/* char addrstr[INET6_ADDRSTRLEN]; */
404
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
405
/* sizeof(addrstr)) == NULL){ */
406
/* perror("inet_ntop"); */
408
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
409
/* addrstr, ntohs(to.sin6_port)); */
606
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
607
char interface[IF_NAMESIZE];
608
if(if_indextoname((unsigned int)if_index, interface) == NULL){
609
perror("if_indextoname");
611
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
612
ip, interface, port);
615
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
618
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
619
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
622
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
625
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
631
if(strcmp(addrstr, ip) != 0){
632
fprintf(stderr, "Canonical address form: %s\n", addrstr);
413
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
638
ret = connect(tcp_sd, &to.in6, sizeof(to));
640
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
415
643
perror("connect");
419
ret = initgnutls (&es);
647
const char *out = mandos_protocol_version;
650
size_t out_size = strlen(out);
651
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
652
out_size - written));
658
written += (size_t)ret;
659
if(written < out_size){
662
if(out == mandos_protocol_version){
425
gnutls_transport_set_ptr (es.session,
426
(gnutls_transport_ptr_t) tcp_sd);
429
672
fprintf(stderr, "Establishing TLS session with %s\n", ip);
432
ret = gnutls_handshake (es.session);
434
if (ret != GNUTLS_E_SUCCESS){
675
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
678
ret = gnutls_handshake(session);
679
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
681
if(ret != GNUTLS_E_SUCCESS){
436
fprintf(stderr, "\n*** Handshake failed ***\n");
683
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
443
//Retrieve OpenPGP packet that contains the wanted password
690
/* Read OpenPGP packet that contains the wanted password */
446
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
693
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
451
if (buffer_length + BUFFER_SIZE > buffer_capacity){
452
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
457
buffer_capacity += BUFFER_SIZE;
698
buffer_capacity = incbuffer(&buffer, buffer_length,
700
if(buffer_capacity == 0){
460
ret = gnutls_record_recv
461
(es.session, buffer+buffer_length, BUFFER_SIZE);
706
sret = gnutls_record_recv(session, buffer+buffer_length,
467
713
case GNUTLS_E_INTERRUPTED:
468
714
case GNUTLS_E_AGAIN:
470
716
case GNUTLS_E_REHANDSHAKE:
471
ret = gnutls_handshake (es.session);
473
fprintf(stderr, "\n*** Handshake failed ***\n");
718
ret = gnutls_handshake(session);
719
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
721
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
480
728
fprintf(stderr, "Unknown error while reading data from"
481
" encrypted session with mandos server\n");
729
" encrypted session with Mandos server\n");
483
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
731
gnutls_bye(session, GNUTLS_SHUT_RDWR);
487
buffer_length += (size_t) ret;
735
buffer_length += (size_t) sret;
491
if (buffer_length > 0){
740
fprintf(stderr, "Closing TLS session\n");
743
gnutls_bye(session, GNUTLS_SHUT_RDWR);
745
if(buffer_length > 0){
492
746
decrypted_buffer_size = pgp_packet_decrypt(buffer,
496
if (decrypted_buffer_size >= 0){
749
if(decrypted_buffer_size >= 0){
497
751
while(written < (size_t) decrypted_buffer_size){
498
ret = (int)fwrite (decrypted_buffer + written, 1,
499
(size_t)decrypted_buffer_size - written,
752
ret = (int)fwrite(decrypted_buffer + written, 1,
753
(size_t)decrypted_buffer_size - written,
501
755
if(ret == 0 and ferror(stdout)){
503
757
fprintf(stderr, "Error writing encrypted data: %s\n",
566
814
char ip[AVAHI_ADDRESS_STR_MAX];
567
815
avahi_address_snprint(ip, sizeof(ip), address);
569
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
570
" port %d\n", name, host_name, ip, port);
817
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
818
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
819
ip, (intmax_t)interface, port);
572
int ret = start_mandos_communication(ip, port, interface);
821
int ret = start_mandos_communication(ip, port, interface,
822
avahi_proto_to_af(proto));
824
avahi_simple_poll_quit(mc.simple_poll);
578
828
avahi_s_service_resolver_free(r);
581
static void browse_callback(
582
AvahiSServiceBrowser *b,
583
AvahiIfIndex interface,
584
AvahiProtocol protocol,
585
AvahiBrowserEvent event,
589
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
592
AvahiServer *s = userdata;
593
assert(b); /* Spurious warning */
595
/* Called whenever a new services becomes available on the LAN or
596
is removed from the LAN */
600
case AVAHI_BROWSER_FAILURE:
602
fprintf(stderr, "(Browser) %s\n",
603
avahi_strerror(avahi_server_errno(server)));
604
avahi_simple_poll_quit(simple_poll);
607
case AVAHI_BROWSER_NEW:
608
/* We ignore the returned resolver object. In the callback
609
function we free it. If the server is terminated before
610
the callback function is called the server will free
611
the resolver for us. */
613
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
615
AVAHI_PROTO_INET6, 0,
616
resolve_callback, s)))
617
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
618
avahi_strerror(avahi_server_errno(s)));
621
case AVAHI_BROWSER_REMOVE:
624
case AVAHI_BROWSER_ALL_FOR_NOW:
625
case AVAHI_BROWSER_CACHE_EXHAUSTED:
831
static void browse_callback(AvahiSServiceBrowser *b,
832
AvahiIfIndex interface,
833
AvahiProtocol protocol,
834
AvahiBrowserEvent event,
838
AVAHI_GCC_UNUSED AvahiLookupResultFlags
840
AVAHI_GCC_UNUSED void* userdata){
843
/* Called whenever a new services becomes available on the LAN or
844
is removed from the LAN */
848
case AVAHI_BROWSER_FAILURE:
850
fprintf(stderr, "(Avahi browser) %s\n",
851
avahi_strerror(avahi_server_errno(mc.server)));
852
avahi_simple_poll_quit(mc.simple_poll);
855
case AVAHI_BROWSER_NEW:
856
/* We ignore the returned Avahi resolver object. In the callback
857
function we free it. If the Avahi server is terminated before
858
the callback function is called the Avahi server will free the
861
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
862
name, type, domain, protocol, 0,
863
resolve_callback, NULL) == NULL)
864
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
865
name, avahi_strerror(avahi_server_errno(mc.server)));
868
case AVAHI_BROWSER_REMOVE:
871
case AVAHI_BROWSER_ALL_FOR_NOW:
872
case AVAHI_BROWSER_CACHE_EXHAUSTED:
874
fprintf(stderr, "No Mandos server found, still searching...\n");
630
/* combinds file name and path and returns the malloced new string. som sane checks could/should be added */
631
const char *combinepath(const char *first, const char *second){
880
sig_atomic_t quit_now = 0;
882
/* stop main loop after sigterm has been called */
883
static void handle_sigterm(__attribute__((unused)) int sig){
888
int old_errno = errno;
889
if(mc.simple_poll != NULL){
890
avahi_simple_poll_quit(mc.simple_poll);
895
int main(int argc, char *argv[]){
896
AvahiSServiceBrowser *sb = NULL;
633
tmp = malloc(strlen(first) + strlen(second) + 2);
639
if (first[0] != '\0' and first[strlen(first) - 1] != '/'){
647
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
901
int exitcode = EXIT_SUCCESS;
902
const char *interface = "eth0";
903
struct ifreq network;
907
char *connect_to = NULL;
908
char tempdir[] = "/tmp/mandosXXXXXX";
909
bool tempdir_created = false;
910
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
911
const char *seckey = PATHDIR "/" SECKEY;
912
const char *pubkey = PATHDIR "/" PUBKEY;
914
bool gnutls_initialized = false;
915
bool gpgme_initialized = false;
918
struct sigaction old_sigterm_action;
919
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
922
struct argp_option options[] = {
923
{ .name = "debug", .key = 128,
924
.doc = "Debug mode", .group = 3 },
925
{ .name = "connect", .key = 'c',
926
.arg = "ADDRESS:PORT",
927
.doc = "Connect directly to a specific Mandos server",
929
{ .name = "interface", .key = 'i',
931
.doc = "Network interface that will be used to search for"
934
{ .name = "seckey", .key = 's',
936
.doc = "OpenPGP secret key file base name",
938
{ .name = "pubkey", .key = 'p',
940
.doc = "OpenPGP public key file base name",
942
{ .name = "dh-bits", .key = 129,
944
.doc = "Bit length of the prime number used in the"
945
" Diffie-Hellman key exchange",
947
{ .name = "priority", .key = 130,
949
.doc = "GnuTLS priority string for the TLS handshake",
951
{ .name = "delay", .key = 131,
953
.doc = "Maximum delay to wait for interface startup",
958
error_t parse_opt(int key, char *arg,
959
struct argp_state *state){
961
case 128: /* --debug */
964
case 'c': /* --connect */
967
case 'i': /* --interface */
970
case 's': /* --seckey */
973
case 'p': /* --pubkey */
976
case 129: /* --dh-bits */
978
tmpmax = strtoimax(arg, &tmp, 10);
979
if(errno != 0 or tmp == arg or *tmp != '\0'
980
or tmpmax != (typeof(mc.dh_bits))tmpmax){
981
fprintf(stderr, "Bad number of DH bits\n");
984
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
986
case 130: /* --priority */
989
case 131: /* --delay */
991
delay = strtof(arg, &tmp);
992
if(errno != 0 or tmp == arg or *tmp != '\0'){
993
fprintf(stderr, "Bad delay\n");
1002
return ARGP_ERR_UNKNOWN;
1007
struct argp argp = { .options = options, .parser = parse_opt,
1009
.doc = "Mandos client -- Get and decrypt"
1010
" passwords from a Mandos server" };
1011
ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
1012
if(ret == ARGP_ERR_UNKNOWN){
1013
fprintf(stderr, "Unknown error while parsing arguments\n");
1014
exitcode = EXIT_FAILURE;
1020
avahi_set_log_function(empty_log);
1023
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1024
from the signal handler */
1025
/* Initialize the pseudo-RNG for Avahi */
1026
srand((unsigned int) time(NULL));
1027
mc.simple_poll = avahi_simple_poll_new();
1028
if(mc.simple_poll == NULL){
1029
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1030
exitcode = EXIT_FAILURE;
1034
sigemptyset(&sigterm_action.sa_mask);
1035
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1037
perror("sigaddset");
1038
exitcode = EXIT_FAILURE;
1041
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1043
perror("sigaddset");
1044
exitcode = EXIT_FAILURE;
1047
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1049
perror("sigaddset");
1050
exitcode = EXIT_FAILURE;
1053
ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
1055
perror("sigaction");
1056
exitcode = EXIT_FAILURE;
1060
/* If the interface is down, bring it up */
1061
if(interface[0] != '\0'){
1063
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1064
messages to mess up the prompt */
1065
ret = klogctl(8, NULL, 5);
1066
bool restore_loglevel = true;
1068
restore_loglevel = false;
1071
#endif /* __linux__ */
1073
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1076
exitcode = EXIT_FAILURE;
1078
if(restore_loglevel){
1079
ret = klogctl(7, NULL, 0);
1084
#endif /* __linux__ */
1087
strcpy(network.ifr_name, interface);
1088
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1090
perror("ioctl SIOCGIFFLAGS");
1092
if(restore_loglevel){
1093
ret = klogctl(7, NULL, 0);
1098
#endif /* __linux__ */
1099
exitcode = EXIT_FAILURE;
1102
if((network.ifr_flags & IFF_UP) == 0){
1103
network.ifr_flags |= IFF_UP;
1104
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1106
perror("ioctl SIOCSIFFLAGS");
1107
exitcode = EXIT_FAILURE;
1109
if(restore_loglevel){
1110
ret = klogctl(7, NULL, 0);
1115
#endif /* __linux__ */
1119
/* sleep checking until interface is running */
1120
for(int i=0; i < delay * 4; i++){
1121
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1123
perror("ioctl SIOCGIFFLAGS");
1124
} else if(network.ifr_flags & IFF_RUNNING){
1127
struct timespec sleeptime = { .tv_nsec = 250000000 };
1128
ret = nanosleep(&sleeptime, NULL);
1129
if(ret == -1 and errno != EINTR){
1130
perror("nanosleep");
1133
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1138
if(restore_loglevel){
1139
/* Restores kernel loglevel to default */
1140
ret = klogctl(7, NULL, 0);
1145
#endif /* __linux__ */
1162
ret = init_gnutls_global(pubkey, seckey);
1164
fprintf(stderr, "init_gnutls_global failed\n");
1165
exitcode = EXIT_FAILURE;
1168
gnutls_initialized = true;
1171
if(mkdtemp(tempdir) == NULL){
1175
tempdir_created = true;
1177
if(not init_gpgme(pubkey, seckey, tempdir)){
1178
fprintf(stderr, "init_gpgme failed\n");
1179
exitcode = EXIT_FAILURE;
1182
gpgme_initialized = true;
1185
if(interface[0] != '\0'){
1186
if_index = (AvahiIfIndex) if_nametoindex(interface);
1188
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1189
exitcode = EXIT_FAILURE;
1194
if(connect_to != NULL){
1195
/* Connect directly, do not use Zeroconf */
1196
/* (Mainly meant for debugging) */
1197
char *address = strrchr(connect_to, ':');
1198
if(address == NULL){
1199
fprintf(stderr, "No colon in address\n");
1200
exitcode = EXIT_FAILURE;
1205
tmpmax = strtoimax(address+1, &tmp, 10);
1206
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1207
or tmpmax != (uint16_t)tmpmax){
1208
fprintf(stderr, "Bad port number\n");
1209
exitcode = EXIT_FAILURE;
1212
port = (uint16_t)tmpmax;
1214
address = connect_to;
1215
/* Colon in address indicates IPv6 */
1217
if(strchr(address, ':') != NULL){
1222
ret = start_mandos_communication(address, port, if_index, af);
1224
exitcode = EXIT_FAILURE;
1226
exitcode = EXIT_SUCCESS;
648
1232
AvahiServerConfig config;
649
AvahiSServiceBrowser *sb = NULL;
652
int returncode = EXIT_SUCCESS;
653
const char *interface = NULL;
654
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
655
char *connect_to = NULL;
658
static struct option long_options[] = {
659
{"debug", no_argument, (int *)&debug, 1},
660
{"connect", required_argument, 0, 'C'},
661
{"interface", required_argument, 0, 'i'},
662
{"certdir", required_argument, 0, 'd'},
663
{"certkey", required_argument, 0, 'c'},
664
{"certfile", required_argument, 0, 'k'},
667
int option_index = 0;
668
ret = getopt_long (argc, argv, "i:", long_options,
698
certfile = combinepath(certdir, certfile);
699
if (certfile == NULL){
703
if(interface != NULL){
704
if_index = (AvahiIfIndex) if_nametoindex(interface);
706
fprintf(stderr, "No such interface: \"%s\"\n", interface);
711
if(connect_to != NULL){
712
/* Connect directly, do not use Zeroconf */
713
/* (Mainly meant for debugging) */
714
char *address = strrchr(connect_to, ':');
716
fprintf(stderr, "No colon in address\n");
720
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
722
perror("Bad port number");
726
address = connect_to;
727
ret = start_mandos_communication(address, port, if_index);
735
certkey = combinepath(certdir, certkey);
736
if (certkey == NULL){
741
avahi_set_log_function(empty_log);
744
/* Initialize the psuedo-RNG */
745
srand((unsigned int) time(NULL));
747
/* Allocate main loop object */
748
if (!(simple_poll = avahi_simple_poll_new())) {
749
fprintf(stderr, "Failed to create simple poll object.\n");
754
/* Do not publish any local records */
1233
/* Do not publish any local Zeroconf records */
755
1234
avahi_server_config_init(&config);
756
1235
config.publish_hinfo = 0;
757
1236
config.publish_addresses = 0;
758
1237
config.publish_workstation = 0;
759
1238
config.publish_domain = 0;
761
1240
/* Allocate a new server */
762
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
763
&config, NULL, NULL, &error);
765
/* Free the configuration data */
1241
mc.server = avahi_server_new(avahi_simple_poll_get
1242
(mc.simple_poll), &config, NULL,
1245
/* Free the Avahi configuration data */
766
1246
avahi_server_config_free(&config);
768
/* Check if creating the server object succeeded */
770
fprintf(stderr, "Failed to create server: %s\n",
771
avahi_strerror(error));
772
returncode = EXIT_FAILURE;
776
/* Create the service browser */
777
sb = avahi_s_service_browser_new(server, if_index,
779
"_mandos._tcp", NULL, 0,
780
browse_callback, server);
782
fprintf(stderr, "Failed to create service browser: %s\n",
783
avahi_strerror(avahi_server_errno(server)));
784
returncode = EXIT_FAILURE;
788
/* Run the main loop */
791
fprintf(stderr, "Starting avahi loop search\n");
794
avahi_simple_poll_loop(simple_poll);
799
fprintf(stderr, "%s exiting\n", argv[0]);
804
avahi_s_service_browser_free(sb);
807
avahi_server_free(server);
810
avahi_simple_poll_free(simple_poll);
1249
/* Check if creating the Avahi server object succeeded */
1250
if(mc.server == NULL){
1251
fprintf(stderr, "Failed to create Avahi server: %s\n",
1252
avahi_strerror(error));
1253
exitcode = EXIT_FAILURE;
1257
/* Create the Avahi service browser */
1258
sb = avahi_s_service_browser_new(mc.server, if_index,
1259
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1260
NULL, 0, browse_callback, NULL);
1262
fprintf(stderr, "Failed to create service browser: %s\n",
1263
avahi_strerror(avahi_server_errno(mc.server)));
1264
exitcode = EXIT_FAILURE;
1268
/* Run the main loop */
1271
fprintf(stderr, "Starting Avahi loop search\n");
1274
avahi_simple_poll_loop(mc.simple_poll);
1279
fprintf(stderr, "%s exiting\n", argv[0]);
1282
/* Cleanup things */
1284
avahi_s_service_browser_free(sb);
1286
if(mc.server != NULL)
1287
avahi_server_free(mc.server);
1289
if(mc.simple_poll != NULL)
1290
avahi_simple_poll_free(mc.simple_poll);
1292
if(gnutls_initialized){
1293
gnutls_certificate_free_credentials(mc.cred);
1294
gnutls_global_deinit();
1295
gnutls_dh_params_deinit(mc.dh_params);
1298
if(gpgme_initialized){
1299
gpgme_release(mc.ctx);
1302
/* Removes the temp directory used by GPGME */
1303
if(tempdir_created){
1305
struct dirent *direntry;
1306
d = opendir(tempdir);
1308
if(errno != ENOENT){
1313
direntry = readdir(d);
1314
if(direntry == NULL){
1317
/* Skip "." and ".." */
1318
if(direntry->d_name[0] == '.'
1319
and (direntry->d_name[1] == '\0'
1320
or (direntry->d_name[1] == '.'
1321
and direntry->d_name[2] == '\0'))){
1324
char *fullname = NULL;
1325
ret = asprintf(&fullname, "%s/%s", tempdir,
1331
ret = remove(fullname);
1333
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1340
ret = rmdir(tempdir);
1341
if(ret == -1 and errno != ENOENT){