31
32
/* Needed by GPGME, specifically gpgme_data_seek() */
33
#ifndef _LARGEFILE_SOURCE
32
34
#define _LARGEFILE_SOURCE
36
#ifndef _FILE_OFFSET_BITS
33
37
#define _FILE_OFFSET_BITS 64
39
#include <net/if.h> /* if_nametoindex */
40
#include <sys/ioctl.h> // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
41
#include <net/if.h> // ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, SIOCSIFFLAGS
40
#define _GNU_SOURCE /* TEMP_FAILURE_RETRY(), asprintf() */
42
#include <stdio.h> /* fprintf(), stderr, fwrite(),
43
stdout, ferror(), remove() */
44
#include <stdint.h> /* uint16_t, uint32_t */
45
#include <stddef.h> /* NULL, size_t, ssize_t */
46
#include <stdlib.h> /* free(), EXIT_SUCCESS, EXIT_FAILURE,
48
#include <stdbool.h> /* bool, false, true */
49
#include <string.h> /* memset(), strcmp(), strlen(),
50
strerror(), asprintf(), strcpy() */
51
#include <sys/ioctl.h> /* ioctl */
52
#include <sys/types.h> /* socket(), inet_pton(), sockaddr,
53
sockaddr_in6, PF_INET6,
54
SOCK_STREAM, uid_t, gid_t, open(),
56
#include <sys/stat.h> /* open() */
57
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
58
inet_pton(), connect() */
59
#include <fcntl.h> /* open() */
60
#include <dirent.h> /* opendir(), struct dirent, readdir()
62
#include <inttypes.h> /* PRIu16, PRIdMAX, intmax_t,
64
#include <assert.h> /* assert() */
65
#include <errno.h> /* perror(), errno */
66
#include <time.h> /* nanosleep(), time() */
67
#include <net/if.h> /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
68
SIOCSIFFLAGS, if_indextoname(),
69
if_nametoindex(), IF_NAMESIZE */
70
#include <netinet/in.h> /* IN6_IS_ADDR_LINKLOCAL,
71
INET_ADDRSTRLEN, INET6_ADDRSTRLEN
73
#include <unistd.h> /* close(), SEEK_SET, off_t, write(),
74
getuid(), getgid(), setuid(),
76
#include <arpa/inet.h> /* inet_pton(), htons */
77
#include <iso646.h> /* not, or, and */
78
#include <argp.h> /* struct argp_option, error_t, struct
79
argp_state, struct argp,
80
argp_parse(), ARGP_KEY_ARG,
81
ARGP_KEY_END, ARGP_ERR_UNKNOWN */
82
#include <signal.h> /* sigemptyset(), sigaddset(),
83
sigaction(), SIGTERM, sigaction,
87
#include <sys/klog.h> /* klogctl() */
88
#endif /* __linux__ */
91
/* All Avahi types, constants and functions
43
94
#include <avahi-core/core.h>
44
95
#include <avahi-core/lookup.h>
45
96
#include <avahi-core/log.h>
47
98
#include <avahi-common/malloc.h>
48
99
#include <avahi-common/error.h>
51
#include <sys/types.h> /* socket(), inet_pton() */
52
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
53
struct in6_addr, inet_pton() */
54
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
55
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
57
#include <unistd.h> /* close() */
58
#include <netinet/in.h>
59
#include <stdbool.h> /* true */
60
#include <string.h> /* memset */
61
#include <arpa/inet.h> /* inet_pton() */
62
#include <iso646.h> /* not */
65
#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,
71
118
#define BUFFER_SIZE 256
74
static const char *certdir = "/conf/conf.d/mandos";
75
static const char *certfile = "openpgp-client.txt";
76
static const char *certkey = "openpgp-client-key.txt";
120
#define PATHDIR "/conf/conf.d/mandos"
121
#define SECKEY "seckey.txt"
122
#define PUBKEY "pubkey.txt"
78
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 */
81
gnutls_session_t session;
131
AvahiSimplePoll *simple_poll;
82
133
gnutls_certificate_credentials_t cred;
134
unsigned int dh_bits;
83
135
gnutls_dh_params_t dh_params;
87
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
90
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){
94
ssize_t new_packet_capacity = 0;
95
ssize_t new_packet_length = 0;
96
169
gpgme_engine_info_t engine_info;
99
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");
103
212
gpgme_check_version(NULL);
104
213
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
105
if (rc != GPG_ERR_NO_ERROR){
214
if(rc != GPG_ERR_NO_ERROR){
106
215
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
107
216
gpgme_strsource(rc), gpgme_strerror(rc));
111
/* Set GPGME home directory */
112
rc = gpgme_get_engine_info (&engine_info);
113
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){
114
223
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
115
224
gpgme_strsource(rc), gpgme_strerror(rc));
118
227
while(engine_info != NULL){
119
228
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
120
229
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
121
engine_info->file_name, homedir);
230
engine_info->file_name, tempdir);
124
233
engine_info = engine_info->next;
126
235
if(engine_info == NULL){
127
fprintf(stderr, "Could not set home dir to %s\n", homedir);
131
/* Create new GPGME data buffer from packet buffer */
132
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
133
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){
134
276
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
135
277
gpgme_strsource(rc), gpgme_strerror(rc));
139
281
/* Create new empty GPGME data buffer for the plaintext */
140
282
rc = gpgme_data_new(&dh_plain);
141
if (rc != GPG_ERR_NO_ERROR){
283
if(rc != GPG_ERR_NO_ERROR){
142
284
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
143
285
gpgme_strsource(rc), gpgme_strerror(rc));
147
/* Create new GPGME "context" */
148
rc = gpgme_new(&ctx);
149
if (rc != GPG_ERR_NO_ERROR){
150
fprintf(stderr, "bad gpgme_new: %s: %s\n",
151
gpgme_strsource(rc), gpgme_strerror(rc));
155
/* Decrypt data from the FILE pointer to the plaintext data
157
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
158
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){
159
294
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
160
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;
165
fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
169
gpgme_decrypt_result_t result;
170
result = gpgme_op_decrypt_result(ctx);
172
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
174
fprintf(stderr, "Unsupported algorithm: %s\n",
175
result->unsupported_algorithm);
176
fprintf(stderr, "Wrong key usage: %d\n",
177
result->wrong_key_usage);
178
if(result->file_name != NULL){
179
fprintf(stderr, "File name: %s\n", result->file_name);
181
gpgme_recipient_t recipient;
182
recipient = result->recipients;
184
while(recipient != NULL){
185
fprintf(stderr, "Public key algorithm: %s\n",
186
gpgme_pubkey_algo_name(recipient->pubkey_algo));
187
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
188
fprintf(stderr, "Secret key available: %s\n",
189
recipient->status == GPG_ERR_NO_SECKEY
191
recipient = recipient->next;
197
/* Delete the GPGME FILE pointer cryptotext data buffer */
198
gpgme_data_release(dh_crypto);
329
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
200
332
/* Seek back to the beginning of the GPGME plaintext data buffer */
201
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
202
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;
207
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
208
*new_packet = realloc(*new_packet,
209
(unsigned int)new_packet_capacity
211
if (*new_packet == NULL){
215
new_packet_capacity += BUFFER_SIZE;
341
plaintext_capacity = incbuffer(plaintext,
342
(size_t)plaintext_length,
344
if(plaintext_capacity == 0){
346
plaintext_length = -1;
218
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
350
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
220
352
/* Print the data, if any */
225
358
perror("gpgme_data_read");
228
new_packet_length += ret;
231
/* FIXME: check characters before printing to screen so to not print
232
terminal control characters */
234
/* fprintf(stderr, "decrypted password is: "); */
235
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
236
/* 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);
239
378
/* Delete the GPGME plaintext data buffer */
240
379
gpgme_data_release(dh_plain);
241
return new_packet_length;
380
return plaintext_length;
244
static const char * safer_gnutls_strerror (int value) {
245
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 */
247
387
ret = "(unknown)";
391
/* GnuTLS log function callback */
251
392
static void debuggnutls(__attribute__((unused)) int level,
252
393
const char* string){
253
fprintf(stderr, "%s", string);
394
fprintf(stderr, "GnuTLS: %s", string);
256
static int initgnutls(encrypted_session *es){
397
static int init_gnutls_global(const char *pubkeyfilename,
398
const char *seckeyfilename){
261
402
fprintf(stderr, "Initializing GnuTLS\n");
264
if ((ret = gnutls_global_init ())
265
!= GNUTLS_E_SUCCESS) {
266
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."
271
416
gnutls_global_set_log_level(11);
272
417
gnutls_global_set_log_function(debuggnutls);
275
/* openpgp credentials */
276
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
277
!= GNUTLS_E_SUCCESS) {
278
fprintf (stderr, "memory error: %s\n",
279
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();
284
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
285
" 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,
289
438
ret = gnutls_certificate_set_openpgp_key_file
290
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
291
if (ret != GNUTLS_E_SUCCESS) {
293
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
295
ret, certfile, certkey);
296
fprintf(stdout, "The Error is: %s\n",
297
safer_gnutls_strerror(ret));
301
//GnuTLS server initialization
302
if ((ret = gnutls_dh_params_init (&es->dh_params))
303
!= GNUTLS_E_SUCCESS) {
304
fprintf (stderr, "Error in dh parameter initialization: %s\n",
305
safer_gnutls_strerror(ret));
309
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
310
!= GNUTLS_E_SUCCESS) {
311
fprintf (stderr, "Error in prime generation: %s\n",
312
safer_gnutls_strerror(ret));
316
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
318
// GnuTLS session creation
319
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
320
!= 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){
321
481
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
322
482
safer_gnutls_strerror(ret));
325
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
326
!= GNUTLS_E_SUCCESS) {
327
fprintf(stderr, "Syntax error at: %s\n", err);
328
fprintf(stderr, "GnuTLS error: %s\n",
329
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);
333
if ((ret = gnutls_credentials_set
334
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
335
!= GNUTLS_E_SUCCESS) {
336
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",
337
501
safer_gnutls_strerror(ret));
502
gnutls_deinit(*session);
341
506
/* ignore client certificate if any. */
342
gnutls_certificate_server_set_request (es->session,
507
gnutls_certificate_server_set_request(*session,
345
gnutls_dh_set_prime_bits (es->session, DH_BITS);
510
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
515
/* Avahi log function callback */
350
516
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
351
517
__attribute__((unused)) const char *txt){}
519
/* Called when a Mandos server is found */
353
520
static int start_mandos_communication(const char *ip, uint16_t port,
354
AvahiIfIndex if_index){
521
AvahiIfIndex if_index,
356
struct sockaddr_in6 to;
357
encrypted_session es;
526
struct sockaddr_in in;
527
struct sockaddr_in6 in6;
358
529
char *buffer = NULL;
359
530
char *decrypted_buffer;
360
531
size_t buffer_length = 0;
361
532
size_t buffer_capacity = 0;
362
533
ssize_t decrypted_buffer_size;
365
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);
368
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
557
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
372
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
561
tcp_sd = socket(pf, SOCK_STREAM, 0);
374
563
perror("socket");
379
if(if_indextoname((unsigned int)if_index, interface) == NULL){
381
perror("if_indextoname");
386
fprintf(stderr, "Binding to interface %s\n", interface);
389
memset(&to,0,sizeof(to)); /* Spurious warning */
390
to.sin6_family = AF_INET6;
391
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);
393
576
perror("inet_pton");
397
580
fprintf(stderr, "Bad address: %s\n", ip);
400
to.sin6_port = htons(port); /* Spurious warning */
402
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 */
405
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
406
/* char addrstr[INET6_ADDRSTRLEN]; */
407
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
408
/* sizeof(addrstr)) == NULL){ */
409
/* perror("inet_ntop"); */
411
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
412
/* 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);
416
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 */
418
643
perror("connect");
422
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){
428
gnutls_transport_set_ptr (es.session,
429
(gnutls_transport_ptr_t) tcp_sd);
432
672
fprintf(stderr, "Establishing TLS session with %s\n", ip);
435
ret = gnutls_handshake (es.session);
437
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){
439
fprintf(stderr, "\n*** Handshake failed ***\n");
683
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
446
//Retrieve OpenPGP packet that contains the wanted password
690
/* Read OpenPGP packet that contains the wanted password */
449
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
693
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
454
if (buffer_length + BUFFER_SIZE > buffer_capacity){
455
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
460
buffer_capacity += BUFFER_SIZE;
698
buffer_capacity = incbuffer(&buffer, buffer_length,
700
if(buffer_capacity == 0){
463
ret = gnutls_record_recv
464
(es.session, buffer+buffer_length, BUFFER_SIZE);
706
sret = gnutls_record_recv(session, buffer+buffer_length,
470
713
case GNUTLS_E_INTERRUPTED:
471
714
case GNUTLS_E_AGAIN:
473
716
case GNUTLS_E_REHANDSHAKE:
474
ret = gnutls_handshake (es.session);
476
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");
483
728
fprintf(stderr, "Unknown error while reading data from"
484
" encrypted session with mandos server\n");
729
" encrypted session with Mandos server\n");
486
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
731
gnutls_bye(session, GNUTLS_SHUT_RDWR);
490
buffer_length += (size_t) ret;
735
buffer_length += (size_t) sret;
494
if (buffer_length > 0){
740
fprintf(stderr, "Closing TLS session\n");
743
gnutls_bye(session, GNUTLS_SHUT_RDWR);
745
if(buffer_length > 0){
495
746
decrypted_buffer_size = pgp_packet_decrypt(buffer,
499
if (decrypted_buffer_size >= 0){
749
if(decrypted_buffer_size >= 0){
500
751
while(written < (size_t) decrypted_buffer_size){
501
ret = (int)fwrite (decrypted_buffer + written, 1,
502
(size_t)decrypted_buffer_size - written,
752
ret = (int)fwrite(decrypted_buffer + written, 1,
753
(size_t)decrypted_buffer_size - written,
504
755
if(ret == 0 and ferror(stdout)){
506
757
fprintf(stderr, "Error writing encrypted data: %s\n",
569
814
char ip[AVAHI_ADDRESS_STR_MAX];
570
815
avahi_address_snprint(ip, sizeof(ip), address);
572
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
573
" 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);
575
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);
581
828
avahi_s_service_resolver_free(r);
584
static void browse_callback(
585
AvahiSServiceBrowser *b,
586
AvahiIfIndex interface,
587
AvahiProtocol protocol,
588
AvahiBrowserEvent event,
592
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
595
AvahiServer *s = userdata;
596
assert(b); /* Spurious warning */
598
/* Called whenever a new services becomes available on the LAN or
599
is removed from the LAN */
603
case AVAHI_BROWSER_FAILURE:
605
fprintf(stderr, "(Browser) %s\n",
606
avahi_strerror(avahi_server_errno(server)));
607
avahi_simple_poll_quit(simple_poll);
610
case AVAHI_BROWSER_NEW:
611
/* We ignore the returned resolver object. In the callback
612
function we free it. If the server is terminated before
613
the callback function is called the server will free
614
the resolver for us. */
616
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
618
AVAHI_PROTO_INET6, 0,
619
resolve_callback, s)))
620
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
621
avahi_strerror(avahi_server_errno(s)));
624
case AVAHI_BROWSER_REMOVE:
627
case AVAHI_BROWSER_ALL_FOR_NOW:
628
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");
633
/* Combines file name and path and returns the malloced new
634
string. some sane checks could/should be added */
635
static const char *combinepath(const char *first, const char *second){
636
size_t f_len = strlen(first);
637
size_t s_len = strlen(second);
638
char *tmp = malloc(f_len + s_len + 2);
643
memcpy(tmp, first, f_len);
647
memcpy(tmp + f_len + 1, second, s_len);
649
tmp[f_len + 1 + s_len] = '\0';
654
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
655
AvahiServerConfig config;
656
AvahiSServiceBrowser *sb = NULL;
659
int returncode = EXIT_SUCCESS;
660
const char *interface = "eth0";
661
struct ifreq network;
663
char *connect_to = NULL;
664
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
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;
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",
667
static struct option long_options[] = {
668
{"debug", no_argument, (int *)&debug, 1},
669
{"connect", required_argument, 0, 'C'},
670
{"interface", required_argument, 0, 'i'},
671
{"certdir", required_argument, 0, 'd'},
672
{"certkey", required_argument, 0, 'c'},
673
{"certfile", required_argument, 0, 'k'},
676
int option_index = 0;
677
ret = getopt_long (argc, argv, "i:", long_options,
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");
707
certfile = combinepath(certdir, certfile);
708
if (certfile == NULL){
709
perror("combinepath");
710
returncode = EXIT_FAILURE;
714
certkey = combinepath(certdir, certkey);
715
if (certkey == NULL){
716
perror("combinepath");
717
returncode = EXIT_FAILURE;
721
if_index = (AvahiIfIndex) if_nametoindex(interface);
723
fprintf(stderr, "No such interface: \"%s\"\n", interface);
727
if(connect_to != NULL){
728
/* Connect directly, do not use Zeroconf */
729
/* (Mainly meant for debugging) */
730
char *address = strrchr(connect_to, ':');
732
fprintf(stderr, "No colon in address\n");
736
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
738
perror("Bad port number");
742
address = connect_to;
743
ret = start_mandos_communication(address, port, if_index);
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__ */
751
1073
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
753
1075
perror("socket");
754
returncode = EXIT_FAILURE;
1076
exitcode = EXIT_FAILURE;
1078
if(restore_loglevel){
1079
ret = klogctl(7, NULL, 0);
1084
#endif /* __linux__ */
757
strcpy(network.ifr_name, interface);
1087
strcpy(network.ifr_name, interface);
758
1088
ret = ioctl(sd, SIOCGIFFLAGS, &network);
761
1090
perror("ioctl SIOCGIFFLAGS");
762
returncode = EXIT_FAILURE;
1092
if(restore_loglevel){
1093
ret = klogctl(7, NULL, 0);
1098
#endif /* __linux__ */
1099
exitcode = EXIT_FAILURE;
765
1102
if((network.ifr_flags & IFF_UP) == 0){
766
1103
network.ifr_flags |= IFF_UP;
767
1104
ret = ioctl(sd, SIOCSIFFLAGS, &network);
769
1106
perror("ioctl SIOCSIFFLAGS");
770
returncode = EXIT_FAILURE;
777
avahi_set_log_function(empty_log);
780
/* Initialize the psuedo-RNG */
781
srand((unsigned int) time(NULL));
783
/* Allocate main loop object */
784
if (!(simple_poll = avahi_simple_poll_new())) {
785
fprintf(stderr, "Failed to create simple poll object.\n");
786
returncode = EXIT_FAILURE;
790
/* Do not publish any local records */
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;
1232
AvahiServerConfig config;
1233
/* Do not publish any local Zeroconf records */
791
1234
avahi_server_config_init(&config);
792
1235
config.publish_hinfo = 0;
793
1236
config.publish_addresses = 0;
794
1237
config.publish_workstation = 0;
795
1238
config.publish_domain = 0;
797
1240
/* Allocate a new server */
798
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
799
&config, NULL, NULL, &error);
801
/* 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 */
802
1246
avahi_server_config_free(&config);
804
/* Check if creating the server object succeeded */
806
fprintf(stderr, "Failed to create server: %s\n",
807
avahi_strerror(error));
808
returncode = EXIT_FAILURE;
812
/* Create the service browser */
813
sb = avahi_s_service_browser_new(server, if_index,
815
"_mandos._tcp", NULL, 0,
816
browse_callback, server);
818
fprintf(stderr, "Failed to create service browser: %s\n",
819
avahi_strerror(avahi_server_errno(server)));
820
returncode = EXIT_FAILURE;
824
/* Run the main loop */
827
fprintf(stderr, "Starting avahi loop search\n");
830
avahi_simple_poll_loop(simple_poll);
835
fprintf(stderr, "%s exiting\n", argv[0]);
840
avahi_s_service_browser_free(sb);
843
avahi_server_free(server);
846
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){