91
46
#include <avahi-common/malloc.h>
92
47
#include <avahi-common/error.h>
95
#include <gnutls/gnutls.h> /* All GnuTLS types, constants and
98
init_gnutls_session(),
100
#include <gnutls/openpgp.h>
101
/* gnutls_certificate_set_openpgp_key_file(),
102
GNUTLS_OPENPGP_FMT_BASE64 */
105
#include <gpgme.h> /* All GPGME types, constants and
108
GPGME_PROTOCOL_OpenPGP,
50
#include <sys/types.h> /* socket(), inet_pton() */
51
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
52
struct in6_addr, inet_pton() */
53
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
54
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
56
#include <unistd.h> /* close() */
57
#include <netinet/in.h>
58
#include <stdbool.h> /* true */
59
#include <string.h> /* memset */
60
#include <arpa/inet.h> /* inet_pton() */
61
#include <iso646.h> /* not */
64
#include <errno.h> /* perror() */
71
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
73
#define CERTFILE CERT_ROOT "openpgp-client.txt"
74
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
111
75
#define BUFFER_SIZE 256
113
#define PATHDIR "/conf/conf.d/mandos"
114
#define SECKEY "seckey.txt"
115
#define PUBKEY "pubkey.txt"
117
78
bool debug = false;
118
static const char mandos_protocol_version[] = "1";
119
const char *argp_program_version = "mandos-client " VERSION;
120
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
122
/* Used for passing in values through the Avahi callback functions */
124
AvahiSimplePoll *simple_poll;
81
gnutls_session_t session;
126
82
gnutls_certificate_credentials_t cred;
127
unsigned int dh_bits;
128
83
gnutls_dh_params_t dh_params;
129
const char *priority;
87
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
char **new_packet, const char *homedir){
89
gpgme_data_t dh_crypto, dh_plain;
133
/* global context so signal handler can reach it*/
134
mandos_context mc = { .simple_poll = NULL, .server = NULL,
135
.dh_bits = 1024, .priority = "SECURE256"
136
":!CTYPE-X.509:+CTYPE-OPENPGP" };
139
* Make additional room in "buffer" for at least BUFFER_SIZE
140
* additional bytes. "buffer_capacity" is how much is currently
141
* allocated, "buffer_length" is how much is already used.
143
size_t incbuffer(char **buffer, size_t buffer_length,
144
size_t buffer_capacity){
145
if(buffer_length + BUFFER_SIZE > buffer_capacity){
146
*buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
150
buffer_capacity += BUFFER_SIZE;
152
return buffer_capacity;
158
static bool init_gpgme(const char *seckey,
159
const char *pubkey, const char *tempdir){
93
ssize_t new_packet_capacity = 0;
94
ssize_t new_packet_length = 0;
162
95
gpgme_engine_info_t engine_info;
166
* Helper function to insert pub and seckey to the engine keyring.
168
bool import_key(const char *filename){
170
gpgme_data_t pgp_data;
172
fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
178
rc = gpgme_data_new_from_fd(&pgp_data, fd);
179
if(rc != GPG_ERR_NO_ERROR){
180
fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
181
gpgme_strsource(rc), gpgme_strerror(rc));
185
rc = gpgme_op_import(mc.ctx, pgp_data);
186
if(rc != GPG_ERR_NO_ERROR){
187
fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
188
gpgme_strsource(rc), gpgme_strerror(rc));
192
ret = (int)TEMP_FAILURE_RETRY(close(fd));
196
gpgme_data_release(pgp_data);
201
fprintf(stderr, "Initialize gpgme\n");
98
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
205
102
gpgme_check_version(NULL);
206
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
207
if(rc != GPG_ERR_NO_ERROR){
208
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
209
gpgme_strsource(rc), gpgme_strerror(rc));
103
gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
213
/* Set GPGME home directory for the OpenPGP engine only */
214
rc = gpgme_get_engine_info(&engine_info);
215
if(rc != GPG_ERR_NO_ERROR){
105
/* Set GPGME home directory */
106
rc = gpgme_get_engine_info (&engine_info);
107
if (rc != GPG_ERR_NO_ERROR){
216
108
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
217
109
gpgme_strsource(rc), gpgme_strerror(rc));
220
112
while(engine_info != NULL){
221
113
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
222
114
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
223
engine_info->file_name, tempdir);
115
engine_info->file_name, homedir);
226
118
engine_info = engine_info->next;
228
120
if(engine_info == NULL){
229
fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
233
/* Create new GPGME "context" */
234
rc = gpgme_new(&(mc.ctx));
235
if(rc != GPG_ERR_NO_ERROR){
236
fprintf(stderr, "bad gpgme_new: %s: %s\n",
237
gpgme_strsource(rc), gpgme_strerror(rc));
241
if(not import_key(pubkey) or not import_key(seckey)){
249
* Decrypt OpenPGP data.
250
* Returns -1 on error
252
static ssize_t pgp_packet_decrypt(const char *cryptotext,
255
gpgme_data_t dh_crypto, dh_plain;
258
size_t plaintext_capacity = 0;
259
ssize_t plaintext_length = 0;
262
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
265
/* Create new GPGME data buffer from memory cryptotext */
266
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
268
if(rc != GPG_ERR_NO_ERROR){
121
fprintf(stderr, "Could not set home dir to %s\n", homedir);
125
/* Create new GPGME data buffer from packet buffer */
126
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
127
if (rc != GPG_ERR_NO_ERROR){
269
128
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
270
129
gpgme_strsource(rc), gpgme_strerror(rc));
274
133
/* Create new empty GPGME data buffer for the plaintext */
275
134
rc = gpgme_data_new(&dh_plain);
276
if(rc != GPG_ERR_NO_ERROR){
135
if (rc != GPG_ERR_NO_ERROR){
277
136
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
278
137
gpgme_strsource(rc), gpgme_strerror(rc));
279
gpgme_data_release(dh_crypto);
283
/* Decrypt data from the cryptotext data buffer to the plaintext
285
rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
286
if(rc != GPG_ERR_NO_ERROR){
141
/* Create new GPGME "context" */
142
rc = gpgme_new(&ctx);
143
if (rc != GPG_ERR_NO_ERROR){
144
fprintf(stderr, "bad gpgme_new: %s: %s\n",
145
gpgme_strsource(rc), gpgme_strerror(rc));
149
/* Decrypt data from the FILE pointer to the plaintext data
151
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
152
if (rc != GPG_ERR_NO_ERROR){
287
153
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
288
154
gpgme_strsource(rc), gpgme_strerror(rc));
289
plaintext_length = -1;
291
gpgme_decrypt_result_t result;
292
result = gpgme_op_decrypt_result(mc.ctx);
294
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
296
fprintf(stderr, "Unsupported algorithm: %s\n",
297
result->unsupported_algorithm);
298
fprintf(stderr, "Wrong key usage: %u\n",
299
result->wrong_key_usage);
300
if(result->file_name != NULL){
301
fprintf(stderr, "File name: %s\n", result->file_name);
303
gpgme_recipient_t recipient;
304
recipient = result->recipients;
306
while(recipient != NULL){
307
fprintf(stderr, "Public key algorithm: %s\n",
308
gpgme_pubkey_algo_name(recipient->pubkey_algo));
309
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
310
fprintf(stderr, "Secret key available: %s\n",
311
recipient->status == GPG_ERR_NO_SECKEY
313
recipient = recipient->next;
159
fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
163
gpgme_decrypt_result_t result;
164
result = gpgme_op_decrypt_result(ctx);
166
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
168
fprintf(stderr, "Unsupported algorithm: %s\n",
169
result->unsupported_algorithm);
170
fprintf(stderr, "Wrong key usage: %d\n",
171
result->wrong_key_usage);
172
if(result->file_name != NULL){
173
fprintf(stderr, "File name: %s\n", result->file_name);
175
gpgme_recipient_t recipient;
176
recipient = result->recipients;
178
while(recipient != NULL){
179
fprintf(stderr, "Public key algorithm: %s\n",
180
gpgme_pubkey_algo_name(recipient->pubkey_algo));
181
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
182
fprintf(stderr, "Secret key available: %s\n",
183
recipient->status == GPG_ERR_NO_SECKEY
185
recipient = recipient->next;
322
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
191
/* Delete the GPGME FILE pointer cryptotext data buffer */
192
gpgme_data_release(dh_crypto);
325
194
/* Seek back to the beginning of the GPGME plaintext data buffer */
326
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
327
perror("gpgme_data_seek");
328
plaintext_length = -1;
195
gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
334
plaintext_capacity = incbuffer(plaintext,
335
(size_t)plaintext_length,
337
if(plaintext_capacity == 0){
339
plaintext_length = -1;
199
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
200
*new_packet = realloc(*new_packet,
201
(unsigned int)new_packet_capacity
203
if (*new_packet == NULL){
207
new_packet_capacity += BUFFER_SIZE;
343
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
210
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
345
212
/* Print the data, if any */
351
217
perror("gpgme_data_read");
352
plaintext_length = -1;
355
plaintext_length += ret;
359
fprintf(stderr, "Decrypted password is: ");
360
for(ssize_t i = 0; i < plaintext_length; i++){
361
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
363
fprintf(stderr, "\n");
368
/* Delete the GPGME cryptotext data buffer */
369
gpgme_data_release(dh_crypto);
220
new_packet_length += ret;
223
/* FIXME: check characters before printing to screen so to not print
224
terminal control characters */
226
/* fprintf(stderr, "decrypted password is: "); */
227
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
228
/* fprintf(stderr, "\n"); */
371
231
/* Delete the GPGME plaintext data buffer */
372
232
gpgme_data_release(dh_plain);
373
return plaintext_length;
233
return new_packet_length;
376
static const char * safer_gnutls_strerror(int value){
377
const char *ret = gnutls_strerror(value); /* Spurious warning from
378
-Wunreachable-code */
236
static const char * safer_gnutls_strerror (int value) {
237
const char *ret = gnutls_strerror (value);
380
239
ret = "(unknown)";
384
/* GnuTLS log function callback */
385
static void debuggnutls(__attribute__((unused)) int level,
387
fprintf(stderr, "GnuTLS: %s", string);
243
void debuggnutls(__attribute__((unused)) int level,
245
fprintf(stderr, "%s", string);
390
static int init_gnutls_global(const char *pubkeyfilename,
391
const char *seckeyfilename){
248
int initgnutls(encrypted_session *es){
395
253
fprintf(stderr, "Initializing GnuTLS\n");
398
ret = gnutls_global_init();
399
if(ret != GNUTLS_E_SUCCESS){
400
fprintf(stderr, "GnuTLS global_init: %s\n",
401
safer_gnutls_strerror(ret));
256
if ((ret = gnutls_global_init ())
257
!= GNUTLS_E_SUCCESS) {
258
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
406
/* "Use a log level over 10 to enable all debugging options."
409
263
gnutls_global_set_log_level(11);
410
264
gnutls_global_set_log_function(debuggnutls);
413
/* OpenPGP credentials */
414
gnutls_certificate_allocate_credentials(&mc.cred);
415
if(ret != GNUTLS_E_SUCCESS){
416
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
420
safer_gnutls_strerror(ret));
421
gnutls_global_deinit();
267
/* openpgp credentials */
268
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
269
!= GNUTLS_E_SUCCESS) {
270
fprintf (stderr, "memory error: %s\n",
271
safer_gnutls_strerror(ret));
426
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
427
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
276
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
277
" and keyfile %s as GnuTLS credentials\n", CERTFILE,
431
281
ret = gnutls_certificate_set_openpgp_key_file
432
(mc.cred, pubkeyfilename, seckeyfilename,
433
GNUTLS_OPENPGP_FMT_BASE64);
434
if(ret != GNUTLS_E_SUCCESS){
436
"Error[%d] while reading the OpenPGP key pair ('%s',"
437
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
438
fprintf(stderr, "The GnuTLS error is: %s\n",
439
safer_gnutls_strerror(ret));
443
/* GnuTLS server initialization */
444
ret = gnutls_dh_params_init(&mc.dh_params);
445
if(ret != GNUTLS_E_SUCCESS){
446
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
447
" %s\n", safer_gnutls_strerror(ret));
450
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
451
if(ret != GNUTLS_E_SUCCESS){
452
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
453
safer_gnutls_strerror(ret));
457
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
463
gnutls_certificate_free_credentials(mc.cred);
464
gnutls_global_deinit();
465
gnutls_dh_params_deinit(mc.dh_params);
469
static int init_gnutls_session(gnutls_session_t *session){
471
/* GnuTLS session creation */
472
ret = gnutls_init(session, GNUTLS_SERVER);
473
if(ret != GNUTLS_E_SUCCESS){
282
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
283
if (ret != GNUTLS_E_SUCCESS) {
285
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
287
ret, CERTFILE, KEYFILE);
288
fprintf(stdout, "The Error is: %s\n",
289
safer_gnutls_strerror(ret));
293
//GnuTLS server initialization
294
if ((ret = gnutls_dh_params_init (&es->dh_params))
295
!= GNUTLS_E_SUCCESS) {
296
fprintf (stderr, "Error in dh parameter initialization: %s\n",
297
safer_gnutls_strerror(ret));
301
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
302
!= GNUTLS_E_SUCCESS) {
303
fprintf (stderr, "Error in prime generation: %s\n",
304
safer_gnutls_strerror(ret));
308
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
310
// GnuTLS session creation
311
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
312
!= GNUTLS_E_SUCCESS){
474
313
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
475
314
safer_gnutls_strerror(ret));
480
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
481
if(ret != GNUTLS_E_SUCCESS){
482
fprintf(stderr, "Syntax error at: %s\n", err);
483
fprintf(stderr, "GnuTLS error: %s\n",
484
safer_gnutls_strerror(ret));
485
gnutls_deinit(*session);
317
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
318
!= GNUTLS_E_SUCCESS) {
319
fprintf(stderr, "Syntax error at: %s\n", err);
320
fprintf(stderr, "GnuTLS error: %s\n",
321
safer_gnutls_strerror(ret));
490
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
492
if(ret != GNUTLS_E_SUCCESS){
493
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
325
if ((ret = gnutls_credentials_set
326
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
327
!= GNUTLS_E_SUCCESS) {
328
fprintf(stderr, "Error setting a credentials set: %s\n",
494
329
safer_gnutls_strerror(ret));
495
gnutls_deinit(*session);
499
333
/* ignore client certificate if any. */
500
gnutls_certificate_server_set_request(*session,
334
gnutls_certificate_server_set_request (es->session,
503
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
337
gnutls_dh_set_prime_bits (es->session, DH_BITS);
508
/* Avahi log function callback */
509
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
510
__attribute__((unused)) const char *txt){}
342
void empty_log(__attribute__((unused)) AvahiLogLevel level,
343
__attribute__((unused)) const char *txt){}
512
/* Called when a Mandos server is found */
513
static int start_mandos_communication(const char *ip, uint16_t port,
514
AvahiIfIndex if_index,
345
int start_mandos_communication(const char *ip, uint16_t port,
346
unsigned int if_index){
519
struct sockaddr_in in;
520
struct sockaddr_in6 in6;
348
struct sockaddr_in6 to;
349
encrypted_session es;
522
350
char *buffer = NULL;
523
351
char *decrypted_buffer;
524
352
size_t buffer_length = 0;
525
353
size_t buffer_capacity = 0;
526
354
ssize_t decrypted_buffer_size;
529
gnutls_session_t session;
530
int pf; /* Protocol family */
540
fprintf(stderr, "Bad address family: %d\n", af);
544
ret = init_gnutls_session(&session);
357
char interface[IF_NAMESIZE];
550
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
360
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
554
tcp_sd = socket(pf, SOCK_STREAM, 0);
364
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
556
366
perror("socket");
560
memset(&to, 0, sizeof(to));
562
to.in6.sin6_family = (uint16_t)af;
563
ret = inet_pton(af, ip, &to.in6.sin6_addr);
565
to.in.sin_family = (sa_family_t)af;
566
ret = inet_pton(af, ip, &to.in.sin_addr);
370
if(if_indextoname(if_index, interface) == NULL){
372
perror("if_indextoname");
378
fprintf(stderr, "Binding to interface %s\n", interface);
381
memset(&to,0,sizeof(to)); /* Spurious warning */
382
to.sin6_family = AF_INET6;
383
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
569
385
perror("inet_pton");
573
389
fprintf(stderr, "Bad address: %s\n", ip);
577
to.in6.sin6_port = htons(port); /* Spurious warnings from
579
-Wunreachable-code */
581
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
582
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
584
if(if_index == AVAHI_IF_UNSPEC){
585
fprintf(stderr, "An IPv6 link-local address is incomplete"
586
" without a network interface\n");
589
/* Set the network interface number as scope */
590
to.in6.sin6_scope_id = (uint32_t)if_index;
593
to.in.sin_port = htons(port); /* Spurious warnings from
595
-Wunreachable-code */
392
to.sin6_port = htons(port); /* Spurious warning */
394
to.sin6_scope_id = (uint32_t)if_index;
599
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
600
char interface[IF_NAMESIZE];
601
if(if_indextoname((unsigned int)if_index, interface) == NULL){
602
perror("if_indextoname");
604
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
605
ip, interface, port);
608
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
611
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
612
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
615
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
618
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
624
if(strcmp(addrstr, ip) != 0){
625
fprintf(stderr, "Canonical address form: %s\n", addrstr);
397
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
398
/* char addrstr[INET6_ADDRSTRLEN]; */
399
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
400
/* sizeof(addrstr)) == NULL){ */
401
/* perror("inet_ntop"); */
403
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
404
/* addrstr, ntohs(to.sin6_port)); */
631
ret = connect(tcp_sd, &to.in6, sizeof(to));
633
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
408
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
636
410
perror("connect");
640
const char *out = mandos_protocol_version;
643
size_t out_size = strlen(out);
644
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
645
out_size - written));
651
written += (size_t)ret;
652
if(written < out_size){
655
if(out == mandos_protocol_version){
414
ret = initgnutls (&es);
420
gnutls_transport_set_ptr (es.session,
421
(gnutls_transport_ptr_t) tcp_sd);
665
424
fprintf(stderr, "Establishing TLS session with %s\n", ip);
668
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
671
ret = gnutls_handshake(session);
672
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
674
if(ret != GNUTLS_E_SUCCESS){
427
ret = gnutls_handshake (es.session);
429
if (ret != GNUTLS_E_SUCCESS){
676
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
431
fprintf(stderr, "\n*** Handshake failed ***\n");
683
/* Read OpenPGP packet that contains the wanted password */
438
//Retrieve OpenPGP packet that contains the wanted password
686
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
441
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
691
buffer_capacity = incbuffer(&buffer, buffer_length,
693
if(buffer_capacity == 0){
446
if (buffer_length + BUFFER_SIZE > buffer_capacity){
447
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
452
buffer_capacity += BUFFER_SIZE;
699
sret = gnutls_record_recv(session, buffer+buffer_length,
455
ret = gnutls_record_recv
456
(es.session, buffer+buffer_length, BUFFER_SIZE);
706
462
case GNUTLS_E_INTERRUPTED:
707
463
case GNUTLS_E_AGAIN:
709
465
case GNUTLS_E_REHANDSHAKE:
711
ret = gnutls_handshake(session);
712
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
714
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
466
ret = gnutls_handshake (es.session);
468
fprintf(stderr, "\n*** Handshake failed ***\n");
721
475
fprintf(stderr, "Unknown error while reading data from"
722
" encrypted session with Mandos server\n");
476
" encrypted session with mandos server\n");
724
gnutls_bye(session, GNUTLS_SHUT_RDWR);
478
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
728
buffer_length += (size_t) sret;
482
buffer_length += (size_t) ret;
733
fprintf(stderr, "Closing TLS session\n");
736
gnutls_bye(session, GNUTLS_SHUT_RDWR);
738
if(buffer_length > 0){
486
if (buffer_length > 0){
739
487
decrypted_buffer_size = pgp_packet_decrypt(buffer,
742
if(decrypted_buffer_size >= 0){
491
if (decrypted_buffer_size >= 0){
744
492
while(written < (size_t) decrypted_buffer_size){
745
ret = (int)fwrite(decrypted_buffer + written, 1,
746
(size_t)decrypted_buffer_size - written,
493
ret = (int)fwrite (decrypted_buffer + written, 1,
494
(size_t)decrypted_buffer_size - written,
748
496
if(ret == 0 and ferror(stdout)){
750
498
fprintf(stderr, "Error writing encrypted data: %s\n",
807
561
char ip[AVAHI_ADDRESS_STR_MAX];
808
562
avahi_address_snprint(ip, sizeof(ip), address);
810
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
811
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
812
ip, (intmax_t)interface, port);
564
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
565
" port %d\n", name, host_name, ip, port);
814
int ret = start_mandos_communication(ip, port, interface,
815
avahi_proto_to_af(proto));
817
avahi_simple_poll_quit(mc.simple_poll);
567
int ret = start_mandos_communication(ip, port,
568
(unsigned int) interface);
821
574
avahi_s_service_resolver_free(r);
824
static void browse_callback(AvahiSServiceBrowser *b,
825
AvahiIfIndex interface,
826
AvahiProtocol protocol,
827
AvahiBrowserEvent event,
831
AVAHI_GCC_UNUSED AvahiLookupResultFlags
833
__attribute__((unused)) void* userdata){
836
/* Called whenever a new services becomes available on the LAN or
837
is removed from the LAN */
841
case AVAHI_BROWSER_FAILURE:
843
fprintf(stderr, "(Avahi browser) %s\n",
844
avahi_strerror(avahi_server_errno(mc.server)));
845
avahi_simple_poll_quit(mc.simple_poll);
848
case AVAHI_BROWSER_NEW:
849
/* We ignore the returned Avahi resolver object. In the callback
850
function we free it. If the Avahi server is terminated before
851
the callback function is called the Avahi server will free the
854
if(!(avahi_s_service_resolver_new(mc.server, interface,
855
protocol, name, type, domain,
856
AVAHI_PROTO_INET6, 0,
857
resolve_callback, NULL)))
858
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
859
name, avahi_strerror(avahi_server_errno(mc.server)));
862
case AVAHI_BROWSER_REMOVE:
865
case AVAHI_BROWSER_ALL_FOR_NOW:
866
case AVAHI_BROWSER_CACHE_EXHAUSTED:
868
fprintf(stderr, "No Mandos server found, still searching...\n");
577
static void browse_callback(
578
AvahiSServiceBrowser *b,
579
AvahiIfIndex interface,
580
AvahiProtocol protocol,
581
AvahiBrowserEvent event,
585
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
588
AvahiServer *s = userdata;
589
assert(b); /* Spurious warning */
591
/* Called whenever a new services becomes available on the LAN or
592
is removed from the LAN */
596
case AVAHI_BROWSER_FAILURE:
598
fprintf(stderr, "(Browser) %s\n",
599
avahi_strerror(avahi_server_errno(server)));
600
avahi_simple_poll_quit(simple_poll);
603
case AVAHI_BROWSER_NEW:
604
/* We ignore the returned resolver object. In the callback
605
function we free it. If the server is terminated before
606
the callback function is called the server will free
607
the resolver for us. */
609
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
611
AVAHI_PROTO_INET6, 0,
612
resolve_callback, s)))
613
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
614
avahi_strerror(avahi_server_errno(s)));
617
case AVAHI_BROWSER_REMOVE:
620
case AVAHI_BROWSER_ALL_FOR_NOW:
621
case AVAHI_BROWSER_CACHE_EXHAUSTED:
874
/* stop main loop after sigterm has been called */
875
static void handle_sigterm(__attribute__((unused)) int sig){
876
int old_errno = errno;
877
avahi_simple_poll_quit(mc.simple_poll);
881
int main(int argc, char *argv[]){
882
AvahiSServiceBrowser *sb = NULL;
887
int exitcode = EXIT_SUCCESS;
888
const char *interface = "eth0";
889
struct ifreq network;
893
char *connect_to = NULL;
894
char tempdir[] = "/tmp/mandosXXXXXX";
895
bool tempdir_created = false;
896
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
897
const char *seckey = PATHDIR "/" SECKEY;
898
const char *pubkey = PATHDIR "/" PUBKEY;
900
bool gnutls_initialized = false;
901
bool gpgme_initialized = false;
904
struct sigaction old_sigterm_action;
905
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
908
struct argp_option options[] = {
909
{ .name = "debug", .key = 128,
910
.doc = "Debug mode", .group = 3 },
911
{ .name = "connect", .key = 'c',
912
.arg = "ADDRESS:PORT",
913
.doc = "Connect directly to a specific Mandos server",
915
{ .name = "interface", .key = 'i',
917
.doc = "Network interface that will be used to search for"
920
{ .name = "seckey", .key = 's',
922
.doc = "OpenPGP secret key file base name",
924
{ .name = "pubkey", .key = 'p',
926
.doc = "OpenPGP public key file base name",
928
{ .name = "dh-bits", .key = 129,
930
.doc = "Bit length of the prime number used in the"
931
" Diffie-Hellman key exchange",
933
{ .name = "priority", .key = 130,
935
.doc = "GnuTLS priority string for the TLS handshake",
937
{ .name = "delay", .key = 131,
939
.doc = "Maximum delay to wait for interface startup",
626
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
627
AvahiServerConfig config;
628
AvahiSServiceBrowser *sb = NULL;
631
int returncode = EXIT_SUCCESS;
632
const char *interface = "eth0";
633
unsigned int if_index;
634
char *connect_to = NULL;
944
error_t parse_opt(int key, char *arg,
945
struct argp_state *state){
947
case 128: /* --debug */
950
case 'c': /* --connect */
953
case 'i': /* --interface */
956
case 's': /* --seckey */
959
case 'p': /* --pubkey */
962
case 129: /* --dh-bits */
963
ret = sscanf(arg, "%" SCNdMAX "%n", &tmpmax, &numchars);
964
if(ret < 1 or tmpmax != (typeof(mc.dh_bits))tmpmax
965
or arg[numchars] != '\0'){
966
fprintf(stderr, "Bad number of DH bits\n");
969
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
971
case 130: /* --priority */
974
case 131: /* --delay */
975
ret = sscanf(arg, "%lf%n", &delay, &numchars);
976
if(ret < 1 or arg[numchars] != '\0'){
977
fprintf(stderr, "Bad delay\n");
637
static struct option long_options[] = {
638
{"debug", no_argument, (int *)&debug, 1},
639
{"connect", required_argument, 0, 'c'},
640
{"interface", required_argument, 0, 'i'},
643
int option_index = 0;
644
ret = getopt_long (argc, argv, "i:", long_options,
986
return ARGP_ERR_UNKNOWN;
991
struct argp argp = { .options = options, .parser = parse_opt,
993
.doc = "Mandos client -- Get and decrypt"
994
" passwords from a Mandos server" };
995
ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
996
if(ret == ARGP_ERR_UNKNOWN){
997
fprintf(stderr, "Unknown error while parsing arguments\n");
998
exitcode = EXIT_FAILURE;
1004
avahi_set_log_function(empty_log);
1007
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1008
from the signal handler */
1009
/* Initialize the pseudo-RNG for Avahi */
1010
srand((unsigned int) time(NULL));
1011
mc.simple_poll = avahi_simple_poll_new();
1012
if(mc.simple_poll == NULL){
1013
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1014
exitcode = EXIT_FAILURE;
1018
sigemptyset(&sigterm_action.sa_mask);
1019
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1021
perror("sigaddset");
1022
exitcode = EXIT_FAILURE;
1025
ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
1027
perror("sigaction");
1028
exitcode = EXIT_FAILURE;
1033
/* If the interface is down, bring it up */
1034
if(interface[0] != '\0'){
1036
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1037
messages to mess up the prompt */
1038
ret = klogctl(8, NULL, 5);
1039
bool restore_loglevel = true;
1041
restore_loglevel = false;
1046
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1049
exitcode = EXIT_FAILURE;
1051
if(restore_loglevel){
1052
ret = klogctl(7, NULL, 0);
1060
strcpy(network.ifr_name, interface);
1061
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1063
perror("ioctl SIOCGIFFLAGS");
1065
if(restore_loglevel){
1066
ret = klogctl(7, NULL, 0);
1072
exitcode = EXIT_FAILURE;
1075
if((network.ifr_flags & IFF_UP) == 0){
1076
network.ifr_flags |= IFF_UP;
1077
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1079
perror("ioctl SIOCSIFFLAGS");
1080
exitcode = EXIT_FAILURE;
1082
if(restore_loglevel){
1083
ret = klogctl(7, NULL, 0);
1092
/* sleep checking until interface is running */
1093
for(int i=0; i < delay * 4; i++){
1094
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1096
perror("ioctl SIOCGIFFLAGS");
1097
} else if(network.ifr_flags & IFF_RUNNING){
1100
struct timespec sleeptime = { .tv_nsec = 250000000 };
1101
ret = nanosleep(&sleeptime, NULL);
1102
if(ret == -1 and errno != EINTR){
1103
perror("nanosleep");
1106
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1111
if(restore_loglevel){
1112
/* Restores kernel loglevel to default */
1113
ret = klogctl(7, NULL, 0);
1135
ret = init_gnutls_global(pubkey, seckey);
1137
fprintf(stderr, "init_gnutls_global failed\n");
1138
exitcode = EXIT_FAILURE;
1141
gnutls_initialized = true;
1144
if(mkdtemp(tempdir) == NULL){
1148
tempdir_created = true;
1150
if(not init_gpgme(pubkey, seckey, tempdir)){
1151
fprintf(stderr, "init_gpgme failed\n");
1152
exitcode = EXIT_FAILURE;
1155
gpgme_initialized = true;
1158
if(interface[0] != '\0'){
1159
if_index = (AvahiIfIndex) if_nametoindex(interface);
665
if_index = if_nametoindex(interface);
1160
666
if(if_index == 0){
1161
667
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1162
exitcode = EXIT_FAILURE;
1167
if(connect_to != NULL){
1168
/* Connect directly, do not use Zeroconf */
1169
/* (Mainly meant for debugging) */
1170
char *address = strrchr(connect_to, ':');
1171
if(address == NULL){
1172
fprintf(stderr, "No colon in address\n");
1173
exitcode = EXIT_FAILURE;
1177
ret = sscanf(address+1, "%" SCNdMAX "%n", &tmpmax, &numchars);
1178
if(ret < 1 or tmpmax != (uint16_t)tmpmax
1179
or address[numchars+1] != '\0'){
1180
fprintf(stderr, "Bad port number\n");
1181
exitcode = EXIT_FAILURE;
1184
port = (uint16_t)tmpmax;
1186
address = connect_to;
1187
/* Colon in address indicates IPv6 */
1189
if(strchr(address, ':') != NULL){
1194
ret = start_mandos_communication(address, port, if_index,
1197
exitcode = EXIT_FAILURE;
1199
exitcode = EXIT_SUCCESS;
1205
AvahiServerConfig config;
1206
/* Do not publish any local Zeroconf records */
671
if(connect_to != NULL){
672
/* Connect directly, do not use Zeroconf */
673
/* (Mainly meant for debugging) */
674
char *address = strrchr(connect_to, ':');
676
fprintf(stderr, "No colon in address\n");
680
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
682
perror("Bad port number");
686
address = connect_to;
687
ret = start_mandos_communication(address, port, if_index);
696
avahi_set_log_function(empty_log);
699
/* Initialize the psuedo-RNG */
700
srand((unsigned int) time(NULL));
702
/* Allocate main loop object */
703
if (!(simple_poll = avahi_simple_poll_new())) {
704
fprintf(stderr, "Failed to create simple poll object.\n");
709
/* Do not publish any local records */
1207
710
avahi_server_config_init(&config);
1208
711
config.publish_hinfo = 0;
1209
712
config.publish_addresses = 0;
1210
713
config.publish_workstation = 0;
1211
714
config.publish_domain = 0;
1213
716
/* Allocate a new server */
1214
mc.server = avahi_server_new(avahi_simple_poll_get
1215
(mc.simple_poll), &config, NULL,
1218
/* Free the Avahi configuration data */
717
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
718
&config, NULL, NULL, &error);
720
/* Free the configuration data */
1219
721
avahi_server_config_free(&config);
1222
/* Check if creating the Avahi server object succeeded */
1223
if(mc.server == NULL){
1224
fprintf(stderr, "Failed to create Avahi server: %s\n",
1225
avahi_strerror(error));
1226
exitcode = EXIT_FAILURE;
1230
/* Create the Avahi service browser */
1231
sb = avahi_s_service_browser_new(mc.server, if_index,
1232
AVAHI_PROTO_INET6, "_mandos._tcp",
1233
NULL, 0, browse_callback, NULL);
1235
fprintf(stderr, "Failed to create service browser: %s\n",
1236
avahi_strerror(avahi_server_errno(mc.server)));
1237
exitcode = EXIT_FAILURE;
1241
/* Run the main loop */
1244
fprintf(stderr, "Starting Avahi loop search\n");
1247
avahi_simple_poll_loop(mc.simple_poll);
1252
fprintf(stderr, "%s exiting\n", argv[0]);
1255
/* Cleanup things */
1257
avahi_s_service_browser_free(sb);
1259
if(mc.server != NULL)
1260
avahi_server_free(mc.server);
1262
if(mc.simple_poll != NULL)
1263
avahi_simple_poll_free(mc.simple_poll);
1265
if(gnutls_initialized){
1266
gnutls_certificate_free_credentials(mc.cred);
1267
gnutls_global_deinit();
1268
gnutls_dh_params_deinit(mc.dh_params);
1271
if(gpgme_initialized){
1272
gpgme_release(mc.ctx);
1275
/* Removes the temp directory used by GPGME */
1276
if(tempdir_created){
1278
struct dirent *direntry;
1279
d = opendir(tempdir);
1281
if(errno != ENOENT){
1286
direntry = readdir(d);
1287
if(direntry == NULL){
1290
/* Skip "." and ".." */
1291
if(direntry->d_name[0] == '.'
1292
and (direntry->d_name[1] == '\0'
1293
or (direntry->d_name[1] == '.'
1294
and direntry->d_name[2] == '\0'))){
1297
char *fullname = NULL;
1298
ret = asprintf(&fullname, "%s/%s", tempdir,
1304
ret = remove(fullname);
1306
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1313
ret = rmdir(tempdir);
1314
if(ret == -1 and errno != ENOENT){
723
/* Check if creating the server object succeeded */
725
fprintf(stderr, "Failed to create server: %s\n",
726
avahi_strerror(error));
727
returncode = EXIT_FAILURE;
731
/* Create the service browser */
732
sb = avahi_s_service_browser_new(server, (AvahiIfIndex)if_index,
734
"_mandos._tcp", NULL, 0,
735
browse_callback, server);
737
fprintf(stderr, "Failed to create service browser: %s\n",
738
avahi_strerror(avahi_server_errno(server)));
739
returncode = EXIT_FAILURE;
743
/* Run the main loop */
746
fprintf(stderr, "Starting avahi loop search\n");
749
avahi_simple_poll_loop(simple_poll);
754
fprintf(stderr, "%s exiting\n", argv[0]);
759
avahi_s_service_browser_free(sb);
762
avahi_server_free(server);
765
avahi_simple_poll_free(simple_poll);