25
26
* along with this program. If not, see
26
27
* <http://www.gnu.org/licenses/>.
28
* Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
29
* <https://www.fukt.bsnet.se/~teddy/>.
29
* Contact the authors at <mandos@fukt.bsnet.se>.
32
#define _FORTIFY_SOURCE 2
32
/* Needed by GPGME, specifically gpgme_data_seek() */
34
33
#define _LARGEFILE_SOURCE
35
34
#define _FILE_OFFSET_BITS 64
41
#include <net/if.h> /* if_nametoindex */
36
#define _GNU_SOURCE /* TEMP_FAILURE_RETRY(), asprintf() */
38
#include <stdio.h> /* fprintf(), stderr, fwrite(),
39
stdout, ferror(), sscanf */
40
#include <stdint.h> /* uint16_t, uint32_t */
41
#include <stddef.h> /* NULL, size_t, ssize_t */
42
#include <stdlib.h> /* free(), EXIT_SUCCESS, EXIT_FAILURE,
44
#include <stdbool.h> /* bool, true */
45
#include <string.h> /* memset(), strcmp(), strlen(),
46
strerror(), asprintf(), strcpy() */
47
#include <sys/ioctl.h> /* ioctl */
48
#include <sys/types.h> /* socket(), inet_pton(), sockaddr,
49
sockaddr_in6, PF_INET6,
50
SOCK_STREAM, INET6_ADDRSTRLEN,
51
uid_t, gid_t, open(), opendir(),
53
#include <sys/stat.h> /* open() */
54
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
55
struct in6_addr, inet_pton(),
57
#include <fcntl.h> /* open() */
58
#include <dirent.h> /* opendir(), struct dirent, readdir()
60
#include <inttypes.h> /* PRIu16, intmax_t, SCNdMAX */
61
#include <assert.h> /* assert() */
62
#include <errno.h> /* perror(), errno */
63
#include <time.h> /* time(), nanosleep() */
64
#include <net/if.h> /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
65
SIOCSIFFLAGS, if_indextoname(),
66
if_nametoindex(), IF_NAMESIZE */
67
#include <netinet/in.h>
68
#include <unistd.h> /* close(), SEEK_SET, off_t, write(),
69
getuid(), getgid(), setuid(),
71
#include <arpa/inet.h> /* inet_pton(), htons */
72
#include <iso646.h> /* not, and, or */
73
#include <argp.h> /* struct argp_option, error_t, struct
74
argp_state, struct argp,
75
argp_parse(), ARGP_KEY_ARG,
76
ARGP_KEY_END, ARGP_ERR_UNKNOWN */
77
#include <sys/klog.h> /* klogctl() */
80
/* All Avahi types, constants and functions
43
83
#include <avahi-core/core.h>
44
84
#include <avahi-core/lookup.h>
45
85
#include <avahi-core/log.h>
47
87
#include <avahi-common/malloc.h>
48
88
#include <avahi-common/error.h>
51
#include <sys/types.h> /* socket(), setsockopt(),
53
#include <sys/socket.h> /* socket(), setsockopt(),
55
struct in6_addr, inet_pton() */
56
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
57
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
59
#include <unistd.h> /* close() */
60
#include <netinet/in.h>
61
#include <stdbool.h> /* true */
62
#include <string.h> /* memset */
63
#include <arpa/inet.h> /* inet_pton() */
64
#include <iso646.h> /* not */
67
#include <errno.h> /* perror() */
74
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
76
#define CERTFILE CERT_ROOT "openpgp-client.txt"
77
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
91
#include <gnutls/gnutls.h> /* All GnuTLS types, constants and
94
init_gnutls_session(),
96
#include <gnutls/openpgp.h>
97
/* gnutls_certificate_set_openpgp_key_file(),
98
GNUTLS_OPENPGP_FMT_BASE64 */
101
#include <gpgme.h> /* All GPGME types, constants and
104
GPGME_PROTOCOL_OpenPGP,
78
107
#define BUFFER_SIZE 256
109
#define PATHDIR "/conf/conf.d/mandos"
110
#define SECKEY "seckey.txt"
111
#define PUBKEY "pubkey.txt"
81
113
bool debug = false;
114
static const char mandos_protocol_version[] = "1";
115
const char *argp_program_version = "mandos-client " VERSION;
116
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
118
/* Used for passing in values through the Avahi callback functions */
84
gnutls_session_t session;
120
AvahiSimplePoll *simple_poll;
85
122
gnutls_certificate_credentials_t cred;
123
unsigned int dh_bits;
86
124
gnutls_dh_params_t dh_params;
90
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
91
char **new_packet, const char *homedir){
92
gpgme_data_t dh_crypto, dh_plain;
125
const char *priority;
130
* Make room in "buffer" for at least BUFFER_SIZE additional bytes.
131
* "buffer_capacity" is how much is currently allocated,
132
* "buffer_length" is how much is already used.
134
size_t adjustbuffer(char **buffer, size_t buffer_length,
135
size_t buffer_capacity){
136
if(buffer_length + BUFFER_SIZE > buffer_capacity){
137
*buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
141
buffer_capacity += BUFFER_SIZE;
143
return buffer_capacity;
149
static bool init_gpgme(mandos_context *mc, const char *seckey,
150
const char *pubkey, const char *tempdir){
96
ssize_t new_packet_capacity = 0;
97
ssize_t new_packet_length = 0;
98
153
gpgme_engine_info_t engine_info;
101
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
157
* Helper function to insert pub and seckey to the enigne keyring.
159
bool import_key(const char *filename){
161
gpgme_data_t pgp_data;
163
fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
169
rc = gpgme_data_new_from_fd(&pgp_data, fd);
170
if(rc != GPG_ERR_NO_ERROR){
171
fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
172
gpgme_strsource(rc), gpgme_strerror(rc));
176
rc = gpgme_op_import(mc->ctx, pgp_data);
177
if(rc != GPG_ERR_NO_ERROR){
178
fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
179
gpgme_strsource(rc), gpgme_strerror(rc));
183
ret = (int)TEMP_FAILURE_RETRY(close(fd));
187
gpgme_data_release(pgp_data);
192
fprintf(stderr, "Initialize gpgme\n");
105
196
gpgme_check_version(NULL);
106
gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
197
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
198
if(rc != GPG_ERR_NO_ERROR){
199
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
200
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){
204
/* Set GPGME home directory for the OpenPGP engine only */
205
rc = gpgme_get_engine_info(&engine_info);
206
if(rc != GPG_ERR_NO_ERROR){
111
207
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
112
208
gpgme_strsource(rc), gpgme_strerror(rc));
115
211
while(engine_info != NULL){
116
212
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
117
213
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
118
engine_info->file_name, homedir);
214
engine_info->file_name, tempdir);
121
217
engine_info = engine_info->next;
123
219
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){
220
fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
224
/* Create new GPGME "context" */
225
rc = gpgme_new(&(mc->ctx));
226
if(rc != GPG_ERR_NO_ERROR){
227
fprintf(stderr, "bad gpgme_new: %s: %s\n",
228
gpgme_strsource(rc), gpgme_strerror(rc));
232
if(not import_key(pubkey) or not import_key(seckey)){
240
* Decrypt OpenPGP data.
241
* Returns -1 on error
243
static ssize_t pgp_packet_decrypt(const mandos_context *mc,
244
const char *cryptotext,
247
gpgme_data_t dh_crypto, dh_plain;
250
size_t plaintext_capacity = 0;
251
ssize_t plaintext_length = 0;
254
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
257
/* Create new GPGME data buffer from memory cryptotext */
258
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
260
if(rc != GPG_ERR_NO_ERROR){
131
261
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
132
262
gpgme_strsource(rc), gpgme_strerror(rc));
136
266
/* Create new empty GPGME data buffer for the plaintext */
137
267
rc = gpgme_data_new(&dh_plain);
138
if (rc != GPG_ERR_NO_ERROR){
268
if(rc != GPG_ERR_NO_ERROR){
139
269
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
140
270
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){
271
gpgme_data_release(dh_crypto);
275
/* Decrypt data from the cryptotext data buffer to the plaintext
277
rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
278
if(rc != GPG_ERR_NO_ERROR){
156
279
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
157
280
gpgme_strsource(rc), gpgme_strerror(rc));
281
plaintext_length = -1;
283
gpgme_decrypt_result_t result;
284
result = gpgme_op_decrypt_result(mc->ctx);
286
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
288
fprintf(stderr, "Unsupported algorithm: %s\n",
289
result->unsupported_algorithm);
290
fprintf(stderr, "Wrong key usage: %u\n",
291
result->wrong_key_usage);
292
if(result->file_name != NULL){
293
fprintf(stderr, "File name: %s\n", result->file_name);
295
gpgme_recipient_t recipient;
296
recipient = result->recipients;
298
while(recipient != NULL){
299
fprintf(stderr, "Public key algorithm: %s\n",
300
gpgme_pubkey_algo_name(recipient->pubkey_algo));
301
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
302
fprintf(stderr, "Secret key available: %s\n",
303
recipient->status == GPG_ERR_NO_SECKEY
305
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);
314
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
197
317
/* Seek back to the beginning of the GPGME plaintext data buffer */
198
gpgme_data_seek(dh_plain, 0, SEEK_SET);
318
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
319
perror("gpgme_data_seek");
320
plaintext_length = -1;
202
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
203
*new_packet = realloc(*new_packet,
204
(unsigned int)new_packet_capacity
206
if (*new_packet == NULL){
210
new_packet_capacity += BUFFER_SIZE;
326
plaintext_capacity = adjustbuffer(plaintext,
327
(size_t)plaintext_length,
329
if(plaintext_capacity == 0){
330
perror("adjustbuffer");
331
plaintext_length = -1;
213
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
335
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
215
337
/* Print the data, if any */
220
343
perror("gpgme_data_read");
223
new_packet_length += ret;
226
/* FIXME: check characters before printing to screen so to not print
227
terminal control characters */
229
/* fprintf(stderr, "decrypted password is: "); */
230
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
231
/* fprintf(stderr, "\n"); */
344
plaintext_length = -1;
347
plaintext_length += ret;
351
fprintf(stderr, "Decrypted password is: ");
352
for(ssize_t i = 0; i < plaintext_length; i++){
353
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
355
fprintf(stderr, "\n");
360
/* Delete the GPGME cryptotext data buffer */
361
gpgme_data_release(dh_crypto);
234
363
/* Delete the GPGME plaintext data buffer */
235
364
gpgme_data_release(dh_plain);
236
return new_packet_length;
365
return plaintext_length;
239
static const char * safer_gnutls_strerror (int value) {
240
const char *ret = gnutls_strerror (value);
368
static const char * safer_gnutls_strerror(int value) {
369
const char *ret = gnutls_strerror(value); /* Spurious warning from
370
-Wunreachable-code */
242
372
ret = "(unknown)";
246
void debuggnutls(__attribute__((unused)) int level,
248
fprintf(stderr, "%s", string);
376
/* GnuTLS log function callback */
377
static void debuggnutls(__attribute__((unused)) int level,
379
fprintf(stderr, "GnuTLS: %s", string);
251
int initgnutls(encrypted_session *es){
382
static int init_gnutls_global(mandos_context *mc,
383
const char *pubkeyfilename,
384
const char *seckeyfilename){
256
388
fprintf(stderr, "Initializing GnuTLS\n");
259
if ((ret = gnutls_global_init ())
260
!= GNUTLS_E_SUCCESS) {
261
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
391
ret = gnutls_global_init();
392
if(ret != GNUTLS_E_SUCCESS) {
393
fprintf(stderr, "GnuTLS global_init: %s\n",
394
safer_gnutls_strerror(ret));
399
/* "Use a log level over 10 to enable all debugging options."
266
402
gnutls_global_set_log_level(11);
267
403
gnutls_global_set_log_function(debuggnutls);
270
/* openpgp credentials */
271
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
272
!= GNUTLS_E_SUCCESS) {
273
fprintf (stderr, "memory error: %s\n",
274
safer_gnutls_strerror(ret));
406
/* OpenPGP credentials */
407
gnutls_certificate_allocate_credentials(&mc->cred);
408
if(ret != GNUTLS_E_SUCCESS){
409
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
413
safer_gnutls_strerror(ret));
414
gnutls_global_deinit();
279
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
280
" and keyfile %s as GnuTLS credentials\n", CERTFILE,
419
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
420
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
284
424
ret = gnutls_certificate_set_openpgp_key_file
285
(es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
286
if (ret != GNUTLS_E_SUCCESS) {
288
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
290
ret, CERTFILE, KEYFILE);
291
fprintf(stdout, "The Error is: %s\n",
292
safer_gnutls_strerror(ret));
296
//GnuTLS server initialization
297
if ((ret = gnutls_dh_params_init (&es->dh_params))
298
!= GNUTLS_E_SUCCESS) {
299
fprintf (stderr, "Error in dh parameter initialization: %s\n",
300
safer_gnutls_strerror(ret));
304
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
305
!= GNUTLS_E_SUCCESS) {
306
fprintf (stderr, "Error in prime generation: %s\n",
307
safer_gnutls_strerror(ret));
311
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
313
// GnuTLS session creation
314
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
315
!= GNUTLS_E_SUCCESS){
425
(mc->cred, pubkeyfilename, seckeyfilename,
426
GNUTLS_OPENPGP_FMT_BASE64);
427
if(ret != GNUTLS_E_SUCCESS) {
429
"Error[%d] while reading the OpenPGP key pair ('%s',"
430
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
431
fprintf(stderr, "The GnuTLS error is: %s\n",
432
safer_gnutls_strerror(ret));
436
/* GnuTLS server initialization */
437
ret = gnutls_dh_params_init(&mc->dh_params);
438
if(ret != GNUTLS_E_SUCCESS) {
439
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
440
" %s\n", safer_gnutls_strerror(ret));
443
ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
444
if(ret != GNUTLS_E_SUCCESS) {
445
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
446
safer_gnutls_strerror(ret));
450
gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
456
gnutls_certificate_free_credentials(mc->cred);
457
gnutls_global_deinit();
458
gnutls_dh_params_deinit(mc->dh_params);
462
static int init_gnutls_session(mandos_context *mc,
463
gnutls_session_t *session){
465
/* GnuTLS session creation */
466
ret = gnutls_init(session, GNUTLS_SERVER);
467
if(ret != GNUTLS_E_SUCCESS){
316
468
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
317
469
safer_gnutls_strerror(ret));
320
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
321
!= GNUTLS_E_SUCCESS) {
322
fprintf(stderr, "Syntax error at: %s\n", err);
323
fprintf(stderr, "GnuTLS error: %s\n",
324
safer_gnutls_strerror(ret));
474
ret = gnutls_priority_set_direct(*session, mc->priority, &err);
475
if(ret != GNUTLS_E_SUCCESS) {
476
fprintf(stderr, "Syntax error at: %s\n", err);
477
fprintf(stderr, "GnuTLS error: %s\n",
478
safer_gnutls_strerror(ret));
479
gnutls_deinit(*session);
328
if ((ret = gnutls_credentials_set
329
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
330
!= GNUTLS_E_SUCCESS) {
331
fprintf(stderr, "Error setting a credentials set: %s\n",
484
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
486
if(ret != GNUTLS_E_SUCCESS) {
487
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
332
488
safer_gnutls_strerror(ret));
489
gnutls_deinit(*session);
336
493
/* ignore client certificate if any. */
337
gnutls_certificate_server_set_request (es->session,
494
gnutls_certificate_server_set_request(*session,
340
gnutls_dh_set_prime_bits (es->session, DH_BITS);
497
gnutls_dh_set_prime_bits(*session, mc->dh_bits);
345
void empty_log(__attribute__((unused)) AvahiLogLevel level,
346
__attribute__((unused)) const char *txt){}
502
/* Avahi log function callback */
503
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
504
__attribute__((unused)) const char *txt){}
348
int start_mandos_communication(char *ip, uint16_t port,
349
unsigned int if_index){
506
/* Called when a Mandos server is found */
507
static int start_mandos_communication(const char *ip, uint16_t port,
508
AvahiIfIndex if_index,
351
struct sockaddr_in6 to;
352
encrypted_session es;
512
union { struct sockaddr in; struct sockaddr_in6 in6; } to;
353
513
char *buffer = NULL;
354
514
char *decrypted_buffer;
355
515
size_t buffer_length = 0;
356
516
size_t buffer_capacity = 0;
357
517
ssize_t decrypted_buffer_size;
359
520
char interface[IF_NAMESIZE];
521
gnutls_session_t session;
523
ret = init_gnutls_session(mc, &session);
362
fprintf(stderr, "Setting up a tcp connection to %s\n", ip);
529
fprintf(stderr, "Setting up a tcp connection to %s, port %" PRIu16
365
533
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
371
if(if_indextoname(if_index, interface) == NULL){
540
if(if_indextoname((unsigned int)if_index, interface) == NULL){
373
541
perror("if_indextoname");
379
544
fprintf(stderr, "Binding to interface %s\n", interface);
382
ret = setsockopt(tcp_sd, SOL_SOCKET, SO_BINDTODEVICE, interface, 5);
384
perror("setsockopt bindtodevice");
388
memset(&to,0,sizeof(to));
389
to.sin6_family = AF_INET6;
390
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
547
memset(&to, 0, sizeof(to));
548
to.in6.sin6_family = AF_INET6;
549
/* It would be nice to have a way to detect if we were passed an
550
IPv4 address here. Now we assume an IPv6 address. */
551
ret = inet_pton(AF_INET6, ip, &to.in6.sin6_addr);
392
553
perror("inet_pton");
396
557
fprintf(stderr, "Bad address: %s\n", ip);
399
/* Spurious warnings for the next line, see for instance
400
<http://bugs.debian.org/488884> */
401
to.sin6_port = htons(port);
560
to.in6.sin6_port = htons(port); /* Spurious warnings from
562
-Wunreachable-code */
403
to.sin6_scope_id = (uint32_t)if_index;
564
to.in6.sin6_scope_id = (uint32_t)if_index;
406
fprintf(stderr, "Connection to: %s\n", ip);
567
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
569
char addrstr[INET6_ADDRSTRLEN] = "";
570
if(inet_ntop(to.in6.sin6_family, &(to.in6.sin6_addr), addrstr,
571
sizeof(addrstr)) == NULL){
574
if(strcmp(addrstr, ip) != 0){
575
fprintf(stderr, "Canonical address form: %s\n", addrstr);
409
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
580
ret = connect(tcp_sd, &to.in, sizeof(to));
411
582
perror("connect");
415
ret = initgnutls (&es);
586
const char *out = mandos_protocol_version;
589
size_t out_size = strlen(out);
590
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
591
out_size - written));
597
written += (size_t)ret;
598
if(written < out_size){
601
if(out == mandos_protocol_version){
421
gnutls_transport_set_ptr (es.session,
422
(gnutls_transport_ptr_t) tcp_sd);
425
611
fprintf(stderr, "Establishing TLS session with %s\n", ip);
428
ret = gnutls_handshake (es.session);
430
if (ret != GNUTLS_E_SUCCESS){
431
fprintf(stderr, "\n*** Handshake failed ***\n");
614
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
617
ret = gnutls_handshake(session);
618
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
620
if(ret != GNUTLS_E_SUCCESS){
622
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
437
//Retrieve OpenPGP packet that contains the wanted password
629
/* Read OpenPGP packet that contains the wanted password */
440
632
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
445
if (buffer_length + BUFFER_SIZE > buffer_capacity){
446
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
451
buffer_capacity += BUFFER_SIZE;
637
buffer_capacity = adjustbuffer(&buffer, buffer_length,
639
if(buffer_capacity == 0){
640
perror("adjustbuffer");
454
ret = gnutls_record_recv
455
(es.session, buffer+buffer_length, BUFFER_SIZE);
645
sret = gnutls_record_recv(session, buffer+buffer_length,
461
652
case GNUTLS_E_INTERRUPTED:
462
653
case GNUTLS_E_AGAIN:
464
655
case GNUTLS_E_REHANDSHAKE:
465
ret = gnutls_handshake (es.session);
467
fprintf(stderr, "\n*** Handshake failed ***\n");
657
ret = gnutls_handshake(session);
658
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
660
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
474
667
fprintf(stderr, "Unknown error while reading data from"
475
" encrypted session with mandos server\n");
668
" encrypted session with Mandos server\n");
477
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
670
gnutls_bye(session, GNUTLS_SHUT_RDWR);
481
buffer_length += (size_t) ret;
674
buffer_length += (size_t) sret;
485
if (buffer_length > 0){
486
decrypted_buffer_size = pgp_packet_decrypt(buffer,
679
fprintf(stderr, "Closing TLS session\n");
682
gnutls_bye(session, GNUTLS_SHUT_RDWR);
684
if(buffer_length > 0){
685
decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
490
if (decrypted_buffer_size >= 0){
491
while(decrypted_buffer_size > 0){
492
ret = fwrite (decrypted_buffer, 1, (size_t)decrypted_buffer_size,
688
if(decrypted_buffer_size >= 0){
690
while(written < (size_t) decrypted_buffer_size){
691
ret = (int)fwrite(decrypted_buffer + written, 1,
692
(size_t)decrypted_buffer_size - written,
494
694
if(ret == 0 and ferror(stdout)){
496
696
fprintf(stderr, "Error writing encrypted data: %s\n",
502
decrypted_buffer += ret;
503
decrypted_buffer_size -= ret;
702
written += (size_t)ret;
505
704
free(decrypted_buffer);
514
fprintf(stderr, "Closing TLS session\n");
712
/* Shutdown procedure */
518
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
521
gnutls_deinit (es.session);
522
gnutls_certificate_free_credentials (es.cred);
523
gnutls_global_deinit ();
716
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
720
gnutls_deinit(session);
527
static AvahiSimplePoll *simple_poll = NULL;
528
static AvahiServer *server = NULL;
530
static void resolve_callback(
531
AvahiSServiceResolver *r,
532
AVAHI_GCC_UNUSED AvahiIfIndex interface,
533
AVAHI_GCC_UNUSED AvahiProtocol protocol,
534
AvahiResolverEvent event,
538
const char *host_name,
539
const AvahiAddress *address,
541
AVAHI_GCC_UNUSED AvahiStringList *txt,
542
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
543
AVAHI_GCC_UNUSED void* userdata) {
724
static void resolve_callback(AvahiSServiceResolver *r,
725
AvahiIfIndex interface,
726
AVAHI_GCC_UNUSED AvahiProtocol protocol,
727
AvahiResolverEvent event,
731
const char *host_name,
732
const AvahiAddress *address,
734
AVAHI_GCC_UNUSED AvahiStringList *txt,
735
AVAHI_GCC_UNUSED AvahiLookupResultFlags
738
mandos_context *mc = userdata;
547
741
/* Called whenever a service has been resolved successfully or
552
746
case AVAHI_RESOLVER_FAILURE:
553
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
554
" type '%s' in domain '%s': %s\n", name, type, domain,
555
avahi_strerror(avahi_server_errno(server)));
747
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
748
" of type '%s' in domain '%s': %s\n", name, type, domain,
749
avahi_strerror(avahi_server_errno(mc->server)));
558
752
case AVAHI_RESOLVER_FOUND:
560
754
char ip[AVAHI_ADDRESS_STR_MAX];
561
755
avahi_address_snprint(ip, sizeof(ip), address);
563
fprintf(stderr, "Mandos server found on %s (%s) on port %d\n",
564
host_name, ip, port);
757
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
758
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
759
ip, (intmax_t)interface, port);
566
int ret = start_mandos_communication(ip, port,
761
int ret = start_mandos_communication(ip, port, interface, mc);
763
avahi_simple_poll_quit(mc->simple_poll);
576
767
avahi_s_service_resolver_free(r);
579
static void browse_callback(
580
AvahiSServiceBrowser *b,
581
AvahiIfIndex interface,
582
AvahiProtocol protocol,
583
AvahiBrowserEvent event,
587
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
590
AvahiServer *s = userdata;
593
/* Called whenever a new services becomes available on the LAN or
594
is removed from the LAN */
598
case AVAHI_BROWSER_FAILURE:
600
fprintf(stderr, "(Browser) %s\n",
601
avahi_strerror(avahi_server_errno(server)));
602
avahi_simple_poll_quit(simple_poll);
605
case AVAHI_BROWSER_NEW:
606
/* We ignore the returned resolver object. In the callback
607
function we free it. If the server is terminated before
608
the callback function is called the server will free
609
the resolver for us. */
611
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
613
AVAHI_PROTO_INET6, 0,
614
resolve_callback, s)))
615
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
616
avahi_strerror(avahi_server_errno(s)));
619
case AVAHI_BROWSER_REMOVE:
622
case AVAHI_BROWSER_ALL_FOR_NOW:
623
case AVAHI_BROWSER_CACHE_EXHAUSTED:
770
static void browse_callback( AvahiSServiceBrowser *b,
771
AvahiIfIndex interface,
772
AvahiProtocol protocol,
773
AvahiBrowserEvent event,
777
AVAHI_GCC_UNUSED AvahiLookupResultFlags
780
mandos_context *mc = userdata;
783
/* Called whenever a new services becomes available on the LAN or
784
is removed from the LAN */
788
case AVAHI_BROWSER_FAILURE:
790
fprintf(stderr, "(Avahi browser) %s\n",
791
avahi_strerror(avahi_server_errno(mc->server)));
792
avahi_simple_poll_quit(mc->simple_poll);
795
case AVAHI_BROWSER_NEW:
796
/* We ignore the returned Avahi resolver object. In the callback
797
function we free it. If the Avahi server is terminated before
798
the callback function is called the Avahi server will free the
801
if(!(avahi_s_service_resolver_new(mc->server, interface,
802
protocol, name, type, domain,
803
AVAHI_PROTO_INET6, 0,
804
resolve_callback, mc)))
805
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
806
name, avahi_strerror(avahi_server_errno(mc->server)));
809
case AVAHI_BROWSER_REMOVE:
812
case AVAHI_BROWSER_ALL_FOR_NOW:
813
case AVAHI_BROWSER_CACHE_EXHAUSTED:
815
fprintf(stderr, "No Mandos server found, still searching...\n");
628
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
629
AvahiServerConfig config;
821
int main(int argc, char *argv[]){
630
822
AvahiSServiceBrowser *sb = NULL;
633
int returncode = EXIT_SUCCESS;
827
int exitcode = EXIT_SUCCESS;
634
828
const char *interface = "eth0";
637
static struct option long_options[] = {
638
{"debug", no_argument, (int *)&debug, 1},
639
{"interface", required_argument, 0, 'i'},
642
int option_index = 0;
643
ret = getopt_long (argc, argv, "i:", long_options,
829
struct ifreq network;
833
char *connect_to = NULL;
834
char tempdir[] = "/tmp/mandosXXXXXX";
835
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
836
const char *seckey = PATHDIR "/" SECKEY;
837
const char *pubkey = PATHDIR "/" PUBKEY;
839
mandos_context mc = { .simple_poll = NULL, .server = NULL,
840
.dh_bits = 1024, .priority = "SECURE256"
841
":!CTYPE-X.509:+CTYPE-OPENPGP" };
842
bool gnutls_initalized = false;
843
bool gpgme_initalized = false;
847
struct argp_option options[] = {
848
{ .name = "debug", .key = 128,
849
.doc = "Debug mode", .group = 3 },
850
{ .name = "connect", .key = 'c',
851
.arg = "ADDRESS:PORT",
852
.doc = "Connect directly to a specific Mandos server",
854
{ .name = "interface", .key = 'i',
856
.doc = "Interface that will be used to search for Mandos"
859
{ .name = "seckey", .key = 's',
861
.doc = "OpenPGP secret key file base name",
863
{ .name = "pubkey", .key = 'p',
865
.doc = "OpenPGP public key file base name",
867
{ .name = "dh-bits", .key = 129,
869
.doc = "Bit length of the prime number used in the"
870
" Diffie-Hellman key exchange",
872
{ .name = "priority", .key = 130,
874
.doc = "GnuTLS priority string for the TLS handshake",
876
{ .name = "delay", .key = 131,
878
.doc = "Maximum delay to wait for interface startup",
883
error_t parse_opt(int key, char *arg,
884
struct argp_state *state) {
886
case 128: /* --debug */
889
case 'c': /* --connect */
892
case 'i': /* --interface */
895
case 's': /* --seckey */
898
case 'p': /* --pubkey */
901
case 129: /* --dh-bits */
902
ret = sscanf(arg, "%" SCNdMAX "%n", &tmpmax, &numchars);
903
if(ret < 1 or tmpmax != (typeof(mc.dh_bits))tmpmax
904
or arg[numchars] != '\0'){
905
fprintf(stderr, "Bad number of DH bits\n");
908
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
910
case 130: /* --priority */
913
case 131: /* --delay */
914
ret = sscanf(arg, "%lf%n", &delay, &numchars);
915
if(ret < 1 or arg[numchars] != '\0'){
916
fprintf(stderr, "Bad delay\n");
925
return ARGP_ERR_UNKNOWN;
930
struct argp argp = { .options = options, .parser = parse_opt,
932
.doc = "Mandos client -- Get and decrypt"
933
" passwords from a Mandos server" };
934
ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
935
if(ret == ARGP_ERR_UNKNOWN){
936
fprintf(stderr, "Unknown error while parsing arguments\n");
937
exitcode = EXIT_FAILURE;
942
/* If the interface is down, bring it up */
944
// Lower kernel loglevel to KERN_NOTICE to avoid
945
// KERN_INFO messages to mess up the prompt
946
ret = klogctl(8, NULL, 5);
951
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
954
exitcode = EXIT_FAILURE;
955
ret = klogctl(7, NULL, 0);
961
strcpy(network.ifr_name, interface);
962
ret = ioctl(sd, SIOCGIFFLAGS, &network);
964
perror("ioctl SIOCGIFFLAGS");
965
ret = klogctl(7, NULL, 0);
969
exitcode = EXIT_FAILURE;
972
if((network.ifr_flags & IFF_UP) == 0){
973
network.ifr_flags |= IFF_UP;
974
ret = ioctl(sd, SIOCSIFFLAGS, &network);
976
perror("ioctl SIOCSIFFLAGS");
977
exitcode = EXIT_FAILURE;
978
ret = klogctl(7, NULL, 0);
985
// sleep checking until interface is running
986
for(int i=0; i < delay * 4; i++){
987
ret = ioctl(sd, SIOCGIFFLAGS, &network);
989
perror("ioctl SIOCGIFFLAGS");
990
} else if(network.ifr_flags & IFF_RUNNING){
993
struct timespec sleeptime = { .tv_nsec = 250000000 };
994
nanosleep(&sleeptime, NULL);
996
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1000
// Restores kernel loglevel to default
1001
ret = klogctl(7, NULL, 0);
1020
ret = init_gnutls_global(&mc, pubkey, seckey);
1022
fprintf(stderr, "init_gnutls_global failed\n");
1023
exitcode = EXIT_FAILURE;
1026
gnutls_initalized = true;
1029
if(mkdtemp(tempdir) == NULL){
1035
if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
1036
fprintf(stderr, "gpgme_initalized failed\n");
1037
exitcode = EXIT_FAILURE;
1040
gpgme_initalized = true;
1043
if_index = (AvahiIfIndex) if_nametoindex(interface);
1045
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1049
if(connect_to != NULL){
1050
/* Connect directly, do not use Zeroconf */
1051
/* (Mainly meant for debugging) */
1052
char *address = strrchr(connect_to, ':');
1053
if(address == NULL){
1054
fprintf(stderr, "No colon in address\n");
1055
exitcode = EXIT_FAILURE;
1059
ret = sscanf(address+1, "%" SCNdMAX "%n", &tmpmax, &numchars);
1060
if(ret < 1 or tmpmax != (uint16_t)tmpmax
1061
or address[numchars+1] != '\0'){
1062
fprintf(stderr, "Bad port number\n");
1063
exitcode = EXIT_FAILURE;
1066
port = (uint16_t)tmpmax;
1068
address = connect_to;
1069
ret = start_mandos_communication(address, port, if_index, &mc);
1071
exitcode = EXIT_FAILURE;
1073
exitcode = EXIT_SUCCESS;
662
1079
avahi_set_log_function(empty_log);
665
/* Initialize the psuedo-RNG */
1082
/* Initialize the pseudo-RNG for Avahi */
666
1083
srand((unsigned int) time(NULL));
668
/* Allocate main loop object */
669
if (!(simple_poll = avahi_simple_poll_new())) {
670
fprintf(stderr, "Failed to create simple poll object.\n");
675
/* Do not publish any local records */
676
avahi_server_config_init(&config);
677
config.publish_hinfo = 0;
678
config.publish_addresses = 0;
679
config.publish_workstation = 0;
680
config.publish_domain = 0;
682
/* Allocate a new server */
683
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
684
&config, NULL, NULL, &error);
686
/* Free the configuration data */
687
avahi_server_config_free(&config);
689
/* Check if creating the server object succeeded */
691
fprintf(stderr, "Failed to create server: %s\n",
1085
/* Allocate main Avahi loop object */
1086
mc.simple_poll = avahi_simple_poll_new();
1087
if(mc.simple_poll == NULL) {
1088
fprintf(stderr, "Avahi: Failed to create simple poll"
1090
exitcode = EXIT_FAILURE;
1095
AvahiServerConfig config;
1096
/* Do not publish any local Zeroconf records */
1097
avahi_server_config_init(&config);
1098
config.publish_hinfo = 0;
1099
config.publish_addresses = 0;
1100
config.publish_workstation = 0;
1101
config.publish_domain = 0;
1103
/* Allocate a new server */
1104
mc.server = avahi_server_new(avahi_simple_poll_get
1105
(mc.simple_poll), &config, NULL,
1108
/* Free the Avahi configuration data */
1109
avahi_server_config_free(&config);
1112
/* Check if creating the Avahi server object succeeded */
1113
if(mc.server == NULL) {
1114
fprintf(stderr, "Failed to create Avahi server: %s\n",
692
1115
avahi_strerror(error));
693
returncode = EXIT_FAILURE;
1116
exitcode = EXIT_FAILURE;
697
/* Create the service browser */
698
sb = avahi_s_service_browser_new(server,
700
if_nametoindex(interface),
1120
/* Create the Avahi service browser */
1121
sb = avahi_s_service_browser_new(mc.server, if_index,
701
1122
AVAHI_PROTO_INET6,
702
1123
"_mandos._tcp", NULL, 0,
703
browse_callback, server);
1124
browse_callback, &mc);
705
1126
fprintf(stderr, "Failed to create service browser: %s\n",
706
avahi_strerror(avahi_server_errno(server)));
707
returncode = EXIT_FAILURE;
1127
avahi_strerror(avahi_server_errno(mc.server)));
1128
exitcode = EXIT_FAILURE;
711
1132
/* Run the main loop */
714
fprintf(stderr, "Starting avahi loop search\n");
1135
fprintf(stderr, "Starting Avahi loop search\n");
717
avahi_simple_poll_loop(simple_poll);
1138
avahi_simple_poll_loop(mc.simple_poll);
722
1143
fprintf(stderr, "%s exiting\n", argv[0]);
725
1146
/* Cleanup things */
727
1148
avahi_s_service_browser_free(sb);
730
avahi_server_free(server);
733
avahi_simple_poll_free(simple_poll);
1150
if(mc.server != NULL)
1151
avahi_server_free(mc.server);
1153
if(mc.simple_poll != NULL)
1154
avahi_simple_poll_free(mc.simple_poll);
1156
if(gnutls_initalized){
1157
gnutls_certificate_free_credentials(mc.cred);
1158
gnutls_global_deinit();
1159
gnutls_dh_params_deinit(mc.dh_params);
1162
if(gpgme_initalized){
1163
gpgme_release(mc.ctx);
1166
/* Removes the temp directory used by GPGME */
1167
if(tempdir[0] != '\0'){
1169
struct dirent *direntry;
1170
d = opendir(tempdir);
1172
if(errno != ENOENT){
1177
direntry = readdir(d);
1178
if(direntry == NULL){
1181
if(direntry->d_type == DT_REG){
1182
char *fullname = NULL;
1183
ret = asprintf(&fullname, "%s/%s", tempdir,
1189
ret = unlink(fullname);
1191
fprintf(stderr, "unlink(\"%s\"): %s",
1192
fullname, strerror(errno));
1199
ret = rmdir(tempdir);
1200
if(ret == -1 and errno != ENOENT){