45
100
#include <avahi-common/malloc.h>
46
101
#include <avahi-common/error.h>
49
#include <sys/types.h> /* socket(), inet_pton() */
50
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
51
struct in6_addr, inet_pton() */
52
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
53
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
55
#include <unistd.h> /* close() */
56
#include <netinet/in.h>
57
#include <stdbool.h> /* true */
58
#include <string.h> /* memset */
59
#include <arpa/inet.h> /* inet_pton() */
60
#include <iso646.h> /* not */
63
#include <errno.h> /* perror() */
104
#include <gnutls/gnutls.h> /* All GnuTLS types, constants and
107
init_gnutls_session(),
109
#include <gnutls/openpgp.h>
110
/* gnutls_certificate_set_openpgp_key_file(),
111
GNUTLS_OPENPGP_FMT_BASE64 */
114
#include <gpgme.h> /* All GPGME types, constants and
117
GPGME_PROTOCOL_OpenPGP,
69
120
#define BUFFER_SIZE 256
71
static int dh_bits = 1024;
73
static const char *keydir = "/conf/conf.d/mandos";
74
static const char *pubkeyfile = "pubkey.txt";
75
static const char *seckeyfile = "seckey.txt";
122
#define PATHDIR "/conf/conf.d/mandos"
123
#define SECKEY "seckey.txt"
124
#define PUBKEY "pubkey.txt"
77
126
bool debug = false;
127
static const char mandos_protocol_version[] = "1";
128
const char *argp_program_version = "mandos-client " VERSION;
129
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
130
static const char sys_class_net[] = "/sys/class/net";
131
char *connect_to = NULL;
133
/* Used for passing in values through the Avahi callback functions */
81
gnutls_session_t session;
135
AvahiSimplePoll *simple_poll;
82
137
gnutls_certificate_credentials_t cred;
138
unsigned int dh_bits;
83
139
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;
140
const char *priority;
144
/* global context so signal handler can reach it*/
145
mandos_context mc = { .simple_poll = NULL, .server = NULL,
146
.dh_bits = 1024, .priority = "SECURE256"
147
":!CTYPE-X.509:+CTYPE-OPENPGP" };
149
sig_atomic_t quit_now = 0;
150
int signal_received = 0;
153
* Make additional room in "buffer" for at least BUFFER_SIZE more
154
* bytes. "buffer_capacity" is how much is currently allocated,
155
* "buffer_length" is how much is already used.
157
size_t incbuffer(char **buffer, size_t buffer_length,
158
size_t buffer_capacity){
159
if(buffer_length + BUFFER_SIZE > buffer_capacity){
160
*buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
164
buffer_capacity += BUFFER_SIZE;
166
return buffer_capacity;
172
static bool init_gpgme(const char *seckey,
173
const char *pubkey, const char *tempdir){
94
ssize_t new_packet_capacity = 0;
95
ssize_t new_packet_length = 0;
96
175
gpgme_engine_info_t engine_info;
99
fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
179
* Helper function to insert pub and seckey to the engine keyring.
181
bool import_key(const char *filename){
184
gpgme_data_t pgp_data;
186
fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
192
rc = gpgme_data_new_from_fd(&pgp_data, fd);
193
if(rc != GPG_ERR_NO_ERROR){
194
fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
195
gpgme_strsource(rc), gpgme_strerror(rc));
199
rc = gpgme_op_import(mc.ctx, pgp_data);
200
if(rc != GPG_ERR_NO_ERROR){
201
fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
202
gpgme_strsource(rc), gpgme_strerror(rc));
206
ret = (int)TEMP_FAILURE_RETRY(close(fd));
210
gpgme_data_release(pgp_data);
215
fprintf(stderr, "Initializing GPGME\n");
103
219
gpgme_check_version(NULL);
104
220
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
105
if (rc != GPG_ERR_NO_ERROR){
221
if(rc != GPG_ERR_NO_ERROR){
106
222
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
107
223
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){
227
/* Set GPGME home directory for the OpenPGP engine only */
228
rc = gpgme_get_engine_info(&engine_info);
229
if(rc != GPG_ERR_NO_ERROR){
114
230
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
115
231
gpgme_strsource(rc), gpgme_strerror(rc));
118
234
while(engine_info != NULL){
119
235
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
120
236
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
121
engine_info->file_name, homedir);
237
engine_info->file_name, tempdir);
124
240
engine_info = engine_info->next;
126
242
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){
243
fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
247
/* Create new GPGME "context" */
248
rc = gpgme_new(&(mc.ctx));
249
if(rc != GPG_ERR_NO_ERROR){
250
fprintf(stderr, "bad gpgme_new: %s: %s\n",
251
gpgme_strsource(rc), gpgme_strerror(rc));
255
if(not import_key(pubkey) or not import_key(seckey)){
263
* Decrypt OpenPGP data.
264
* Returns -1 on error
266
static ssize_t pgp_packet_decrypt(const char *cryptotext,
269
gpgme_data_t dh_crypto, dh_plain;
272
size_t plaintext_capacity = 0;
273
ssize_t plaintext_length = 0;
276
fprintf(stderr, "Trying to decrypt OpenPGP data\n");
279
/* Create new GPGME data buffer from memory cryptotext */
280
rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
282
if(rc != GPG_ERR_NO_ERROR){
134
283
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
135
284
gpgme_strsource(rc), gpgme_strerror(rc));
197
/* Delete the GPGME FILE pointer cryptotext data buffer */
198
gpgme_data_release(dh_crypto);
334
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
200
337
/* 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");
338
if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
339
perror("gpgme_data_seek");
340
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;
346
plaintext_capacity = incbuffer(plaintext,
347
(size_t)plaintext_length,
349
if(plaintext_capacity == 0){
351
plaintext_length = -1;
218
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
355
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
220
357
/* Print the data, if any */
225
363
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"); */
364
plaintext_length = -1;
367
plaintext_length += ret;
371
fprintf(stderr, "Decrypted password is: ");
372
for(ssize_t i = 0; i < plaintext_length; i++){
373
fprintf(stderr, "%02hhX ", (*plaintext)[i]);
375
fprintf(stderr, "\n");
380
/* Delete the GPGME cryptotext data buffer */
381
gpgme_data_release(dh_crypto);
239
383
/* Delete the GPGME plaintext data buffer */
240
384
gpgme_data_release(dh_plain);
241
return new_packet_length;
385
return plaintext_length;
244
static const char * safer_gnutls_strerror (int value) {
245
const char *ret = gnutls_strerror (value);
388
static const char * safer_gnutls_strerror(int value){
389
const char *ret = gnutls_strerror(value); /* Spurious warning from
390
-Wunreachable-code */
247
392
ret = "(unknown)";
396
/* GnuTLS log function callback */
251
397
static void debuggnutls(__attribute__((unused)) int level,
252
398
const char* string){
253
fprintf(stderr, "%s", string);
399
fprintf(stderr, "GnuTLS: %s", string);
256
static int initgnutls(encrypted_session *es){
402
static int init_gnutls_global(const char *pubkeyfilename,
403
const char *seckeyfilename){
261
407
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));
410
ret = gnutls_global_init();
411
if(ret != GNUTLS_E_SUCCESS){
412
fprintf(stderr, "GnuTLS global_init: %s\n",
413
safer_gnutls_strerror(ret));
418
/* "Use a log level over 10 to enable all debugging options."
271
421
gnutls_global_set_log_level(11);
272
422
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));
425
/* OpenPGP credentials */
426
gnutls_certificate_allocate_credentials(&mc.cred);
427
if(ret != GNUTLS_E_SUCCESS){
428
fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
432
safer_gnutls_strerror(ret));
433
gnutls_global_deinit();
284
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
285
" and keyfile %s as GnuTLS credentials\n", pubkeyfile,
438
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
439
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
289
443
ret = gnutls_certificate_set_openpgp_key_file
290
(es->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
291
if (ret != GNUTLS_E_SUCCESS) {
293
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
295
ret, pubkeyfile, seckeyfile);
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){
444
(mc.cred, pubkeyfilename, seckeyfilename,
445
GNUTLS_OPENPGP_FMT_BASE64);
446
if(ret != GNUTLS_E_SUCCESS){
448
"Error[%d] while reading the OpenPGP key pair ('%s',"
449
" '%s')\n", ret, pubkeyfilename, seckeyfilename);
450
fprintf(stderr, "The GnuTLS error is: %s\n",
451
safer_gnutls_strerror(ret));
455
/* GnuTLS server initialization */
456
ret = gnutls_dh_params_init(&mc.dh_params);
457
if(ret != GNUTLS_E_SUCCESS){
458
fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
459
" %s\n", safer_gnutls_strerror(ret));
462
ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
463
if(ret != GNUTLS_E_SUCCESS){
464
fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
465
safer_gnutls_strerror(ret));
469
gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
475
gnutls_certificate_free_credentials(mc.cred);
476
gnutls_global_deinit();
477
gnutls_dh_params_deinit(mc.dh_params);
481
static int init_gnutls_session(gnutls_session_t *session){
483
/* GnuTLS session creation */
485
ret = gnutls_init(session, GNUTLS_SERVER);
489
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
490
if(ret != GNUTLS_E_SUCCESS){
321
491
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
322
492
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));
498
ret = gnutls_priority_set_direct(*session, mc.priority, &err);
500
gnutls_deinit(*session);
503
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
504
if(ret != GNUTLS_E_SUCCESS){
505
fprintf(stderr, "Syntax error at: %s\n", err);
506
fprintf(stderr, "GnuTLS error: %s\n",
507
safer_gnutls_strerror(ret));
508
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",
514
ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
517
gnutls_deinit(*session);
520
} while(ret == GNUTLS_E_INTERRUPTED or ret == GNUTLS_E_AGAIN);
521
if(ret != GNUTLS_E_SUCCESS){
522
fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
337
523
safer_gnutls_strerror(ret));
524
gnutls_deinit(*session);
341
528
/* ignore client certificate if any. */
342
gnutls_certificate_server_set_request (es->session,
529
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
345
gnutls_dh_set_prime_bits (es->session, dh_bits);
531
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
536
/* Avahi log function callback */
350
537
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
351
538
__attribute__((unused)) const char *txt){}
540
/* Called when a Mandos server is found */
353
541
static int start_mandos_communication(const char *ip, uint16_t port,
354
AvahiIfIndex if_index){
356
struct sockaddr_in6 to;
357
encrypted_session es;
542
AvahiIfIndex if_index,
544
int ret, tcp_sd = -1;
547
struct sockaddr_in in;
548
struct sockaddr_in6 in6;
358
550
char *buffer = NULL;
359
char *decrypted_buffer;
551
char *decrypted_buffer = NULL;
360
552
size_t buffer_length = 0;
361
553
size_t buffer_capacity = 0;
362
ssize_t decrypted_buffer_size;
365
char interface[IF_NAMESIZE];
556
gnutls_session_t session;
557
int pf; /* Protocol family */
574
fprintf(stderr, "Bad address family: %d\n", af);
579
ret = init_gnutls_session(&session);
368
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
585
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
372
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
589
tcp_sd = socket(pf, SOCK_STREAM, 0);
374
592
perror("socket");
378
if(if_indextoname((unsigned int)if_index, interface) == NULL){
380
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);
602
memset(&to, 0, sizeof(to));
604
to.in6.sin6_family = (sa_family_t)af;
605
ret = inet_pton(af, ip, &to.in6.sin6_addr);
607
to.in.sin_family = (sa_family_t)af;
608
ret = inet_pton(af, ip, &to.in.sin_addr);
393
612
perror("inet_pton");
397
618
fprintf(stderr, "Bad address: %s\n", ip);
400
to.sin6_port = htons(port); /* Spurious warning */
623
to.in6.sin6_port = htons(port); /* Spurious warnings from
625
-Wunreachable-code */
627
if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
628
(&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
630
if(if_index == AVAHI_IF_UNSPEC){
631
fprintf(stderr, "An IPv6 link-local address is incomplete"
632
" without a network interface\n");
636
/* Set the network interface number as scope */
637
to.in6.sin6_scope_id = (uint32_t)if_index;
640
to.in.sin_port = htons(port); /* Spurious warnings from
642
-Wunreachable-code */
402
to.sin6_scope_id = (uint32_t)if_index;
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){
651
if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
652
char interface[IF_NAMESIZE];
653
if(if_indextoname((unsigned int)if_index, interface) == NULL){
654
perror("if_indextoname");
656
fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
657
ip, interface, port);
660
fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
663
char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
664
INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
667
pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
670
pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
409
674
perror("inet_ntop");
411
676
if(strcmp(addrstr, ip) != 0){
412
fprintf(stderr, "Canonical address form: %s\n",
413
addrstr, ntohs(to.sin6_port));
677
fprintf(stderr, "Canonical address form: %s\n", addrstr);
418
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
688
ret = connect(tcp_sd, &to.in6, sizeof(to));
690
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
420
694
perror("connect");
424
ret = initgnutls (&es);
430
gnutls_transport_set_ptr (es.session,
431
(gnutls_transport_ptr_t) tcp_sd);
704
const char *out = mandos_protocol_version;
707
size_t out_size = strlen(out);
708
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
709
out_size - written));
716
written += (size_t)ret;
717
if(written < out_size){
720
if(out == mandos_protocol_version){
434
735
fprintf(stderr, "Establishing TLS session with %s\n", ip);
437
ret = gnutls_handshake (es.session);
439
if (ret != GNUTLS_E_SUCCESS){
743
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
751
ret = gnutls_handshake(session);
756
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
758
if(ret != GNUTLS_E_SUCCESS){
441
fprintf(stderr, "\n*** Handshake failed ***\n");
760
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
448
//Retrieve OpenPGP packet that contains the wanted password
767
/* Read OpenPGP packet that contains the wanted password */
451
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
770
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
456
if (buffer_length + BUFFER_SIZE > buffer_capacity){
457
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
462
buffer_capacity += BUFFER_SIZE;
465
ret = gnutls_record_recv
466
(es.session, buffer+buffer_length, BUFFER_SIZE);
781
buffer_capacity = incbuffer(&buffer, buffer_length,
783
if(buffer_capacity == 0){
795
sret = gnutls_record_recv(session, buffer+buffer_length,
472
802
case GNUTLS_E_INTERRUPTED:
473
803
case GNUTLS_E_AGAIN:
475
805
case GNUTLS_E_REHANDSHAKE:
476
ret = gnutls_handshake (es.session);
478
fprintf(stderr, "\n*** Handshake failed ***\n");
807
ret = gnutls_handshake(session);
813
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
815
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
485
822
fprintf(stderr, "Unknown error while reading data from"
486
" encrypted session with mandos server\n");
488
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
823
" encrypted session with Mandos server\n");
824
gnutls_bye(session, GNUTLS_SHUT_RDWR);
492
buffer_length += (size_t) ret;
496
if (buffer_length > 0){
829
buffer_length += (size_t) sret;
834
fprintf(stderr, "Closing TLS session\n");
843
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
848
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
850
if(buffer_length > 0){
851
ssize_t decrypted_buffer_size;
497
852
decrypted_buffer_size = pgp_packet_decrypt(buffer,
501
if (decrypted_buffer_size >= 0){
855
if(decrypted_buffer_size >= 0){
502
858
while(written < (size_t) decrypted_buffer_size){
503
ret = (int)fwrite (decrypted_buffer + written, 1,
504
(size_t)decrypted_buffer_size - written,
864
ret = (int)fwrite(decrypted_buffer + written, 1,
865
(size_t)decrypted_buffer_size - written,
506
867
if(ret == 0 and ferror(stdout)){
508
870
fprintf(stderr, "Error writing encrypted data: %s\n",
509
871
strerror(errno));
514
876
written += (size_t)ret;
516
free(decrypted_buffer);
882
/* Shutdown procedure */
887
free(decrypted_buffer);
890
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
898
gnutls_deinit(session);
525
fprintf(stderr, "Closing TLS session\n");
529
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
532
gnutls_deinit (es.session);
533
gnutls_certificate_free_credentials (es.cred);
534
gnutls_global_deinit ();
538
static AvahiSimplePoll *simple_poll = NULL;
539
static AvahiServer *server = NULL;
541
static void resolve_callback(
542
AvahiSServiceResolver *r,
543
AvahiIfIndex interface,
544
AVAHI_GCC_UNUSED AvahiProtocol protocol,
545
AvahiResolverEvent event,
549
const char *host_name,
550
const AvahiAddress *address,
552
AVAHI_GCC_UNUSED AvahiStringList *txt,
553
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
554
AVAHI_GCC_UNUSED void* userdata) {
556
assert(r); /* Spurious warning */
908
static void resolve_callback(AvahiSServiceResolver *r,
909
AvahiIfIndex interface,
911
AvahiResolverEvent event,
915
const char *host_name,
916
const AvahiAddress *address,
918
AVAHI_GCC_UNUSED AvahiStringList *txt,
919
AVAHI_GCC_UNUSED AvahiLookupResultFlags
921
AVAHI_GCC_UNUSED void* userdata){
558
924
/* Called whenever a service has been resolved successfully or
563
933
case AVAHI_RESOLVER_FAILURE:
564
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
565
" type '%s' in domain '%s': %s\n", name, type, domain,
566
avahi_strerror(avahi_server_errno(server)));
934
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
935
" of type '%s' in domain '%s': %s\n", name, type, domain,
936
avahi_strerror(avahi_server_errno(mc.server)));
569
939
case AVAHI_RESOLVER_FOUND:
571
941
char ip[AVAHI_ADDRESS_STR_MAX];
572
942
avahi_address_snprint(ip, sizeof(ip), address);
574
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
575
" port %d\n", name, host_name, ip, port);
944
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
945
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
946
ip, (intmax_t)interface, port);
577
int ret = start_mandos_communication(ip, port, interface);
948
int ret = start_mandos_communication(ip, port, interface,
949
avahi_proto_to_af(proto));
951
avahi_simple_poll_quit(mc.simple_poll);
583
955
avahi_s_service_resolver_free(r);
586
static void browse_callback(
587
AvahiSServiceBrowser *b,
588
AvahiIfIndex interface,
589
AvahiProtocol protocol,
590
AvahiBrowserEvent event,
594
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
597
AvahiServer *s = userdata;
598
assert(b); /* Spurious warning */
600
/* Called whenever a new services becomes available on the LAN or
601
is removed from the LAN */
958
static void browse_callback(AvahiSServiceBrowser *b,
959
AvahiIfIndex interface,
960
AvahiProtocol protocol,
961
AvahiBrowserEvent event,
965
AVAHI_GCC_UNUSED AvahiLookupResultFlags
967
AVAHI_GCC_UNUSED void* userdata){
970
/* Called whenever a new services becomes available on the LAN or
971
is removed from the LAN */
979
case AVAHI_BROWSER_FAILURE:
981
fprintf(stderr, "(Avahi browser) %s\n",
982
avahi_strerror(avahi_server_errno(mc.server)));
983
avahi_simple_poll_quit(mc.simple_poll);
986
case AVAHI_BROWSER_NEW:
987
/* We ignore the returned Avahi resolver object. In the callback
988
function we free it. If the Avahi server is terminated before
989
the callback function is called the Avahi server will free the
992
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
993
name, type, domain, protocol, 0,
994
resolve_callback, NULL) == NULL)
995
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
996
name, avahi_strerror(avahi_server_errno(mc.server)));
999
case AVAHI_BROWSER_REMOVE:
1002
case AVAHI_BROWSER_ALL_FOR_NOW:
1003
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1005
fprintf(stderr, "No Mandos server found, still searching...\n");
1011
/* stop main loop after sigterm has been called */
1012
static void handle_sigterm(int sig){
1017
signal_received = sig;
1018
int old_errno = errno;
1019
if(mc.simple_poll != NULL){
1020
avahi_simple_poll_quit(mc.simple_poll);
1026
* This function determines if a directory entry in /sys/class/net
1027
* corresponds to an acceptable network device.
1028
* (This function is passed to scandir(3) as a filter function.)
1030
int good_interface(const struct dirent *if_entry){
1032
char *flagname = NULL;
1033
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
1039
if(if_entry->d_name[0] == '.'){
1042
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1047
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1048
/* read line from flags_fd */
1049
ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
1050
char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1051
flagstring[(size_t)to_read] = '\0';
1052
if(flagstring == NULL){
1058
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1075
tmpmax = strtoimax(flagstring, &tmp, 0);
1076
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1077
and not (isspace(*tmp)))
1078
or tmpmax != (ifreq_flags)tmpmax){
1080
fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1081
flagstring, if_entry->d_name);
1087
ifreq_flags flags = (ifreq_flags)tmpmax;
1088
/* Reject the loopback device */
1089
if(flags & IFF_LOOPBACK){
1091
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1096
/* Accept point-to-point devices only if connect_to is specified */
1097
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1099
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1104
/* Otherwise, reject non-broadcast-capable devices */
1105
if(not (flags & IFF_BROADCAST)){
1107
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1112
/* Accept this device */
1114
fprintf(stderr, "Interface \"%s\" is acceptable\n",
1120
int main(int argc, char *argv[]){
1121
AvahiSServiceBrowser *sb = NULL;
1126
int exitcode = EXIT_SUCCESS;
1127
const char *interface = "";
1128
struct ifreq network;
1130
bool take_down_interface = false;
1133
char tempdir[] = "/tmp/mandosXXXXXX";
1134
bool tempdir_created = false;
1135
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1136
const char *seckey = PATHDIR "/" SECKEY;
1137
const char *pubkey = PATHDIR "/" PUBKEY;
1139
bool gnutls_initialized = false;
1140
bool gpgme_initialized = false;
1143
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1144
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1149
/* Lower any group privileges we might have, just to be safe */
1156
/* Lower user privileges (temporarily) */
1168
struct argp_option options[] = {
1169
{ .name = "debug", .key = 128,
1170
.doc = "Debug mode", .group = 3 },
1171
{ .name = "connect", .key = 'c',
1172
.arg = "ADDRESS:PORT",
1173
.doc = "Connect directly to a specific Mandos server",
1175
{ .name = "interface", .key = 'i',
1177
.doc = "Network interface that will be used to search for"
1180
{ .name = "seckey", .key = 's',
1182
.doc = "OpenPGP secret key file base name",
1184
{ .name = "pubkey", .key = 'p',
1186
.doc = "OpenPGP public key file base name",
1188
{ .name = "dh-bits", .key = 129,
1190
.doc = "Bit length of the prime number used in the"
1191
" Diffie-Hellman key exchange",
1193
{ .name = "priority", .key = 130,
1195
.doc = "GnuTLS priority string for the TLS handshake",
1197
{ .name = "delay", .key = 131,
1199
.doc = "Maximum delay to wait for interface startup",
1202
* These reproduce what we would get without ARGP_NO_HELP
1204
{ .name = "help", .key = '?',
1205
.doc = "Give this help list", .group = -1 },
1206
{ .name = "usage", .key = -3,
1207
.doc = "Give a short usage message", .group = -1 },
1208
{ .name = "version", .key = 'V',
1209
.doc = "Print program version", .group = -1 },
1213
error_t parse_opt(int key, char *arg,
1214
struct argp_state *state){
1217
case 128: /* --debug */
1220
case 'c': /* --connect */
1223
case 'i': /* --interface */
1226
case 's': /* --seckey */
1229
case 'p': /* --pubkey */
1232
case 129: /* --dh-bits */
1234
tmpmax = strtoimax(arg, &tmp, 10);
1235
if(errno != 0 or tmp == arg or *tmp != '\0'
1236
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1237
argp_error(state, "Bad number of DH bits");
1239
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1241
case 130: /* --priority */
1244
case 131: /* --delay */
1246
delay = strtof(arg, &tmp);
1247
if(errno != 0 or tmp == arg or *tmp != '\0'){
1248
argp_error(state, "Bad delay");
1252
* These reproduce what we would get without ARGP_NO_HELP
1254
case '?': /* --help */
1255
argp_state_help(state, state->out_stream,
1256
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1257
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1258
case -3: /* --usage */
1259
argp_state_help(state, state->out_stream,
1260
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1261
case 'V': /* --version */
1262
fprintf(state->out_stream, "%s\n", argp_program_version);
1263
exit(argp_err_exit_status);
1266
return ARGP_ERR_UNKNOWN;
1271
struct argp argp = { .options = options, .parser = parse_opt,
1273
.doc = "Mandos client -- Get and decrypt"
1274
" passwords from a Mandos server" };
1275
ret = argp_parse(&argp, argc, argv,
1276
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
605
case AVAHI_BROWSER_FAILURE:
607
fprintf(stderr, "(Browser) %s\n",
608
avahi_strerror(avahi_server_errno(server)));
609
avahi_simple_poll_quit(simple_poll);
612
case AVAHI_BROWSER_NEW:
613
/* We ignore the returned resolver object. In the callback
614
function we free it. If the server is terminated before
615
the callback function is called the server will free
616
the resolver for us. */
618
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
620
AVAHI_PROTO_INET6, 0,
621
resolve_callback, s)))
622
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
623
avahi_strerror(avahi_server_errno(s)));
626
case AVAHI_BROWSER_REMOVE:
629
case AVAHI_BROWSER_ALL_FOR_NOW:
630
case AVAHI_BROWSER_CACHE_EXHAUSTED:
635
/* Combines file name and path and returns the malloced new
636
string. some sane checks could/should be added */
637
static const char *combinepath(const char *first, const char *second){
638
size_t f_len = strlen(first);
639
size_t s_len = strlen(second);
640
char *tmp = malloc(f_len + s_len + 2);
645
memcpy(tmp, first, f_len);
649
memcpy(tmp + f_len + 1, second, s_len);
651
tmp[f_len + 1 + s_len] = '\0';
656
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
1283
perror("argp_parse");
1284
exitcode = EX_OSERR;
1287
exitcode = EX_USAGE;
1293
avahi_set_log_function(empty_log);
1296
if(interface[0] == '\0'){
1297
struct dirent **direntries;
1298
ret = scandir(sys_class_net, &direntries, good_interface,
1301
/* Pick the first good interface */
1302
interface = strdup(direntries[0]->d_name);
1304
fprintf(stderr, "Using interface \"%s\"\n", interface);
1306
if(interface == NULL){
1309
exitcode = EXIT_FAILURE;
1315
fprintf(stderr, "Could not find a network interface\n");
1316
exitcode = EXIT_FAILURE;
1321
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1322
from the signal handler */
1323
/* Initialize the pseudo-RNG for Avahi */
1324
srand((unsigned int) time(NULL));
1325
mc.simple_poll = avahi_simple_poll_new();
1326
if(mc.simple_poll == NULL){
1327
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1328
exitcode = EX_UNAVAILABLE;
1332
sigemptyset(&sigterm_action.sa_mask);
1333
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1335
perror("sigaddset");
1336
exitcode = EX_OSERR;
1339
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1341
perror("sigaddset");
1342
exitcode = EX_OSERR;
1345
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1347
perror("sigaddset");
1348
exitcode = EX_OSERR;
1351
/* Need to check if the handler is SIG_IGN before handling:
1352
| [[info:libc:Initial Signal Actions]] |
1353
| [[info:libc:Basic Signal Handling]] |
1355
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1357
perror("sigaction");
1360
if(old_sigterm_action.sa_handler != SIG_IGN){
1361
ret = sigaction(SIGINT, &sigterm_action, NULL);
1363
perror("sigaction");
1364
exitcode = EX_OSERR;
1368
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1370
perror("sigaction");
1373
if(old_sigterm_action.sa_handler != SIG_IGN){
1374
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1376
perror("sigaction");
1377
exitcode = EX_OSERR;
1381
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1383
perror("sigaction");
1386
if(old_sigterm_action.sa_handler != SIG_IGN){
1387
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1389
perror("sigaction");
1390
exitcode = EX_OSERR;
1395
/* If the interface is down, bring it up */
1396
if(strcmp(interface, "none") != 0){
1397
if_index = (AvahiIfIndex) if_nametoindex(interface);
1399
fprintf(stderr, "No such interface: \"%s\"\n", interface);
1400
exitcode = EX_UNAVAILABLE;
1408
/* Re-raise priviliges */
1416
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1417
messages about the network interface to mess up the prompt */
1418
ret = klogctl(8, NULL, 5);
1419
bool restore_loglevel = true;
1421
restore_loglevel = false;
1424
#endif /* __linux__ */
1426
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1429
exitcode = EX_OSERR;
1431
if(restore_loglevel){
1432
ret = klogctl(7, NULL, 0);
1437
#endif /* __linux__ */
1438
/* Lower privileges */
1446
strcpy(network.ifr_name, interface);
1447
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1449
perror("ioctl SIOCGIFFLAGS");
1451
if(restore_loglevel){
1452
ret = klogctl(7, NULL, 0);
1457
#endif /* __linux__ */
1458
exitcode = EX_OSERR;
1459
/* Lower privileges */
1467
if((network.ifr_flags & IFF_UP) == 0){
1468
network.ifr_flags |= IFF_UP;
1469
take_down_interface = true;
1470
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1472
take_down_interface = false;
1473
perror("ioctl SIOCSIFFLAGS +IFF_UP");
1474
exitcode = EX_OSERR;
1476
if(restore_loglevel){
1477
ret = klogctl(7, NULL, 0);
1482
#endif /* __linux__ */
1483
/* Lower privileges */
1492
/* sleep checking until interface is running */
1493
for(int i=0; i < delay * 4; i++){
1494
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1496
perror("ioctl SIOCGIFFLAGS");
1497
} else if(network.ifr_flags & IFF_RUNNING){
1500
struct timespec sleeptime = { .tv_nsec = 250000000 };
1501
ret = nanosleep(&sleeptime, NULL);
1502
if(ret == -1 and errno != EINTR){
1503
perror("nanosleep");
1506
if(not take_down_interface){
1507
/* We won't need the socket anymore */
1508
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1514
if(restore_loglevel){
1515
/* Restores kernel loglevel to default */
1516
ret = klogctl(7, NULL, 0);
1521
#endif /* __linux__ */
1522
/* Lower privileges */
1524
if(take_down_interface){
1525
/* Lower privileges */
1531
/* Lower privileges permanently */
1543
ret = init_gnutls_global(pubkey, seckey);
1545
fprintf(stderr, "init_gnutls_global failed\n");
1546
exitcode = EX_UNAVAILABLE;
1549
gnutls_initialized = true;
1556
tempdir_created = true;
1557
if(mkdtemp(tempdir) == NULL){
1558
tempdir_created = false;
1567
if(not init_gpgme(pubkey, seckey, tempdir)){
1568
fprintf(stderr, "init_gpgme failed\n");
1569
exitcode = EX_UNAVAILABLE;
1572
gpgme_initialized = true;
1579
if(connect_to != NULL){
1580
/* Connect directly, do not use Zeroconf */
1581
/* (Mainly meant for debugging) */
1582
char *address = strrchr(connect_to, ':');
1583
if(address == NULL){
1584
fprintf(stderr, "No colon in address\n");
1585
exitcode = EX_USAGE;
1595
tmpmax = strtoimax(address+1, &tmp, 10);
1596
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1597
or tmpmax != (uint16_t)tmpmax){
1598
fprintf(stderr, "Bad port number\n");
1599
exitcode = EX_USAGE;
1607
port = (uint16_t)tmpmax;
1609
address = connect_to;
1610
/* Colon in address indicates IPv6 */
1612
if(strchr(address, ':') != NULL){
1622
ret = start_mandos_communication(address, port, if_index, af);
1628
exitcode = EX_NOHOST;
1631
exitcode = EX_USAGE;
1634
exitcode = EX_IOERR;
1637
exitcode = EX_PROTOCOL;
1640
exitcode = EX_OSERR;
1644
exitcode = EXIT_SUCCESS;
657
1654
AvahiServerConfig config;
658
AvahiSServiceBrowser *sb = NULL;
662
int returncode = EXIT_SUCCESS;
663
const char *interface = NULL;
664
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
665
char *connect_to = NULL;
667
debug_int = debug ? 1 : 0;
669
static struct option long_options[] = {
670
{"debug", no_argument, &debug_int, 1},
671
{"connect", required_argument, NULL, 'C'},
672
{"interface", required_argument, NULL, 'i'},
673
{"keydir", required_argument, NULL, 'd'},
674
{"seckey", required_argument, NULL, 'c'},
675
{"pubkey", required_argument, NULL, 'k'},
676
{"dh-bits", required_argument, NULL, 'D'},
679
int option_index = 0;
680
ret = getopt_long (argc, argv, "i:", long_options,
706
dh_bits = atoi(optarg);
714
debug = debug_int ? true : false;
716
pubkeyfile = combinepath(keydir, pubkeyfile);
717
if (pubkeyfile == NULL){
718
perror("combinepath");
722
if(interface != NULL){
723
if_index = (AvahiIfIndex) if_nametoindex(interface);
725
fprintf(stderr, "No such interface: \"%s\"\n", interface);
730
if(connect_to != NULL){
731
/* Connect directly, do not use Zeroconf */
732
/* (Mainly meant for debugging) */
733
char *address = strrchr(connect_to, ':');
735
fprintf(stderr, "No colon in address\n");
739
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
741
perror("Bad port number");
745
address = connect_to;
746
ret = start_mandos_communication(address, port, if_index);
754
seckeyfile = combinepath(keydir, seckeyfile);
755
if (seckeyfile == NULL){
756
perror("combinepath");
761
avahi_set_log_function(empty_log);
764
/* Initialize the psuedo-RNG */
765
srand((unsigned int) time(NULL));
767
/* Allocate main loop object */
768
if (!(simple_poll = avahi_simple_poll_new())) {
769
fprintf(stderr, "Failed to create simple poll object.\n");
774
/* Do not publish any local records */
1655
/* Do not publish any local Zeroconf records */
775
1656
avahi_server_config_init(&config);
776
1657
config.publish_hinfo = 0;
777
1658
config.publish_addresses = 0;
778
1659
config.publish_workstation = 0;
779
1660
config.publish_domain = 0;
781
1662
/* Allocate a new server */
782
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
783
&config, NULL, NULL, &error);
785
/* Free the configuration data */
1663
mc.server = avahi_server_new(avahi_simple_poll_get
1664
(mc.simple_poll), &config, NULL,
1667
/* Free the Avahi configuration data */
786
1668
avahi_server_config_free(&config);
788
/* Check if creating the server object succeeded */
790
fprintf(stderr, "Failed to create server: %s\n",
791
avahi_strerror(error));
792
returncode = EXIT_FAILURE;
796
/* Create the service browser */
797
sb = avahi_s_service_browser_new(server, if_index,
799
"_mandos._tcp", NULL, 0,
800
browse_callback, server);
802
fprintf(stderr, "Failed to create service browser: %s\n",
803
avahi_strerror(avahi_server_errno(server)));
804
returncode = EXIT_FAILURE;
808
/* Run the main loop */
811
fprintf(stderr, "Starting avahi loop search\n");
814
avahi_simple_poll_loop(simple_poll);
819
fprintf(stderr, "%s exiting\n", argv[0]);
824
avahi_s_service_browser_free(sb);
827
avahi_server_free(server);
830
avahi_simple_poll_free(simple_poll);
1671
/* Check if creating the Avahi server object succeeded */
1672
if(mc.server == NULL){
1673
fprintf(stderr, "Failed to create Avahi server: %s\n",
1674
avahi_strerror(error));
1675
exitcode = EX_UNAVAILABLE;
1683
/* Create the Avahi service browser */
1684
sb = avahi_s_service_browser_new(mc.server, if_index,
1685
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1686
NULL, 0, browse_callback, NULL);
1688
fprintf(stderr, "Failed to create service browser: %s\n",
1689
avahi_strerror(avahi_server_errno(mc.server)));
1690
exitcode = EX_UNAVAILABLE;
1698
/* Run the main loop */
1701
fprintf(stderr, "Starting Avahi loop search\n");
1704
avahi_simple_poll_loop(mc.simple_poll);
1709
fprintf(stderr, "%s exiting\n", argv[0]);
1712
/* Cleanup things */
1714
avahi_s_service_browser_free(sb);
1716
if(mc.server != NULL)
1717
avahi_server_free(mc.server);
1719
if(mc.simple_poll != NULL)
1720
avahi_simple_poll_free(mc.simple_poll);
1722
if(gnutls_initialized){
1723
gnutls_certificate_free_credentials(mc.cred);
1724
gnutls_global_deinit();
1725
gnutls_dh_params_deinit(mc.dh_params);
1728
if(gpgme_initialized){
1729
gpgme_release(mc.ctx);
1732
/* Take down the network interface */
1733
if(take_down_interface){
1734
/* Re-raise priviliges */
1741
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1743
perror("ioctl SIOCGIFFLAGS");
1744
} else if(network.ifr_flags & IFF_UP) {
1745
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1746
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1748
perror("ioctl SIOCSIFFLAGS -IFF_UP");
1751
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1755
/* Lower privileges permanently */
1764
/* Removes the temp directory used by GPGME */
1765
if(tempdir_created){
1767
struct dirent *direntry;
1768
d = opendir(tempdir);
1770
if(errno != ENOENT){
1775
direntry = readdir(d);
1776
if(direntry == NULL){
1779
/* Skip "." and ".." */
1780
if(direntry->d_name[0] == '.'
1781
and (direntry->d_name[1] == '\0'
1782
or (direntry->d_name[1] == '.'
1783
and direntry->d_name[2] == '\0'))){
1786
char *fullname = NULL;
1787
ret = asprintf(&fullname, "%s/%s", tempdir,
1793
ret = remove(fullname);
1795
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1802
ret = rmdir(tempdir);
1803
if(ret == -1 and errno != ENOENT){
1809
sigemptyset(&old_sigterm_action.sa_mask);
1810
old_sigterm_action.sa_handler = SIG_DFL;
1811
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
1812
&old_sigterm_action,
1815
perror("sigaction");
1818
ret = raise(signal_received);
1819
} while(ret != 0 and errno == EINTR);
1824
TEMP_FAILURE_RETRY(pause());