101
202
return buffer_capacity;
104
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
106
const char *homedir){
107
gpgme_data_t dh_crypto, dh_plain;
205
/* Add server to set of servers to retry periodically */
206
bool add_server(const char *ip, uint16_t port, AvahiIfIndex if_index,
209
server *new_server = malloc(sizeof(server));
210
if(new_server == NULL){
211
perror_plus("malloc");
214
*new_server = (server){ .ip = strdup(ip),
216
.if_index = if_index,
218
if(new_server->ip == NULL){
219
perror_plus("strdup");
222
/* Special case of first server */
223
if (mc.current_server == NULL){
224
new_server->next = new_server;
225
new_server->prev = new_server;
226
mc.current_server = new_server;
227
/* Place the new server last in the list */
229
new_server->next = mc.current_server;
230
new_server->prev = mc.current_server->prev;
231
new_server->prev->next = new_server;
232
mc.current_server->prev = new_server;
234
ret = clock_gettime(CLOCK_MONOTONIC, &mc.current_server->last_seen);
236
perror_plus("clock_gettime");
245
static bool init_gpgme(const char *seckey, const char *pubkey,
246
const char *tempdir){
109
247
gpgme_error_t rc;
111
size_t new_packet_capacity = 0;
112
ssize_t new_packet_length = 0;
113
248
gpgme_engine_info_t engine_info;
116
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
252
* Helper function to insert pub and seckey to the engine keyring.
254
bool import_key(const char *filename){
257
gpgme_data_t pgp_data;
259
fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
265
rc = gpgme_data_new_from_fd(&pgp_data, fd);
266
if(rc != GPG_ERR_NO_ERROR){
267
fprintf_plus(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
268
gpgme_strsource(rc), gpgme_strerror(rc));
272
rc = gpgme_op_import(mc.ctx, pgp_data);
273
if(rc != GPG_ERR_NO_ERROR){
274
fprintf_plus(stderr, "bad gpgme_op_import: %s: %s\n",
275
gpgme_strsource(rc), gpgme_strerror(rc));
279
ret = (int)TEMP_FAILURE_RETRY(close(fd));
281
perror_plus("close");
283
gpgme_data_release(pgp_data);
288
fprintf_plus(stderr, "Initializing GPGME\n");
120
292
gpgme_check_version(NULL);
121
293
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
122
if (rc != GPG_ERR_NO_ERROR){
123
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
124
gpgme_strsource(rc), gpgme_strerror(rc));
294
if(rc != GPG_ERR_NO_ERROR){
295
fprintf_plus(stderr, "bad gpgme_engine_check_version: %s: %s\n",
296
gpgme_strsource(rc), gpgme_strerror(rc));
128
/* Set GPGME home directory */
129
rc = gpgme_get_engine_info (&engine_info);
130
if (rc != GPG_ERR_NO_ERROR){
131
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
132
gpgme_strsource(rc), gpgme_strerror(rc));
300
/* Set GPGME home directory for the OpenPGP engine only */
301
rc = gpgme_get_engine_info(&engine_info);
302
if(rc != GPG_ERR_NO_ERROR){
303
fprintf_plus(stderr, "bad gpgme_get_engine_info: %s: %s\n",
304
gpgme_strsource(rc), gpgme_strerror(rc));
135
307
while(engine_info != NULL){
136
308
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
137
309
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
138
engine_info->file_name, homedir);
310
engine_info->file_name, tempdir);
141
313
engine_info = engine_info->next;
143
315
if(engine_info == NULL){
144
fprintf(stderr, "Could not set home dir to %s\n", homedir);
148
/* Create new GPGME data buffer from packet buffer */
149
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
150
if (rc != GPG_ERR_NO_ERROR){
151
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
152
gpgme_strsource(rc), gpgme_strerror(rc));
316
fprintf_plus(stderr, "Could not set GPGME home dir to %s\n",
321
/* Create new GPGME "context" */
322
rc = gpgme_new(&(mc.ctx));
323
if(rc != GPG_ERR_NO_ERROR){
324
fprintf_plus(stderr, "Mandos plugin mandos-client: "
325
"bad gpgme_new: %s: %s\n", gpgme_strsource(rc),
330
if(not import_key(pubkey) or not import_key(seckey)){
338
* Decrypt OpenPGP data.
339
* Returns -1 on error
341
static ssize_t pgp_packet_decrypt(const char *cryptotext,
344
gpgme_data_t dh_crypto, dh_plain;
347
size_t plaintext_capacity = 0;
348
ssize_t plaintext_length = 0;
351
fprintf_plus(stderr, "Trying to decrypt OpenPGP data\n");
354
/* Create new GPGME data buffer from memory cryptotext */
355
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
357
if(rc != GPG_ERR_NO_ERROR){
358
fprintf_plus(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
359
gpgme_strsource(rc), gpgme_strerror(rc));
156
363
/* Create new empty GPGME data buffer for the plaintext */
157
364
rc = gpgme_data_new(&dh_plain);
158
if (rc != GPG_ERR_NO_ERROR){
159
fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
160
gpgme_strsource(rc), gpgme_strerror(rc));
164
/* Create new GPGME "context" */
165
rc = gpgme_new(&ctx);
166
if (rc != GPG_ERR_NO_ERROR){
167
fprintf(stderr, "bad gpgme_new: %s: %s\n",
168
gpgme_strsource(rc), gpgme_strerror(rc));
172
/* Decrypt data from the FILE pointer to the plaintext data
174
rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
175
if (rc != GPG_ERR_NO_ERROR){
176
fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
177
gpgme_strsource(rc), gpgme_strerror(rc));
182
fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
186
gpgme_decrypt_result_t result;
187
result = gpgme_op_decrypt_result(ctx);
189
fprintf(stderr, "gpgme_op_decrypt_result failed\n");
191
fprintf(stderr, "Unsupported algorithm: %s\n",
192
result->unsupported_algorithm);
193
fprintf(stderr, "Wrong key usage: %d\n",
194
result->wrong_key_usage);
195
if(result->file_name != NULL){
196
fprintf(stderr, "File name: %s\n", result->file_name);
198
gpgme_recipient_t recipient;
199
recipient = result->recipients;
365
if(rc != GPG_ERR_NO_ERROR){
366
fprintf_plus(stderr, "Mandos plugin mandos-client: "
367
"bad gpgme_data_new: %s: %s\n",
368
gpgme_strsource(rc), gpgme_strerror(rc));
369
gpgme_data_release(dh_crypto);
373
/* Decrypt data from the cryptotext data buffer to the plaintext
375
rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
376
if(rc != GPG_ERR_NO_ERROR){
377
fprintf_plus(stderr, "bad gpgme_op_decrypt: %s: %s\n",
378
gpgme_strsource(rc), gpgme_strerror(rc));
379
plaintext_length = -1;
381
gpgme_decrypt_result_t result;
382
result = gpgme_op_decrypt_result(mc.ctx);
384
fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
386
fprintf_plus(stderr, "Unsupported algorithm: %s\n",
387
result->unsupported_algorithm);
388
fprintf_plus(stderr, "Wrong key usage: %u\n",
389
result->wrong_key_usage);
390
if(result->file_name != NULL){
391
fprintf_plus(stderr, "File name: %s\n", result->file_name);
393
gpgme_recipient_t recipient;
394
recipient = result->recipients;
201
395
while(recipient != NULL){
202
fprintf(stderr, "Public key algorithm: %s\n",
203
gpgme_pubkey_algo_name(recipient->pubkey_algo));
204
fprintf(stderr, "Key ID: %s\n", recipient->keyid);
205
fprintf(stderr, "Secret key available: %s\n",
206
recipient->status == GPG_ERR_NO_SECKEY
396
fprintf_plus(stderr, "Public key algorithm: %s\n",
397
gpgme_pubkey_algo_name
398
(recipient->pubkey_algo));
399
fprintf_plus(stderr, "Key ID: %s\n", recipient->keyid);
400
fprintf_plus(stderr, "Secret key available: %s\n",
401
recipient->status == GPG_ERR_NO_SECKEY
208
403
recipient = recipient->next;
214
/* Delete the GPGME FILE pointer cryptotext data buffer */
215
gpgme_data_release(dh_crypto);
411
fprintf_plus(stderr, "Decryption of OpenPGP data succeeded\n");
217
414
/* Seek back to the beginning of the GPGME plaintext data buffer */
218
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
219
perror("pgpme_data_seek");
415
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
416
perror_plus("gpgme_data_seek");
417
plaintext_length = -1;
224
new_packet_capacity = adjustbuffer(*new_packet, new_packet_length,
225
new_packet_capacity);
226
if (new_packet_capacity == 0){
227
perror("adjustbuffer");
230
new_packet_capacity += BUFFER_SIZE;
423
plaintext_capacity = incbuffer(plaintext,
424
(size_t)plaintext_length,
426
if(plaintext_capacity == 0){
427
perror_plus("incbuffer");
428
plaintext_length = -1;
233
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
432
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
235
434
/* Print the data, if any */
240
perror("gpgme_data_read");
243
new_packet_length += ret;
246
/* FIXME: check characters before printing to screen so to not print
247
terminal control characters */
249
/* fprintf(stderr, "decrypted password is: "); */
250
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
251
/* fprintf(stderr, "\n"); */
440
perror_plus("gpgme_data_read");
441
plaintext_length = -1;
444
plaintext_length += ret;
448
fprintf_plus(stderr, "Decrypted password is: ");
449
for(ssize_t i = 0; i < plaintext_length; i++){
450
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
452
fprintf(stderr, "\n");
457
/* Delete the GPGME cryptotext data buffer */
458
gpgme_data_release(dh_crypto);
254
460
/* Delete the GPGME plaintext data buffer */
255
461
gpgme_data_release(dh_plain);
256
return new_packet_length;
462
return plaintext_length;
259
static const char * safer_gnutls_strerror (int value) {
260
const char *ret = gnutls_strerror (value);
465
static const char * safer_gnutls_strerror(int value){
466
const char *ret = gnutls_strerror(value); /* Spurious warning from
467
-Wunreachable-code */
262
469
ret = "(unknown)";
473
/* GnuTLS log function callback */
266
474
static void debuggnutls(__attribute__((unused)) int level,
267
475
const char* string){
268
fprintf(stderr, "%s", string);
476
fprintf_plus(stderr, "GnuTLS: %s", string);
271
static int initgnutls(mandos_context *mc){
479
static int init_gnutls_global(const char *pubkeyfilename,
480
const char *seckeyfilename){
276
fprintf(stderr, "Initializing GnuTLS\n");
484
fprintf_plus(stderr, "Initializing GnuTLS\n");
279
if ((ret = gnutls_global_init ())
280
!= GNUTLS_E_SUCCESS) {
281
fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
487
ret = gnutls_global_init();
488
if(ret != GNUTLS_E_SUCCESS){
489
fprintf_plus(stderr, "GnuTLS global_init: %s\n",
490
safer_gnutls_strerror(ret));
495
/* "Use a log level over 10 to enable all debugging options."
286
498
gnutls_global_set_log_level(11);
287
499
gnutls_global_set_log_function(debuggnutls);
290
/* openpgp credentials */
291
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
292
!= GNUTLS_E_SUCCESS) {
293
fprintf (stderr, "memory error: %s\n",
294
safer_gnutls_strerror(ret));
502
/* OpenPGP credentials */
503
ret = gnutls_certificate_allocate_credentials(&mc.cred);
504
if(ret != GNUTLS_E_SUCCESS){
505
fprintf_plus(stderr, "GnuTLS memory error: %s\n",
506
safer_gnutls_strerror(ret));
507
gnutls_global_deinit();
299
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
300
" and keyfile %s as GnuTLS credentials\n", certfile,
512
fprintf_plus(stderr, "Attempting to use OpenPGP public key %s and"
513
" secret key %s as GnuTLS credentials\n",
304
518
ret = gnutls_certificate_set_openpgp_key_file
305
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
306
if (ret != GNUTLS_E_SUCCESS) {
308
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
310
ret, certfile, certkey);
311
fprintf(stdout, "The Error is: %s\n",
312
safer_gnutls_strerror(ret));
316
//GnuTLS server initialization
317
if ((ret = gnutls_dh_params_init (&es->dh_params))
318
!= GNUTLS_E_SUCCESS) {
319
fprintf (stderr, "Error in dh parameter initialization: %s\n",
320
safer_gnutls_strerror(ret));
324
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
325
!= GNUTLS_E_SUCCESS) {
326
fprintf (stderr, "Error in prime generation: %s\n",
327
safer_gnutls_strerror(ret));
331
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
333
// GnuTLS session creation
334
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
335
!= GNUTLS_E_SUCCESS){
336
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
337
safer_gnutls_strerror(ret));
340
if ((ret = gnutls_priority_set_direct (es->session, mc->priority, &err))
341
!= GNUTLS_E_SUCCESS) {
342
fprintf(stderr, "Syntax error at: %s\n", err);
343
fprintf(stderr, "GnuTLS error: %s\n",
344
safer_gnutls_strerror(ret));
348
if ((ret = gnutls_credentials_set
349
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
350
!= GNUTLS_E_SUCCESS) {
351
fprintf(stderr, "Error setting a credentials set: %s\n",
352
safer_gnutls_strerror(ret));
519
(mc.cred, pubkeyfilename, seckeyfilename,
520
GNUTLS_OPENPGP_FMT_BASE64);
521
if(ret != GNUTLS_E_SUCCESS){
523
"Error[%d] while reading the OpenPGP key pair ('%s',"
524
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
525
fprintf_plus(stderr, "The GnuTLS error is: %s\n",
526
safer_gnutls_strerror(ret));
530
/* GnuTLS server initialization */
531
ret = gnutls_dh_params_init(&mc.dh_params);
532
if(ret != GNUTLS_E_SUCCESS){
533
fprintf_plus(stderr, "Error in GnuTLS DH parameter"
534
" initialization: %s\n",
535
safer_gnutls_strerror(ret));
538
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
539
if(ret != GNUTLS_E_SUCCESS){
540
fprintf_plus(stderr, "Error in GnuTLS prime generation: %s\n",
541
safer_gnutls_strerror(ret));
545
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
551
gnutls_certificate_free_credentials(mc.cred);
552
gnutls_global_deinit();
553
gnutls_dh_params_deinit(mc.dh_params);
557
static int init_gnutls_session(gnutls_session_t *session){
559
/* GnuTLS session creation */
561
ret = gnutls_init(session, GNUTLS_SERVER);
565
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
566
if(ret != GNUTLS_E_SUCCESS){
568
"Error in GnuTLS session initialization: %s\n",
569
safer_gnutls_strerror(ret));
575
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
577
gnutls_deinit(*session);
580
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
581
if(ret != GNUTLS_E_SUCCESS){
582
fprintf_plus(stderr, "Syntax error at: %s\n", err);
583
fprintf_plus(stderr, "GnuTLS error: %s\n",
584
safer_gnutls_strerror(ret));
585
gnutls_deinit(*session);
591
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
594
gnutls_deinit(*session);
597
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
598
if(ret != GNUTLS_E_SUCCESS){
599
fprintf_plus(stderr, "Error setting GnuTLS credentials: %s\n",
600
safer_gnutls_strerror(ret));
601
gnutls_deinit(*session);
356
605
/* ignore client certificate if any. */
357
gnutls_certificate_server_set_request (es->session,
606
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
360
gnutls_dh_set_prime_bits (es->session, DH_BITS);
608
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
613
/* Avahi log function callback */
365
614
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
366
615
__attribute__((unused)) const char *txt){}
617
/* Called when a Mandos server is found */
368
618
static int start_mandos_communication(const char *ip, uint16_t port,
369
619
AvahiIfIndex if_index,
372
struct sockaddr_in6 to;
373
encrypted_session es;
621
int ret, tcp_sd = -1;
624
struct sockaddr_in in;
625
struct sockaddr_in6 in6;
374
627
char *buffer = NULL;
375
char *decrypted_buffer;
628
char *decrypted_buffer = NULL;
376
629
size_t buffer_length = 0;
377
630
size_t buffer_capacity = 0;
378
ssize_t decrypted_buffer_size;
381
char interface[IF_NAMESIZE];
384
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
388
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
395
if(if_indextoname((unsigned int)if_index, interface) == NULL){
397
perror("if_indextoname");
402
fprintf(stderr, "Binding to interface %s\n", interface);
405
memset(&to,0,sizeof(to)); /* Spurious warning */
406
to.sin6_family = AF_INET6;
407
ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
633
gnutls_session_t session;
634
int pf; /* Protocol family */
651
fprintf_plus(stderr, "Bad address family: %d\n", af);
656
ret = init_gnutls_session(&session);
662
fprintf_plus(stderr, "Setting up a TCP connection to %s, port %"
663
PRIu16 "\n", ip, port);
666
tcp_sd = socket(pf, SOCK_STREAM, 0);
669
perror_plus("socket");
679
memset(&to, 0, sizeof(to));
681
to.in6.sin6_family = (sa_family_t)af;
682
ret = inet_pton(af, ip, &to.in6.sin6_addr);
684
to.in.sin_family = (sa_family_t)af;
685
ret = inet_pton(af, ip, &to.in.sin_addr);
689
perror_plus("inet_pton");
413
fprintf(stderr, "Bad address: %s\n", ip);
416
to.sin6_port = htons(port); /* Spurious warning */
695
fprintf_plus(stderr, "Bad address: %s\n", ip);
700
to.in6.sin6_port = htons(port); /* Spurious warnings from
702
-Wunreachable-code */
704
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
705
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
707
if(if_index == AVAHI_IF_UNSPEC){
708
fprintf_plus(stderr, "An IPv6 link-local address is"
709
" incomplete without a network interface\n");
713
/* Set the network interface number as scope */
714
to.in6.sin6_scope_id = (uint32_t)if_index;
717
to.in.sin_port = htons(port); /* Spurious warnings from
719
-Wunreachable-code */
418
to.sin6_scope_id = (uint32_t)if_index;
421
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
422
/* char addrstr[INET6_ADDRSTRLEN]; */
423
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
424
/* sizeof(addrstr)) == NULL){ */
425
/* perror("inet_ntop"); */
427
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
428
/* addrstr, ntohs(to.sin6_port)); */
432
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
438
char *out = mandos_protocol_version;
728
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
729
char interface[IF_NAMESIZE];
730
if(if_indextoname((unsigned int)if_index, interface) == NULL){
731
perror_plus("if_indextoname");
733
fprintf_plus(stderr, "Connection to: %s%%%s, port %" PRIu16
734
"\n", ip, interface, port);
737
fprintf_plus(stderr, "Connection to: %s, port %" PRIu16 "\n",
740
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
741
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
744
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
747
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
751
perror_plus("inet_ntop");
753
if(strcmp(addrstr, ip) != 0){
754
fprintf_plus(stderr, "Canonical address form: %s\n", addrstr);
765
ret = connect(tcp_sd, &to.in6, sizeof(to));
767
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
770
if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
772
perror_plus("connect");
783
const char *out = mandos_protocol_version;
441
786
size_t out_size = strlen(out);
442
ret = TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
443
out_size - written));
787
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
788
out_size - written));
791
perror_plus("write");
795
written += (size_t)ret;
450
796
if(written < out_size){
453
if (out == mandos_protocol_version){
799
if(out == mandos_protocol_version){
462
ret = initgnutls (&es);
468
gnutls_transport_set_ptr (es.session,
469
(gnutls_transport_ptr_t) tcp_sd);
472
fprintf(stderr, "Establishing TLS session with %s\n", ip);
475
ret = gnutls_handshake (es.session);
477
if (ret != GNUTLS_E_SUCCESS){
814
fprintf_plus(stderr, "Establishing TLS session with %s\n", ip);
822
/* Spurious warning from -Wint-to-pointer-cast */
823
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
831
ret = gnutls_handshake(session);
836
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
838
if(ret != GNUTLS_E_SUCCESS){
479
fprintf(stderr, "\n*** Handshake failed ***\n");
840
fprintf_plus(stderr, "*** GnuTLS Handshake failed ***\n");
486
//Retrieve OpenPGP packet that contains the wanted password
847
/* Read OpenPGP packet that contains the wanted password */
489
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
850
fprintf_plus(stderr, "Retrieving OpenPGP encrypted password from"
494
buffer_capacity = adjustbuffer(buffer, buffer_length, buffer_capacity);
495
if (buffer_capacity == 0){
496
perror("adjustbuffer");
501
ret = gnutls_record_recv
502
(es.session, buffer+buffer_length, BUFFER_SIZE);
861
buffer_capacity = incbuffer(&buffer, buffer_length,
863
if(buffer_capacity == 0){
865
perror_plus("incbuffer");
875
sret = gnutls_record_recv(session, buffer+buffer_length,
508
882
case GNUTLS_E_INTERRUPTED:
509
883
case GNUTLS_E_AGAIN:
511
885
case GNUTLS_E_REHANDSHAKE:
512
ret = gnutls_handshake (es.session);
514
fprintf(stderr, "\n*** Handshake failed ***\n");
887
ret = gnutls_handshake(session);
893
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
895
fprintf_plus(stderr, "*** GnuTLS Re-handshake failed "
521
fprintf(stderr, "Unknown error while reading data from"
522
" encrypted session with mandos server\n");
524
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
903
fprintf_plus(stderr, "Unknown error while reading data from"
904
" encrypted session with Mandos server\n");
905
gnutls_bye(session, GNUTLS_SHUT_RDWR);
528
buffer_length += (size_t) ret;
532
if (buffer_length > 0){
533
decrypted_buffer_size = pgp_packet_decrypt(buffer,
537
if (decrypted_buffer_size >= 0){
910
buffer_length += (size_t) sret;
915
fprintf_plus(stderr, "Closing TLS session\n");
924
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
929
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
931
if(buffer_length > 0){
932
ssize_t decrypted_buffer_size;
933
decrypted_buffer_size = pgp_packet_decrypt(buffer, buffer_length,
935
if(decrypted_buffer_size >= 0){
539
938
while(written < (size_t) decrypted_buffer_size){
540
ret = (int)fwrite (decrypted_buffer + written, 1,
541
(size_t)decrypted_buffer_size - written,
944
ret = (int)fwrite(decrypted_buffer + written, 1,
945
(size_t)decrypted_buffer_size - written,
543
947
if(ret == 0 and ferror(stdout)){
545
fprintf(stderr, "Error writing encrypted data: %s\n",
950
fprintf_plus(stderr, "Error writing encrypted data: %s\n",
551
956
written += (size_t)ret;
553
free(decrypted_buffer);
962
/* Shutdown procedure */
967
free(decrypted_buffer);
970
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
976
perror_plus("close");
978
gnutls_deinit(session);
562
fprintf(stderr, "Closing TLS session\n");
566
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
569
gnutls_deinit (es.session);
570
gnutls_certificate_free_credentials (es.cred);
571
gnutls_global_deinit ();
575
static void resolve_callback( AvahiSServiceResolver *r,
576
AvahiIfIndex interface,
577
AVAHI_GCC_UNUSED AvahiProtocol protocol,
578
AvahiResolverEvent event,
582
const char *host_name,
583
const AvahiAddress *address,
585
AVAHI_GCC_UNUSED AvahiStringList *txt,
586
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
587
AVAHI_GCC_UNUSED void* userdata) {
588
mandos_context *mc = userdata;
589
assert(r); /* Spurious warning */
988
static void resolve_callback(AvahiSServiceResolver *r,
989
AvahiIfIndex interface,
991
AvahiResolverEvent event,
995
const char *host_name,
996
const AvahiAddress *address,
998
AVAHI_GCC_UNUSED AvahiStringList *txt,
999
AVAHI_GCC_UNUSED AvahiLookupResultFlags
1001
AVAHI_GCC_UNUSED void* userdata){
591
1004
/* Called whenever a service has been resolved successfully or
596
1013
case AVAHI_RESOLVER_FAILURE:
597
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
598
" type '%s' in domain '%s': %s\n", name, type, domain,
599
avahi_strerror(avahi_server_errno(mc->server)));
1014
fprintf_plus(stderr, "(Avahi Resolver) Failed to resolve service "
1015
"'%s' of type '%s' in domain '%s': %s\n", name, type,
1017
avahi_strerror(avahi_server_errno(mc.server)));
602
1020
case AVAHI_RESOLVER_FOUND:
604
1022
char ip[AVAHI_ADDRESS_STR_MAX];
605
1023
avahi_address_snprint(ip, sizeof(ip), address);
607
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
608
" port %d\n", name, host_name, ip, port);
1025
fprintf_plus(stderr, "Mandos server \"%s\" found on %s (%s, %"
1026
PRIdMAX ") on port %" PRIu16 "\n", name,
1027
host_name, ip, (intmax_t)interface, port);
610
int ret = start_mandos_communication(ip, port, interface, mc);
1029
int ret = start_mandos_communication(ip, port, interface,
1030
avahi_proto_to_af(proto));
1032
avahi_simple_poll_quit(mc.simple_poll);
1034
if(not add_server(ip, port, interface,
1035
avahi_proto_to_af(proto))){
1036
fprintf_plus(stderr, "Failed to add server \"%s\" to server"
616
1042
avahi_s_service_resolver_free(r);
619
static void browse_callback( AvahiSServiceBrowser *b,
620
AvahiIfIndex interface,
621
AvahiProtocol protocol,
622
AvahiBrowserEvent event,
626
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
628
mandos_context *mc = userdata;
629
assert(b); /* Spurious warning */
1045
static void browse_callback(AvahiSServiceBrowser *b,
1046
AvahiIfIndex interface,
1047
AvahiProtocol protocol,
1048
AvahiBrowserEvent event,
1052
AVAHI_GCC_UNUSED AvahiLookupResultFlags
1054
AVAHI_GCC_UNUSED void* userdata){
631
1057
/* Called whenever a new services becomes available on the LAN or
632
1058
is removed from the LAN */
636
1066
case AVAHI_BROWSER_FAILURE:
638
fprintf(stderr, "(Browser) %s\n",
639
avahi_strerror(avahi_server_errno(mc->server)));
640
avahi_simple_poll_quit(mc->simple_poll);
1068
fprintf_plus(stderr, "(Avahi browser) %s\n",
1069
avahi_strerror(avahi_server_errno(mc.server)));
1070
avahi_simple_poll_quit(mc.simple_poll);
643
1073
case AVAHI_BROWSER_NEW:
644
/* We ignore the returned resolver object. In the callback
645
function we free it. If the server is terminated before
646
the callback function is called the server will free
647
the resolver for us. */
649
if (!(avahi_s_service_resolver_new(mc->server, interface, protocol, name,
651
AVAHI_PROTO_INET6, 0,
652
resolve_callback, mc)))
653
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
654
avahi_strerror(avahi_server_errno(s)));
1074
/* We ignore the returned Avahi resolver object. In the callback
1075
function we free it. If the Avahi server is terminated before
1076
the callback function is called the Avahi server will free the
1079
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
1080
name, type, domain, protocol, 0,
1081
resolve_callback, NULL) == NULL)
1082
fprintf_plus(stderr, "Avahi: Failed to resolve service '%s':"
1084
avahi_strerror(avahi_server_errno(mc.server)));
657
1087
case AVAHI_BROWSER_REMOVE:
660
1090
case AVAHI_BROWSER_ALL_FOR_NOW:
661
1091
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1093
fprintf_plus(stderr, "No Mandos server found, still"
666
/* Combines file name and path and returns the malloced new
667
string. some sane checks could/should be added */
668
static const char *combinepath(const char *first, const char *second){
669
size_t f_len = strlen(first);
670
size_t s_len = strlen(second);
671
char *tmp = malloc(f_len + s_len + 2);
676
memcpy(tmp, first, f_len);
680
memcpy(tmp + f_len + 1, second, s_len);
682
tmp[f_len + 1 + s_len] = '\0';
687
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
688
AvahiServerConfig config;
689
AvahiSServiceBrowser *sb = NULL;
692
int returncode = EXIT_SUCCESS;
693
const char *interface = "eth0";
694
struct ifreq network;
696
char *connect_to = NULL;
697
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
698
mandos_context mc = { .simple_poll = NULL, .server = NULL,
699
.dh_bits = 2048, .priority = "SECURE256"};
1100
/* Signal handler that stops main loop after SIGTERM */
1101
static void handle_sigterm(int sig){
1106
signal_received = sig;
1107
int old_errno = errno;
1108
/* set main loop to exit */
1109
if(mc.simple_poll != NULL){
1110
avahi_simple_poll_quit(mc.simple_poll);
1115
bool get_flags(const char *ifname, struct ifreq *ifr){
1118
int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1120
perror_plus("socket");
1123
strcpy(ifr->ifr_name, ifname);
1124
ret = ioctl(s, SIOCGIFFLAGS, ifr);
1127
perror_plus("ioctl SIOCGIFFLAGS");
1134
bool good_flags(const char *ifname, const struct ifreq *ifr){
1136
/* Reject the loopback device */
1137
if(ifr->ifr_flags & IFF_LOOPBACK){
1139
fprintf_plus(stderr, "Rejecting loopback interface \"%s\"\n",
1144
/* Accept point-to-point devices only if connect_to is specified */
1145
if(connect_to != NULL and (ifr->ifr_flags & IFF_POINTOPOINT)){
1147
fprintf_plus(stderr, "Accepting point-to-point interface"
1148
" \"%s\"\n", ifname);
1152
/* Otherwise, reject non-broadcast-capable devices */
1153
if(not (ifr->ifr_flags & IFF_BROADCAST)){
1155
fprintf_plus(stderr, "Rejecting non-broadcast interface"
1156
" \"%s\"\n", ifname);
1160
/* Reject non-ARP interfaces (including dummy interfaces) */
1161
if(ifr->ifr_flags & IFF_NOARP){
1163
fprintf_plus(stderr, "Rejecting non-ARP interface \"%s\"\n",
1169
/* Accept this device */
1171
fprintf_plus(stderr, "Interface \"%s\" is good\n", ifname);
1177
* This function determines if a directory entry in /sys/class/net
1178
* corresponds to an acceptable network device.
1179
* (This function is passed to scandir(3) as a filter function.)
1181
int good_interface(const struct dirent *if_entry){
1182
if(if_entry->d_name[0] == '.'){
1187
if(not get_flags(if_entry->d_name, &ifr)){
1189
fprintf_plus(stderr, "Failed to get flags for interface "
1190
"\"%s\"\n", if_entry->d_name);
1195
if(not good_flags(if_entry->d_name, &ifr)){
1202
* This function determines if a directory entry in /sys/class/net
1203
* corresponds to an acceptable network device which is up.
1204
* (This function is passed to scandir(3) as a filter function.)
1206
int up_interface(const struct dirent *if_entry){
1207
if(if_entry->d_name[0] == '.'){
1212
if(not get_flags(if_entry->d_name, &ifr)){
1214
fprintf_plus(stderr, "Failed to get flags for interface "
1215
"\"%s\"\n", if_entry->d_name);
1220
/* Reject down interfaces */
1221
if(not (ifr.ifr_flags & IFF_UP)){
1223
fprintf_plus(stderr, "Rejecting down interface \"%s\"\n",
1229
/* Reject non-running interfaces */
1230
if(not (ifr.ifr_flags & IFF_RUNNING)){
1232
fprintf_plus(stderr, "Rejecting non-running interface \"%s\"\n",
1238
if(not good_flags(if_entry->d_name, &ifr)){
1244
int notdotentries(const struct dirent *direntry){
1245
/* Skip "." and ".." */
1246
if(direntry->d_name[0] == '.'
1247
and (direntry->d_name[1] == '\0'
1248
or (direntry->d_name[1] == '.'
1249
and direntry->d_name[2] == '\0'))){
1255
/* Is this directory entry a runnable program? */
1256
int runnable_hook(const struct dirent *direntry){
1261
if((direntry->d_name)[0] == '\0'){
1266
sret = strspn(direntry->d_name, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
1267
"abcdefghijklmnopqrstuvwxyz"
1270
if((direntry->d_name)[sret] != '\0'){
1271
/* Contains non-allowed characters */
1273
fprintf_plus(stderr, "Ignoring hook \"%s\" with bad name\n",
1279
char *fullname = NULL;
1280
ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1282
perror_plus("asprintf");
1286
ret = stat(fullname, &st);
1289
perror_plus("Could not stat hook");
1293
if(not (S_ISREG(st.st_mode))){
1294
/* Not a regular file */
1296
fprintf_plus(stderr, "Ignoring hook \"%s\" - not a file\n",
1301
if(not (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))){
1302
/* Not executable */
1304
fprintf_plus(stderr, "Ignoring hook \"%s\" - not executable\n",
1310
fprintf_plus(stderr, "Hook \"%s\" is acceptable\n",
1316
int avahi_loop_with_timeout(AvahiSimplePoll *s, int retry_interval){
1318
struct timespec now;
1319
struct timespec waited_time;
1320
intmax_t block_time;
1323
if(mc.current_server == NULL){
1325
fprintf_plus(stderr, "Wait until first server is found."
1328
ret = avahi_simple_poll_iterate(s, -1);
1331
fprintf_plus(stderr, "Check current_server if we should run"
1334
/* the current time */
1335
ret = clock_gettime(CLOCK_MONOTONIC, &now);
1337
perror_plus("clock_gettime");
1340
/* Calculating in ms how long time between now and server
1341
who we visted longest time ago. Now - last seen. */
1342
waited_time.tv_sec = (now.tv_sec
1343
- mc.current_server->last_seen.tv_sec);
1344
waited_time.tv_nsec = (now.tv_nsec
1345
- mc.current_server->last_seen.tv_nsec);
1346
/* total time is 10s/10,000ms.
1347
Converting to s from ms by dividing by 1,000,
1348
and ns to ms by dividing by 1,000,000. */
1349
block_time = ((retry_interval
1350
- ((intmax_t)waited_time.tv_sec * 1000))
1351
- ((intmax_t)waited_time.tv_nsec / 1000000));
1354
fprintf_plus(stderr, "Blocking for %" PRIdMAX " ms\n",
1358
if(block_time <= 0){
1359
ret = start_mandos_communication(mc.current_server->ip,
1360
mc.current_server->port,
1361
mc.current_server->if_index,
1362
mc.current_server->af);
1364
avahi_simple_poll_quit(mc.simple_poll);
1367
ret = clock_gettime(CLOCK_MONOTONIC,
1368
&mc.current_server->last_seen);
1370
perror_plus("clock_gettime");
1373
mc.current_server = mc.current_server->next;
1374
block_time = 0; /* Call avahi to find new Mandos
1375
servers, but don't block */
1378
ret = avahi_simple_poll_iterate(s, (int)block_time);
1381
if (ret > 0 or errno != EINTR){
1382
return (ret != 1) ? ret : 0;
1388
bool run_network_hooks(const char *mode, const char *interface,
1390
struct dirent **direntries;
1391
struct dirent *direntry;
1393
int numhooks = scandir(hookdir, &direntries, runnable_hook,
1396
perror_plus("scandir");
1398
int devnull = open("/dev/null", O_RDONLY);
1399
for(int i = 0; i < numhooks; i++){
1400
direntry = direntries[i];
1401
char *fullname = NULL;
1402
ret = asprintf(&fullname, "%s/%s", hookdir, direntry->d_name);
1404
perror_plus("asprintf");
1408
fprintf_plus(stderr, "Running network hook \"%s\"\n",
1411
pid_t hook_pid = fork();
1414
/* Raise privileges */
1418
perror_plus("seteuid");
1420
/* Raise privileges even more */
1424
perror_plus("setuid");
1430
perror_plus("setgid");
1432
/* Reset supplementary groups */
1434
ret = setgroups(0, NULL);
1436
perror_plus("setgroups");
1438
dup2(devnull, STDIN_FILENO);
1440
dup2(STDERR_FILENO, STDOUT_FILENO);
1441
ret = setenv("MANDOSNETHOOKDIR", hookdir, 1);
1443
perror_plus("setenv");
1446
ret = setenv("DEVICE", interface, 1);
1448
perror_plus("setenv");
1451
ret = setenv("VERBOSE", debug ? "1" : "0", 1);
1453
perror_plus("setenv");
1456
ret = setenv("MODE", mode, 1);
1458
perror_plus("setenv");
1462
ret = asprintf(&delaystring, "%f", delay);
1464
perror_plus("asprintf");
1467
ret = setenv("DELAY", delaystring, 1);
1470
perror_plus("setenv");
1474
if(execl(fullname, direntry->d_name, mode, NULL) == -1){
1475
perror_plus("execl");
1476
_exit(EXIT_FAILURE);
1480
if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
1481
perror_plus("waitpid");
1485
if(WIFEXITED(status)){
1486
if(WEXITSTATUS(status) != 0){
1487
fprintf_plus(stderr, "Warning: network hook \"%s\" exited"
1488
" with status %d\n", direntry->d_name,
1489
WEXITSTATUS(status));
1493
} else if(WIFSIGNALED(status)){
1494
fprintf_plus(stderr, "Warning: network hook \"%s\" died by"
1495
" signal %d\n", direntry->d_name,
1500
fprintf_plus(stderr, "Warning: network hook \"%s\""
1501
" crashed\n", direntry->d_name);
1508
fprintf_plus(stderr, "Network hook \"%s\" ran successfully\n",
1517
int main(int argc, char *argv[]){
1518
AvahiSServiceBrowser *sb = NULL;
1523
int exitcode = EXIT_SUCCESS;
1524
const char *interface = "";
1525
struct ifreq network;
1527
bool take_down_interface = false;
1530
char tempdir[] = "/tmp/mandosXXXXXX";
1531
bool tempdir_created = false;
1532
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1533
const char *seckey = PATHDIR "/" SECKEY;
1534
const char *pubkey = PATHDIR "/" PUBKEY;
1536
bool gnutls_initialized = false;
1537
bool gpgme_initialized = false;
1539
double retry_interval = 10; /* 10s between trying a server and
1540
retrying the same server again */
1542
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1543
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1548
/* Lower any group privileges we might have, just to be safe */
1552
perror_plus("setgid");
1555
/* Lower user privileges (temporarily) */
1559
perror_plus("seteuid");
1567
struct argp_option options[] = {
1568
{ .name = "debug", .key = 128,
1569
.doc = "Debug mode", .group = 3 },
1570
{ .name = "connect", .key = 'c',
1571
.arg = "ADDRESS:PORT",
1572
.doc = "Connect directly to a specific Mandos server",
1574
{ .name = "interface", .key = 'i',
1576
.doc = "Network interface that will be used to search for"
1579
{ .name = "seckey", .key = 's',
1581
.doc = "OpenPGP secret key file base name",
1583
{ .name = "pubkey", .key = 'p',
1585
.doc = "OpenPGP public key file base name",
1587
{ .name = "dh-bits", .key = 129,
1589
.doc = "Bit length of the prime number used in the"
1590
" Diffie-Hellman key exchange",
1592
{ .name = "priority", .key = 130,
1594
.doc = "GnuTLS priority string for the TLS handshake",
1596
{ .name = "delay", .key = 131,
1598
.doc = "Maximum delay to wait for interface startup",
1600
{ .name = "retry", .key = 132,
1602
.doc = "Retry interval used when denied by the mandos server",
1604
{ .name = "network-hook-dir", .key = 133,
1606
.doc = "Directory where network hooks are located",
1609
* These reproduce what we would get without ARGP_NO_HELP
1611
{ .name = "help", .key = '?',
1612
.doc = "Give this help list", .group = -1 },
1613
{ .name = "usage", .key = -3,
1614
.doc = "Give a short usage message", .group = -1 },
1615
{ .name = "version", .key = 'V',
1616
.doc = "Print program version", .group = -1 },
702
static struct option long_options[] = {
703
{"debug", no_argument, (int *)&debug, 1},
704
{"connect", required_argument, 0, 'C'},
705
{"interface", required_argument, 0, 'i'},
706
{"certdir", required_argument, 0, 'd'},
707
{"certkey", required_argument, 0, 'c'},
708
{"certfile", required_argument, 0, 'k'},
709
{"dh_bits", required_argument, 0, 'D'},
710
{"priority", required_argument, 0, 'p'},
713
int option_index = 0;
714
ret = getopt_long (argc, argv, "i:", long_options,
743
tmp = strtol(optarg, NULL, 10);
744
if (errno == ERANGE){
752
mc.priority = optarg;
1620
error_t parse_opt(int key, char *arg,
1621
struct argp_state *state){
1624
case 128: /* --debug */
1627
case 'c': /* --connect */
1630
case 'i': /* --interface */
1633
case 's': /* --seckey */
1636
case 'p': /* --pubkey */
1639
case 129: /* --dh-bits */
1641
tmpmax = strtoimax(arg, &tmp, 10);
1642
if(errno != 0 or tmp == arg or *tmp != '\0'
1643
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1644
argp_error(state, "Bad number of DH bits");
1646
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1648
case 130: /* --priority */
1651
case 131: /* --delay */
1653
delay = strtof(arg, &tmp);
1654
if(errno != 0 or tmp == arg or *tmp != '\0'){
1655
argp_error(state, "Bad delay");
1657
case 132: /* --retry */
1659
retry_interval = strtod(arg, &tmp);
1660
if(errno != 0 or tmp == arg or *tmp != '\0'
1661
or (retry_interval * 1000) > INT_MAX
1662
or retry_interval < 0){
1663
argp_error(state, "Bad retry interval");
1666
case 133: /* --network-hook-dir */
1670
* These reproduce what we would get without ARGP_NO_HELP
1672
case '?': /* --help */
1673
argp_state_help(state, state->out_stream,
1674
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1675
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1676
case -3: /* --usage */
1677
argp_state_help(state, state->out_stream,
1678
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1679
case 'V': /* --version */
1680
fprintf_plus(state->out_stream, "%s\n", argp_program_version);
1681
exit(argp_err_exit_status);
759
certfile = combinepath(certdir, certfile);
760
if (certfile == NULL){
761
perror("combinepath");
762
returncode = EXIT_FAILURE;
766
certkey = combinepath(certdir, certkey);
767
if (certkey == NULL){
768
perror("combinepath");
769
returncode = EXIT_FAILURE;
1684
return ARGP_ERR_UNKNOWN;
1689
struct argp argp = { .options = options, .parser = parse_opt,
1691
.doc = "Mandos client -- Get and decrypt"
1692
" passwords from a Mandos server" };
1693
ret = argp_parse(&argp, argc, argv,
1694
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
1701
perror_plus("argp_parse");
1702
exitcode = EX_OSERR;
1705
exitcode = EX_USAGE;
1711
/* Work around Debian bug #633582:
1712
<http://bugs.debian.org/633582> */
1714
/* Re-raise priviliges */
1718
perror_plus("seteuid");
1722
if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){
1723
int seckey_fd = open(seckey, O_RDONLY);
1724
if(seckey_fd == -1){
1725
perror_plus("open");
1727
ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st));
1729
perror_plus("fstat");
1731
if(S_ISREG(st.st_mode)
1732
and st.st_uid == 0 and st.st_gid == 0){
1733
ret = fchown(seckey_fd, uid, gid);
1735
perror_plus("fchown");
1739
TEMP_FAILURE_RETRY(close(seckey_fd));
1743
if(strcmp(pubkey, PATHDIR "/" PUBKEY) == 0){
1744
int pubkey_fd = open(pubkey, O_RDONLY);
1745
if(pubkey_fd == -1){
1746
perror_plus("open");
1748
ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st));
1750
perror_plus("fstat");
1752
if(S_ISREG(st.st_mode)
1753
and st.st_uid == 0 and st.st_gid == 0){
1754
ret = fchown(pubkey_fd, uid, gid);
1756
perror_plus("fchown");
1760
TEMP_FAILURE_RETRY(close(pubkey_fd));
1764
/* Lower privileges */
1768
perror_plus("seteuid");
1773
/* Run network hooks */
1774
if(not run_network_hooks("start", interface, delay)){
1779
avahi_set_log_function(empty_log);
1782
if(interface[0] == '\0'){
1783
struct dirent **direntries;
1784
/* First look for interfaces that are up */
1785
ret = scandir(sys_class_net, &direntries, up_interface,
1788
/* No up interfaces, look for any good interfaces */
1790
ret = scandir(sys_class_net, &direntries, good_interface,
1794
/* Pick the first interface returned */
1795
interface = strdup(direntries[0]->d_name);
1797
fprintf_plus(stderr, "Using interface \"%s\"\n", interface);
1799
if(interface == NULL){
1800
perror_plus("malloc");
1802
exitcode = EXIT_FAILURE;
1808
fprintf_plus(stderr, "Could not find a network interface\n");
1809
exitcode = EXIT_FAILURE;
1814
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1815
from the signal handler */
1816
/* Initialize the pseudo-RNG for Avahi */
1817
srand((unsigned int) time(NULL));
1818
mc.simple_poll = avahi_simple_poll_new();
1819
if(mc.simple_poll == NULL){
1820
fprintf_plus(stderr,
1821
"Avahi: Failed to create simple poll object.\n");
1822
exitcode = EX_UNAVAILABLE;
1826
sigemptyset(&sigterm_action.sa_mask);
1827
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1829
perror_plus("sigaddset");
1830
exitcode = EX_OSERR;
1833
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1835
perror_plus("sigaddset");
1836
exitcode = EX_OSERR;
1839
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1841
perror_plus("sigaddset");
1842
exitcode = EX_OSERR;
1845
/* Need to check if the handler is SIG_IGN before handling:
1846
| [[info:libc:Initial Signal Actions]] |
1847
| [[info:libc:Basic Signal Handling]] |
1849
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1851
perror_plus("sigaction");
1854
if(old_sigterm_action.sa_handler != SIG_IGN){
1855
ret = sigaction(SIGINT, &sigterm_action, NULL);
1857
perror_plus("sigaction");
1858
exitcode = EX_OSERR;
1862
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1864
perror_plus("sigaction");
1867
if(old_sigterm_action.sa_handler != SIG_IGN){
1868
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1870
perror_plus("sigaction");
1871
exitcode = EX_OSERR;
1875
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1877
perror_plus("sigaction");
1880
if(old_sigterm_action.sa_handler != SIG_IGN){
1881
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1883
perror_plus("sigaction");
1884
exitcode = EX_OSERR;
1889
/* If the interface is down, bring it up */
1890
if(strcmp(interface, "none") != 0){
773
1891
if_index = (AvahiIfIndex) if_nametoindex(interface);
774
1892
if(if_index == 0){
775
fprintf(stderr, "No such interface: \"%s\"\n", interface);
779
if(connect_to != NULL){
780
/* Connect directly, do not use Zeroconf */
781
/* (Mainly meant for debugging) */
782
char *address = strrchr(connect_to, ':');
784
fprintf(stderr, "No colon in address\n");
788
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
790
perror("Bad port number");
794
address = connect_to;
795
ret = start_mandos_communication(address, port, if_index);
1893
fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
1894
exitcode = EX_UNAVAILABLE;
1902
/* Re-raise priviliges */
1906
perror_plus("seteuid");
1910
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1911
messages about the network interface to mess up the prompt */
1912
ret = klogctl(8, NULL, 5);
1913
bool restore_loglevel = true;
1915
restore_loglevel = false;
1916
perror_plus("klogctl");
1918
#endif /* __linux__ */
803
1920
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
806
returncode = EXIT_FAILURE;
1922
perror_plus("socket");
1923
exitcode = EX_OSERR;
1925
if(restore_loglevel){
1926
ret = klogctl(7, NULL, 0);
1928
perror_plus("klogctl");
1931
#endif /* __linux__ */
1932
/* Lower privileges */
1936
perror_plus("seteuid");
809
strcpy(network.ifr_name, interface);
1940
strcpy(network.ifr_name, interface);
810
1941
ret = ioctl(sd, SIOCGIFFLAGS, &network);
813
perror("ioctl SIOCGIFFLAGS");
814
returncode = EXIT_FAILURE;
1943
perror_plus("ioctl SIOCGIFFLAGS");
1945
if(restore_loglevel){
1946
ret = klogctl(7, NULL, 0);
1948
perror_plus("klogctl");
1951
#endif /* __linux__ */
1952
exitcode = EX_OSERR;
1953
/* Lower privileges */
1957
perror_plus("seteuid");
817
1961
if((network.ifr_flags & IFF_UP) == 0){
818
1962
network.ifr_flags |= IFF_UP;
1963
take_down_interface = true;
819
1964
ret = ioctl(sd, SIOCSIFFLAGS, &network);
821
perror("ioctl SIOCSIFFLAGS");
822
returncode = EXIT_FAILURE;
829
avahi_set_log_function(empty_log);
832
/* Initialize the psuedo-RNG */
833
srand((unsigned int) time(NULL));
835
/* Allocate main loop object */
836
if (!(mc.simple_poll = avahi_simple_poll_new())) {
837
fprintf(stderr, "Failed to create simple poll object.\n");
838
returncode = EXIT_FAILURE;
842
/* Do not publish any local records */
1966
take_down_interface = false;
1967
perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
1968
exitcode = EX_OSERR;
1970
if(restore_loglevel){
1971
ret = klogctl(7, NULL, 0);
1973
perror_plus("klogctl");
1976
#endif /* __linux__ */
1977
/* Lower privileges */
1981
perror_plus("seteuid");
1986
/* Sleep checking until interface is running.
1987
Check every 0.25s, up to total time of delay */
1988
for(int i=0; i < delay * 4; i++){
1989
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1991
perror_plus("ioctl SIOCGIFFLAGS");
1992
} else if(network.ifr_flags & IFF_RUNNING){
1995
struct timespec sleeptime = { .tv_nsec = 250000000 };
1996
ret = nanosleep(&sleeptime, NULL);
1997
if(ret == -1 and errno != EINTR){
1998
perror_plus("nanosleep");
2001
if(not take_down_interface){
2002
/* We won't need the socket anymore */
2003
ret = (int)TEMP_FAILURE_RETRY(close(sd));
2005
perror_plus("close");
2009
if(restore_loglevel){
2010
/* Restores kernel loglevel to default */
2011
ret = klogctl(7, NULL, 0);
2013
perror_plus("klogctl");
2016
#endif /* __linux__ */
2017
/* Lower privileges */
2019
/* Lower privileges */
2022
perror_plus("seteuid");
2030
ret = init_gnutls_global(pubkey, seckey);
2032
fprintf_plus(stderr, "init_gnutls_global failed\n");
2033
exitcode = EX_UNAVAILABLE;
2036
gnutls_initialized = true;
2043
if(mkdtemp(tempdir) == NULL){
2044
perror_plus("mkdtemp");
2047
tempdir_created = true;
2053
if(not init_gpgme(pubkey, seckey, tempdir)){
2054
fprintf_plus(stderr, "init_gpgme failed\n");
2055
exitcode = EX_UNAVAILABLE;
2058
gpgme_initialized = true;
2065
if(connect_to != NULL){
2066
/* Connect directly, do not use Zeroconf */
2067
/* (Mainly meant for debugging) */
2068
char *address = strrchr(connect_to, ':');
2069
if(address == NULL){
2070
fprintf_plus(stderr, "No colon in address\n");
2071
exitcode = EX_USAGE;
2081
tmpmax = strtoimax(address+1, &tmp, 10);
2082
if(errno != 0 or tmp == address+1 or *tmp != '\0'
2083
or tmpmax != (uint16_t)tmpmax){
2084
fprintf_plus(stderr, "Bad port number\n");
2085
exitcode = EX_USAGE;
2093
port = (uint16_t)tmpmax;
2095
/* Colon in address indicates IPv6 */
2097
if(strchr(connect_to, ':') != NULL){
2099
/* Accept [] around IPv6 address - see RFC 5952 */
2100
if(connect_to[0] == '[' and address[-1] == ']')
2108
address = connect_to;
2114
while(not quit_now){
2115
ret = start_mandos_communication(address, port, if_index, af);
2116
if(quit_now or ret == 0){
2120
fprintf_plus(stderr, "Retrying in %d seconds\n",
2121
(int)retry_interval);
2123
sleep((int)retry_interval);
2127
exitcode = EXIT_SUCCESS;
2138
AvahiServerConfig config;
2139
/* Do not publish any local Zeroconf records */
843
2140
avahi_server_config_init(&config);
844
2141
config.publish_hinfo = 0;
845
2142
config.publish_addresses = 0;
846
2143
config.publish_workstation = 0;
847
2144
config.publish_domain = 0;
849
2146
/* Allocate a new server */
850
mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
851
&config, NULL, NULL, &error);
853
/* Free the configuration data */
2147
mc.server = avahi_server_new(avahi_simple_poll_get
2148
(mc.simple_poll), &config, NULL,
2151
/* Free the Avahi configuration data */
854
2152
avahi_server_config_free(&config);
856
/* Check if creating the server object succeeded */
858
fprintf(stderr, "Failed to create server: %s\n",
859
avahi_strerror(error));
860
returncode = EXIT_FAILURE;
864
/* Create the service browser */
865
sb = avahi_s_service_browser_new(mc.server, if_index,
867
"_mandos._tcp", NULL, 0,
868
browse_callback, &mc);
870
fprintf(stderr, "Failed to create service browser: %s\n",
871
avahi_strerror(avahi_server_errno(mc.server)));
872
returncode = EXIT_FAILURE;
876
/* Run the main loop */
879
fprintf(stderr, "Starting avahi loop search\n");
882
avahi_simple_poll_loop(simple_poll);
887
fprintf(stderr, "%s exiting\n", argv[0]);
892
avahi_s_service_browser_free(sb);
895
avahi_server_free(mc.server);
898
avahi_simple_poll_free(simple_poll);
2155
/* Check if creating the Avahi server object succeeded */
2156
if(mc.server == NULL){
2157
fprintf_plus(stderr, "Failed to create Avahi server: %s\n",
2158
avahi_strerror(error));
2159
exitcode = EX_UNAVAILABLE;
2167
/* Create the Avahi service browser */
2168
sb = avahi_s_service_browser_new(mc.server, if_index,
2169
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
2170
NULL, 0, browse_callback, NULL);
2172
fprintf_plus(stderr, "Failed to create service browser: %s\n",
2173
avahi_strerror(avahi_server_errno(mc.server)));
2174
exitcode = EX_UNAVAILABLE;
2182
/* Run the main loop */
2185
fprintf_plus(stderr, "Starting Avahi loop search\n");
2188
ret = avahi_loop_with_timeout(mc.simple_poll,
2189
(int)(retry_interval * 1000));
2191
fprintf_plus(stderr, "avahi_loop_with_timeout exited %s\n",
2192
(ret == 0) ? "successfully" : "with error");
2198
fprintf_plus(stderr, "%s exiting\n", argv[0]);
2201
/* Cleanup things */
2203
avahi_s_service_browser_free(sb);
2205
if(mc.server != NULL)
2206
avahi_server_free(mc.server);
2208
if(mc.simple_poll != NULL)
2209
avahi_simple_poll_free(mc.simple_poll);
2211
if(gnutls_initialized){
2212
gnutls_certificate_free_credentials(mc.cred);
2213
gnutls_global_deinit();
2214
gnutls_dh_params_deinit(mc.dh_params);
2217
if(gpgme_initialized){
2218
gpgme_release(mc.ctx);
2221
/* Cleans up the circular linked list of Mandos servers the client
2223
if(mc.current_server != NULL){
2224
mc.current_server->prev->next = NULL;
2225
while(mc.current_server != NULL){
2226
server *next = mc.current_server->next;
2227
free(mc.current_server);
2228
mc.current_server = next;
2232
/* Run network hooks */
2233
run_network_hooks("stop", interface, delay);
2235
/* Re-raise priviliges */
2240
perror_plus("seteuid");
2243
/* Take down the network interface */
2244
if(take_down_interface and geteuid() == 0){
2245
ret = ioctl(sd, SIOCGIFFLAGS, &network);
2247
perror_plus("ioctl SIOCGIFFLAGS");
2248
} else if(network.ifr_flags & IFF_UP){
2249
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
2250
ret = ioctl(sd, SIOCSIFFLAGS, &network);
2252
perror_plus("ioctl SIOCSIFFLAGS -IFF_UP");
2255
ret = (int)TEMP_FAILURE_RETRY(close(sd));
2257
perror_plus("close");
2261
/* Lower privileges permanently */
2265
perror_plus("setuid");
2268
/* Removes the GPGME temp directory and all files inside */
2269
if(tempdir_created){
2270
struct dirent **direntries = NULL;
2271
struct dirent *direntry = NULL;
2272
int numentries = scandir(tempdir, &direntries, notdotentries,
2274
if (numentries > 0){
2275
for(int i = 0; i < numentries; i++){
2276
direntry = direntries[i];
2277
char *fullname = NULL;
2278
ret = asprintf(&fullname, "%s/%s", tempdir,
2281
perror_plus("asprintf");
2284
ret = remove(fullname);
2286
fprintf_plus(stderr, "remove(\"%s\"): %s\n", fullname,
2293
/* need to clean even if 0 because man page doesn't specify */
2295
if (numentries == -1){
2296
perror_plus("scandir");
2298
ret = rmdir(tempdir);
2299
if(ret == -1 and errno != ENOENT){
2300
perror_plus("rmdir");
2305
sigemptyset(&old_sigterm_action.sa_mask);
2306
old_sigterm_action.sa_handler = SIG_DFL;
2307
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
2308
&old_sigterm_action,
2311
perror_plus("sigaction");
2314
ret = raise(signal_received);
2315
} while(ret != 0 and errno == EINTR);
2317
perror_plus("raise");
2320
TEMP_FAILURE_RETRY(pause());