47
100
#include <avahi-common/malloc.h>
48
101
#include <avahi-common/error.h>
51
#include <sys/types.h> /* socket(), inet_pton() */
52
#include <sys/socket.h> /* socket(), struct sockaddr_in6,
53
struct in6_addr, inet_pton() */
54
#include <gnutls/gnutls.h> /* All GnuTLS stuff */
55
#include <gnutls/openpgp.h> /* GnuTLS with openpgp stuff */
57
#include <unistd.h> /* close() */
58
#include <netinet/in.h>
59
#include <stdbool.h> /* true */
60
#include <string.h> /* memset */
61
#include <arpa/inet.h> /* inet_pton() */
62
#include <iso646.h> /* not */
65
#include <errno.h> /* perror() */
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,
71
120
#define BUFFER_SIZE 256
74
static const char *certdir = "/conf/conf.d/mandos";
75
static const char *certfile = "openpgp-client.txt";
76
static const char *certkey = "openpgp-client-key.txt";
122
#define PATHDIR "/conf/conf.d/mandos"
123
#define SECKEY "seckey.txt"
124
#define PUBKEY "pubkey.txt"
78
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
135
AvahiSimplePoll *simple_poll;
82
136
AvahiServer *server;
83
137
gnutls_certificate_credentials_t cred;
84
138
unsigned int dh_bits;
139
gnutls_dh_params_t dh_params;
85
140
const char *priority;
88
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
91
gpgme_data_t dh_crypto, dh_plain;
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){
95
ssize_t new_packet_capacity = 0;
96
ssize_t new_packet_length = 0;
97
175
gpgme_engine_info_t engine_info;
100
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");
104
219
gpgme_check_version(NULL);
105
220
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
106
if (rc != GPG_ERR_NO_ERROR){
221
if(rc != GPG_ERR_NO_ERROR){
107
222
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
108
223
gpgme_strsource(rc), gpgme_strerror(rc));
112
/* Set GPGME home directory */
113
rc = gpgme_get_engine_info (&engine_info);
114
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){
115
230
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
116
231
gpgme_strsource(rc), gpgme_strerror(rc));
119
234
while(engine_info != NULL){
120
235
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
121
236
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
122
engine_info->file_name, homedir);
237
engine_info->file_name, tempdir);
125
240
engine_info = engine_info->next;
127
242
if(engine_info == NULL){
128
fprintf(stderr, "Could not set home dir to %s\n", homedir);
132
/* Create new GPGME data buffer from packet buffer */
133
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
134
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){
135
283
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
136
284
gpgme_strsource(rc), gpgme_strerror(rc));
198
/* Delete the GPGME FILE pointer cryptotext data buffer */
199
gpgme_data_release(dh_crypto);
334
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
201
337
/* Seek back to the beginning of the GPGME plaintext data buffer */
202
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
203
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;
208
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
209
*new_packet = realloc(*new_packet,
210
(unsigned int)new_packet_capacity
212
if (*new_packet == NULL){
216
new_packet_capacity += BUFFER_SIZE;
346
plaintext_capacity = incbuffer(plaintext,
347
(size_t)plaintext_length,
349
if(plaintext_capacity == 0){
351
plaintext_length = -1;
219
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
355
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
221
357
/* Print the data, if any */
226
363
perror("gpgme_data_read");
229
new_packet_length += ret;
232
/* FIXME: check characters before printing to screen so to not print
233
terminal control characters */
235
/* fprintf(stderr, "decrypted password is: "); */
236
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
237
/* 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);
240
383
/* Delete the GPGME plaintext data buffer */
241
384
gpgme_data_release(dh_plain);
242
return new_packet_length;
385
return plaintext_length;
245
static const char * safer_gnutls_strerror (int value) {
246
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 */
248
392
ret = "(unknown)";
396
/* GnuTLS log function callback */
252
397
static void debuggnutls(__attribute__((unused)) int level,
253
398
const char* string){
254
fprintf(stderr, "%s", string);
399
fprintf(stderr, "GnuTLS: %s", string);
257
static int initgnutls(mandos_context *mc){
402
static int init_gnutls_global(const char *pubkeyfilename,
403
const char *seckeyfilename){
262
407
fprintf(stderr, "Initializing GnuTLS\n");
265
if ((ret = gnutls_global_init ())
266
!= GNUTLS_E_SUCCESS) {
267
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."
272
421
gnutls_global_set_log_level(11);
273
422
gnutls_global_set_log_function(debuggnutls);
276
/* openpgp credentials */
277
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
278
!= GNUTLS_E_SUCCESS) {
279
fprintf (stderr, "memory error: %s\n",
280
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();
285
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
286
" and keyfile %s as GnuTLS credentials\n", certfile,
438
fprintf(stderr, "Attempting to use OpenPGP public key %s and"
439
" secret key %s as GnuTLS credentials\n", pubkeyfilename,
290
443
ret = gnutls_certificate_set_openpgp_key_file
291
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
292
if (ret != GNUTLS_E_SUCCESS) {
294
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
296
ret, certfile, certkey);
297
fprintf(stdout, "The Error is: %s\n",
298
safer_gnutls_strerror(ret));
302
//GnuTLS server initialization
303
if ((ret = gnutls_dh_params_init (&es->dh_params))
304
!= GNUTLS_E_SUCCESS) {
305
fprintf (stderr, "Error in dh parameter initialization: %s\n",
306
safer_gnutls_strerror(ret));
310
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
311
!= GNUTLS_E_SUCCESS) {
312
fprintf (stderr, "Error in prime generation: %s\n",
313
safer_gnutls_strerror(ret));
317
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
319
// GnuTLS session creation
320
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
321
!= 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){
322
491
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
323
492
safer_gnutls_strerror(ret));
326
if ((ret = gnutls_priority_set_direct (es->session, mc->priority, &err))
327
!= GNUTLS_E_SUCCESS) {
328
fprintf(stderr, "Syntax error at: %s\n", err);
329
fprintf(stderr, "GnuTLS error: %s\n",
330
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);
334
if ((ret = gnutls_credentials_set
335
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
336
!= GNUTLS_E_SUCCESS) {
337
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",
338
523
safer_gnutls_strerror(ret));
524
gnutls_deinit(*session);
342
528
/* ignore client certificate if any. */
343
gnutls_certificate_server_set_request (es->session,
529
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
346
gnutls_dh_set_prime_bits (es->session, DH_BITS);
531
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
536
/* Avahi log function callback */
351
537
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
352
538
__attribute__((unused)) const char *txt){}
540
/* Called when a Mandos server is found */
354
541
static int start_mandos_communication(const char *ip, uint16_t port,
355
542
AvahiIfIndex if_index,
358
struct sockaddr_in6 to;
359
encrypted_session es;
544
int ret, tcp_sd = -1;
547
struct sockaddr_in in;
548
struct sockaddr_in6 in6;
360
550
char *buffer = NULL;
361
char *decrypted_buffer;
551
char *decrypted_buffer = NULL;
362
552
size_t buffer_length = 0;
363
553
size_t buffer_capacity = 0;
364
ssize_t decrypted_buffer_size;
367
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);
370
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
585
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
374
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
589
tcp_sd = socket(pf, SOCK_STREAM, 0);
376
592
perror("socket");
381
if(if_indextoname((unsigned int)if_index, interface) == NULL){
383
perror("if_indextoname");
388
fprintf(stderr, "Binding to interface %s\n", interface);
391
memset(&to,0,sizeof(to)); /* Spurious warning */
392
to.sin6_family = AF_INET6;
393
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);
395
612
perror("inet_pton");
399
618
fprintf(stderr, "Bad address: %s\n", ip);
402
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 */
404
to.sin6_scope_id = (uint32_t)if_index;
407
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
408
/* char addrstr[INET6_ADDRSTRLEN]; */
409
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
410
/* sizeof(addrstr)) == NULL){ */
411
/* perror("inet_ntop"); */
413
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
414
/* addrstr, ntohs(to.sin6_port)); */
418
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
424
ret = initgnutls (&es);
430
gnutls_transport_set_ptr (es.session,
431
(gnutls_transport_ptr_t) tcp_sd);
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,
676
if(strcmp(addrstr, ip) != 0){
677
fprintf(stderr, "Canonical address form: %s\n", addrstr);
688
ret = connect(tcp_sd, &to.in6, sizeof(to));
690
ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
693
if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
706
const char *out = mandos_protocol_version;
709
size_t out_size = strlen(out);
710
ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
711
out_size - written));
718
written += (size_t)ret;
719
if(written < out_size){
722
if(out == mandos_protocol_version){
434
737
fprintf(stderr, "Establishing TLS session with %s\n", ip);
437
ret = gnutls_handshake (es.session);
439
if (ret != GNUTLS_E_SUCCESS){
745
gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
753
ret = gnutls_handshake(session);
758
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
760
if(ret != GNUTLS_E_SUCCESS){
441
fprintf(stderr, "\n*** Handshake failed ***\n");
762
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
448
//Retrieve OpenPGP packet that contains the wanted password
769
/* Read OpenPGP packet that contains the wanted password */
451
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
772
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);
783
buffer_capacity = incbuffer(&buffer, buffer_length,
785
if(buffer_capacity == 0){
797
sret = gnutls_record_recv(session, buffer+buffer_length,
472
804
case GNUTLS_E_INTERRUPTED:
473
805
case GNUTLS_E_AGAIN:
475
807
case GNUTLS_E_REHANDSHAKE:
476
ret = gnutls_handshake (es.session);
478
fprintf(stderr, "\n*** Handshake failed ***\n");
809
ret = gnutls_handshake(session);
815
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
817
fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
485
824
fprintf(stderr, "Unknown error while reading data from"
486
" encrypted session with mandos server\n");
488
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
825
" encrypted session with Mandos server\n");
826
gnutls_bye(session, GNUTLS_SHUT_RDWR);
492
buffer_length += (size_t) ret;
496
if (buffer_length > 0){
831
buffer_length += (size_t) sret;
836
fprintf(stderr, "Closing TLS session\n");
845
ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
850
} while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
852
if(buffer_length > 0){
853
ssize_t decrypted_buffer_size;
497
854
decrypted_buffer_size = pgp_packet_decrypt(buffer,
501
if (decrypted_buffer_size >= 0){
857
if(decrypted_buffer_size >= 0){
502
860
while(written < (size_t) decrypted_buffer_size){
503
ret = (int)fwrite (decrypted_buffer + written, 1,
504
(size_t)decrypted_buffer_size - written,
866
ret = (int)fwrite(decrypted_buffer + written, 1,
867
(size_t)decrypted_buffer_size - written,
506
869
if(ret == 0 and ferror(stdout)){
508
872
fprintf(stderr, "Error writing encrypted data: %s\n",
509
873
strerror(errno));
514
878
written += (size_t)ret;
516
free(decrypted_buffer);
884
/* Shutdown procedure */
889
free(decrypted_buffer);
892
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
900
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 void resolve_callback( AvahiSServiceResolver *r,
539
AvahiIfIndex interface,
540
AVAHI_GCC_UNUSED AvahiProtocol protocol,
541
AvahiResolverEvent event,
545
const char *host_name,
546
const AvahiAddress *address,
548
AVAHI_GCC_UNUSED AvahiStringList *txt,
549
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
550
AVAHI_GCC_UNUSED void* userdata) {
551
mandos_context *mc = userdata;
552
assert(r); /* Spurious warning */
910
static void resolve_callback(AvahiSServiceResolver *r,
911
AvahiIfIndex interface,
913
AvahiResolverEvent event,
917
const char *host_name,
918
const AvahiAddress *address,
920
AVAHI_GCC_UNUSED AvahiStringList *txt,
921
AVAHI_GCC_UNUSED AvahiLookupResultFlags
923
AVAHI_GCC_UNUSED void* userdata){
554
926
/* Called whenever a service has been resolved successfully or
559
935
case AVAHI_RESOLVER_FAILURE:
560
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
561
" type '%s' in domain '%s': %s\n", name, type, domain,
562
avahi_strerror(avahi_server_errno(mc->server)));
936
fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
937
" of type '%s' in domain '%s': %s\n", name, type, domain,
938
avahi_strerror(avahi_server_errno(mc.server)));
565
941
case AVAHI_RESOLVER_FOUND:
567
943
char ip[AVAHI_ADDRESS_STR_MAX];
568
944
avahi_address_snprint(ip, sizeof(ip), address);
570
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
571
" port %d\n", name, host_name, ip, port);
946
fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
947
PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
948
ip, (intmax_t)interface, port);
573
int ret = start_mandos_communication(ip, port, interface, mc);
950
int ret = start_mandos_communication(ip, port, interface,
951
avahi_proto_to_af(proto));
953
avahi_simple_poll_quit(mc.simple_poll);
579
957
avahi_s_service_resolver_free(r);
582
static void browse_callback( AvahiSServiceBrowser *b,
583
AvahiIfIndex interface,
584
AvahiProtocol protocol,
585
AvahiBrowserEvent event,
589
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
591
mandos_context *mc = userdata;
592
assert(b); /* Spurious warning */
960
static void browse_callback(AvahiSServiceBrowser *b,
961
AvahiIfIndex interface,
962
AvahiProtocol protocol,
963
AvahiBrowserEvent event,
967
AVAHI_GCC_UNUSED AvahiLookupResultFlags
969
AVAHI_GCC_UNUSED void* userdata){
594
972
/* Called whenever a new services becomes available on the LAN or
595
973
is removed from the LAN */
599
981
case AVAHI_BROWSER_FAILURE:
601
fprintf(stderr, "(Browser) %s\n",
602
avahi_strerror(avahi_server_errno(mc->server)));
603
avahi_simple_poll_quit(mc->simple_poll);
983
fprintf(stderr, "(Avahi browser) %s\n",
984
avahi_strerror(avahi_server_errno(mc.server)));
985
avahi_simple_poll_quit(mc.simple_poll);
606
988
case AVAHI_BROWSER_NEW:
607
/* We ignore the returned resolver object. In the callback
608
function we free it. If the server is terminated before
609
the callback function is called the server will free
610
the resolver for us. */
612
if (!(avahi_s_service_resolver_new(mc->server, interface, protocol, name,
614
AVAHI_PROTO_INET6, 0,
615
resolve_callback, mc)))
616
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
617
avahi_strerror(avahi_server_errno(s)));
989
/* We ignore the returned Avahi resolver object. In the callback
990
function we free it. If the Avahi server is terminated before
991
the callback function is called the Avahi server will free the
994
if(avahi_s_service_resolver_new(mc.server, interface, protocol,
995
name, type, domain, protocol, 0,
996
resolve_callback, NULL) == NULL)
997
fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
998
name, avahi_strerror(avahi_server_errno(mc.server)));
620
1001
case AVAHI_BROWSER_REMOVE:
623
1004
case AVAHI_BROWSER_ALL_FOR_NOW:
624
1005
case AVAHI_BROWSER_CACHE_EXHAUSTED:
1007
fprintf(stderr, "No Mandos server found, still searching...\n");
629
/* Combines file name and path and returns the malloced new
630
string. some sane checks could/should be added */
631
static const char *combinepath(const char *first, const char *second){
632
size_t f_len = strlen(first);
633
size_t s_len = strlen(second);
634
char *tmp = malloc(f_len + s_len + 2);
639
memcpy(tmp, first, f_len);
643
memcpy(tmp + f_len + 1, second, s_len);
645
tmp[f_len + 1 + s_len] = '\0';
650
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
651
AvahiServerConfig config;
652
AvahiSServiceBrowser *sb = NULL;
655
int returncode = EXIT_SUCCESS;
656
const char *interface = "eth0";
657
struct ifreq network;
659
char *connect_to = NULL;
660
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
661
mandos_context mc = { .simple_poll = NULL, .server = NULL,
662
.dh_bits = 2048, .priority = "SECURE256"};
1013
/* stop main loop after sigterm has been called */
1014
static void handle_sigterm(int sig){
1019
signal_received = sig;
1020
int old_errno = errno;
1021
if(mc.simple_poll != NULL){
1022
avahi_simple_poll_quit(mc.simple_poll);
1028
* This function determines if a directory entry in /sys/class/net
1029
* corresponds to an acceptable network device.
1030
* (This function is passed to scandir(3) as a filter function.)
1032
int good_interface(const struct dirent *if_entry){
1034
char *flagname = NULL;
1035
int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
1041
if(if_entry->d_name[0] == '.'){
1044
int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
1049
typedef short ifreq_flags; /* ifreq.ifr_flags in netdevice(7) */
1050
/* read line from flags_fd */
1051
ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
1052
char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
1053
flagstring[(size_t)to_read] = '\0';
1054
if(flagstring == NULL){
1060
ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
1077
tmpmax = strtoimax(flagstring, &tmp, 0);
1078
if(errno != 0 or tmp == flagstring or (*tmp != '\0'
1079
and not (isspace(*tmp)))
1080
or tmpmax != (ifreq_flags)tmpmax){
1082
fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
1083
flagstring, if_entry->d_name);
1089
ifreq_flags flags = (ifreq_flags)tmpmax;
1090
/* Reject the loopback device */
1091
if(flags & IFF_LOOPBACK){
1093
fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1098
/* Accept point-to-point devices only if connect_to is specified */
1099
if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1101
fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1106
/* Otherwise, reject non-broadcast-capable devices */
1107
if(not (flags & IFF_BROADCAST)){
1109
fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1114
/* Accept this device */
1116
fprintf(stderr, "Interface \"%s\" is acceptable\n",
1122
int main(int argc, char *argv[]){
1123
AvahiSServiceBrowser *sb = NULL;
1128
int exitcode = EXIT_SUCCESS;
1129
const char *interface = "";
1130
struct ifreq network;
1132
bool take_down_interface = false;
1135
char tempdir[] = "/tmp/mandosXXXXXX";
1136
bool tempdir_created = false;
1137
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1138
const char *seckey = PATHDIR "/" SECKEY;
1139
const char *pubkey = PATHDIR "/" PUBKEY;
1141
bool gnutls_initialized = false;
1142
bool gpgme_initialized = false;
1145
struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
1146
struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
1151
/* Lower any group privileges we might have, just to be safe */
1158
/* Lower user privileges (temporarily) */
1170
struct argp_option options[] = {
1171
{ .name = "debug", .key = 128,
1172
.doc = "Debug mode", .group = 3 },
1173
{ .name = "connect", .key = 'c',
1174
.arg = "ADDRESS:PORT",
1175
.doc = "Connect directly to a specific Mandos server",
1177
{ .name = "interface", .key = 'i',
1179
.doc = "Network interface that will be used to search for"
1182
{ .name = "seckey", .key = 's',
1184
.doc = "OpenPGP secret key file base name",
1186
{ .name = "pubkey", .key = 'p',
1188
.doc = "OpenPGP public key file base name",
1190
{ .name = "dh-bits", .key = 129,
1192
.doc = "Bit length of the prime number used in the"
1193
" Diffie-Hellman key exchange",
1195
{ .name = "priority", .key = 130,
1197
.doc = "GnuTLS priority string for the TLS handshake",
1199
{ .name = "delay", .key = 131,
1201
.doc = "Maximum delay to wait for interface startup",
1204
* These reproduce what we would get without ARGP_NO_HELP
1206
{ .name = "help", .key = '?',
1207
.doc = "Give this help list", .group = -1 },
1208
{ .name = "usage", .key = -3,
1209
.doc = "Give a short usage message", .group = -1 },
1210
{ .name = "version", .key = 'V',
1211
.doc = "Print program version", .group = -1 },
665
static struct option long_options[] = {
666
{"debug", no_argument, (int *)&debug, 1},
667
{"connect", required_argument, 0, 'C'},
668
{"interface", required_argument, 0, 'i'},
669
{"certdir", required_argument, 0, 'd'},
670
{"certkey", required_argument, 0, 'c'},
671
{"certfile", required_argument, 0, 'k'},
672
{"dh_bits", required_argument, 0, 'D'},
673
{"priority", required_argument, 0, 'p'},
676
int option_index = 0;
677
ret = getopt_long (argc, argv, "i:", long_options,
706
tmp = strtol(optarg, NULL, 10);
707
if (errno == ERANGE){
715
mc.priority = optarg;
1215
error_t parse_opt(int key, char *arg,
1216
struct argp_state *state){
1219
case 128: /* --debug */
1222
case 'c': /* --connect */
1225
case 'i': /* --interface */
1228
case 's': /* --seckey */
1231
case 'p': /* --pubkey */
1234
case 129: /* --dh-bits */
1236
tmpmax = strtoimax(arg, &tmp, 10);
1237
if(errno != 0 or tmp == arg or *tmp != '\0'
1238
or tmpmax != (typeof(mc.dh_bits))tmpmax){
1239
argp_error(state, "Bad number of DH bits");
1241
mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
1243
case 130: /* --priority */
1246
case 131: /* --delay */
1248
delay = strtof(arg, &tmp);
1249
if(errno != 0 or tmp == arg or *tmp != '\0'){
1250
argp_error(state, "Bad delay");
1254
* These reproduce what we would get without ARGP_NO_HELP
1256
case '?': /* --help */
1257
argp_state_help(state, state->out_stream,
1258
(ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
1259
& ~(unsigned int)ARGP_HELP_EXIT_OK);
1260
case -3: /* --usage */
1261
argp_state_help(state, state->out_stream,
1262
ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
1263
case 'V': /* --version */
1264
fprintf(state->out_stream, "%s\n", argp_program_version);
1265
exit(argp_err_exit_status);
1268
return ARGP_ERR_UNKNOWN;
722
certfile = combinepath(certdir, certfile);
723
if (certfile == NULL){
724
perror("combinepath");
725
returncode = EXIT_FAILURE;
1273
struct argp argp = { .options = options, .parser = parse_opt,
1275
.doc = "Mandos client -- Get and decrypt"
1276
" passwords from a Mandos server" };
1277
ret = argp_parse(&argp, argc, argv,
1278
ARGP_IN_ORDER | ARGP_NO_HELP, 0, NULL);
1285
perror("argp_parse");
1286
exitcode = EX_OSERR;
1289
exitcode = EX_USAGE;
1295
avahi_set_log_function(empty_log);
729
certkey = combinepath(certdir, certkey);
730
if (certkey == NULL){
731
perror("combinepath");
732
returncode = EXIT_FAILURE;
1298
if(interface[0] == '\0'){
1299
struct dirent **direntries;
1300
ret = scandir(sys_class_net, &direntries, good_interface,
1303
/* Pick the first good interface */
1304
interface = strdup(direntries[0]->d_name);
1306
fprintf(stderr, "Using interface \"%s\"\n", interface);
1308
if(interface == NULL){
1311
exitcode = EXIT_FAILURE;
1317
fprintf(stderr, "Could not find a network interface\n");
1318
exitcode = EXIT_FAILURE;
1323
/* Initialize Avahi early so avahi_simple_poll_quit() can be called
1324
from the signal handler */
1325
/* Initialize the pseudo-RNG for Avahi */
1326
srand((unsigned int) time(NULL));
1327
mc.simple_poll = avahi_simple_poll_new();
1328
if(mc.simple_poll == NULL){
1329
fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1330
exitcode = EX_UNAVAILABLE;
1334
sigemptyset(&sigterm_action.sa_mask);
1335
ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1337
perror("sigaddset");
1338
exitcode = EX_OSERR;
1341
ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1343
perror("sigaddset");
1344
exitcode = EX_OSERR;
1347
ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1349
perror("sigaddset");
1350
exitcode = EX_OSERR;
1353
/* Need to check if the handler is SIG_IGN before handling:
1354
| [[info:libc:Initial Signal Actions]] |
1355
| [[info:libc:Basic Signal Handling]] |
1357
ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1359
perror("sigaction");
1362
if(old_sigterm_action.sa_handler != SIG_IGN){
1363
ret = sigaction(SIGINT, &sigterm_action, NULL);
1365
perror("sigaction");
1366
exitcode = EX_OSERR;
1370
ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1372
perror("sigaction");
1375
if(old_sigterm_action.sa_handler != SIG_IGN){
1376
ret = sigaction(SIGHUP, &sigterm_action, NULL);
1378
perror("sigaction");
1379
exitcode = EX_OSERR;
1383
ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1385
perror("sigaction");
1388
if(old_sigterm_action.sa_handler != SIG_IGN){
1389
ret = sigaction(SIGTERM, &sigterm_action, NULL);
1391
perror("sigaction");
1392
exitcode = EX_OSERR;
1397
/* If the interface is down, bring it up */
1398
if(strcmp(interface, "none") != 0){
736
1399
if_index = (AvahiIfIndex) if_nametoindex(interface);
737
1400
if(if_index == 0){
738
1401
fprintf(stderr, "No such interface: \"%s\"\n", interface);
742
if(connect_to != NULL){
743
/* Connect directly, do not use Zeroconf */
744
/* (Mainly meant for debugging) */
745
char *address = strrchr(connect_to, ':');
747
fprintf(stderr, "No colon in address\n");
751
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
753
perror("Bad port number");
757
address = connect_to;
758
ret = start_mandos_communication(address, port, if_index);
1402
exitcode = EX_UNAVAILABLE;
1410
/* Re-raise priviliges */
1418
/* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1419
messages about the network interface to mess up the prompt */
1420
ret = klogctl(8, NULL, 5);
1421
bool restore_loglevel = true;
1423
restore_loglevel = false;
1426
#endif /* __linux__ */
766
1428
sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
768
1430
perror("socket");
769
returncode = EXIT_FAILURE;
1431
exitcode = EX_OSERR;
1433
if(restore_loglevel){
1434
ret = klogctl(7, NULL, 0);
1439
#endif /* __linux__ */
1440
/* Lower privileges */
772
strcpy(network.ifr_name, interface);
1448
strcpy(network.ifr_name, interface);
773
1449
ret = ioctl(sd, SIOCGIFFLAGS, &network);
776
1451
perror("ioctl SIOCGIFFLAGS");
777
returncode = EXIT_FAILURE;
1453
if(restore_loglevel){
1454
ret = klogctl(7, NULL, 0);
1459
#endif /* __linux__ */
1460
exitcode = EX_OSERR;
1461
/* Lower privileges */
780
1469
if((network.ifr_flags & IFF_UP) == 0){
781
1470
network.ifr_flags |= IFF_UP;
1471
take_down_interface = true;
782
1472
ret = ioctl(sd, SIOCSIFFLAGS, &network);
784
perror("ioctl SIOCSIFFLAGS");
785
returncode = EXIT_FAILURE;
792
avahi_set_log_function(empty_log);
795
/* Initialize the psuedo-RNG */
796
srand((unsigned int) time(NULL));
798
/* Allocate main loop object */
799
if (!(mc.simple_poll = avahi_simple_poll_new())) {
800
fprintf(stderr, "Failed to create simple poll object.\n");
801
returncode = EXIT_FAILURE;
805
/* Do not publish any local records */
1474
take_down_interface = false;
1475
perror("ioctl SIOCSIFFLAGS +IFF_UP");
1476
exitcode = EX_OSERR;
1478
if(restore_loglevel){
1479
ret = klogctl(7, NULL, 0);
1484
#endif /* __linux__ */
1485
/* Lower privileges */
1494
/* sleep checking until interface is running */
1495
for(int i=0; i < delay * 4; i++){
1496
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1498
perror("ioctl SIOCGIFFLAGS");
1499
} else if(network.ifr_flags & IFF_RUNNING){
1502
struct timespec sleeptime = { .tv_nsec = 250000000 };
1503
ret = nanosleep(&sleeptime, NULL);
1504
if(ret == -1 and errno != EINTR){
1505
perror("nanosleep");
1508
if(not take_down_interface){
1509
/* We won't need the socket anymore */
1510
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1516
if(restore_loglevel){
1517
/* Restores kernel loglevel to default */
1518
ret = klogctl(7, NULL, 0);
1523
#endif /* __linux__ */
1524
/* Lower privileges */
1526
if(take_down_interface){
1527
/* Lower privileges */
1533
/* Lower privileges permanently */
1545
ret = init_gnutls_global(pubkey, seckey);
1547
fprintf(stderr, "init_gnutls_global failed\n");
1548
exitcode = EX_UNAVAILABLE;
1551
gnutls_initialized = true;
1558
tempdir_created = true;
1559
if(mkdtemp(tempdir) == NULL){
1560
tempdir_created = false;
1569
if(not init_gpgme(pubkey, seckey, tempdir)){
1570
fprintf(stderr, "init_gpgme failed\n");
1571
exitcode = EX_UNAVAILABLE;
1574
gpgme_initialized = true;
1581
if(connect_to != NULL){
1582
/* Connect directly, do not use Zeroconf */
1583
/* (Mainly meant for debugging) */
1584
char *address = strrchr(connect_to, ':');
1585
if(address == NULL){
1586
fprintf(stderr, "No colon in address\n");
1587
exitcode = EX_USAGE;
1597
tmpmax = strtoimax(address+1, &tmp, 10);
1598
if(errno != 0 or tmp == address+1 or *tmp != '\0'
1599
or tmpmax != (uint16_t)tmpmax){
1600
fprintf(stderr, "Bad port number\n");
1601
exitcode = EX_USAGE;
1609
port = (uint16_t)tmpmax;
1611
address = connect_to;
1612
/* Colon in address indicates IPv6 */
1614
if(strchr(address, ':') != NULL){
1624
while(not quit_now){
1625
ret = start_mandos_communication(address, port, if_index, af);
1626
if(quit_now or ret == 0){
1633
exitcode = EXIT_SUCCESS;
1644
AvahiServerConfig config;
1645
/* Do not publish any local Zeroconf records */
806
1646
avahi_server_config_init(&config);
807
1647
config.publish_hinfo = 0;
808
1648
config.publish_addresses = 0;
809
1649
config.publish_workstation = 0;
810
1650
config.publish_domain = 0;
812
1652
/* Allocate a new server */
813
mc.server = avahi_server_new(avahi_simple_poll_get(simple_poll),
814
&config, NULL, NULL, &error);
816
/* Free the configuration data */
1653
mc.server = avahi_server_new(avahi_simple_poll_get
1654
(mc.simple_poll), &config, NULL,
1657
/* Free the Avahi configuration data */
817
1658
avahi_server_config_free(&config);
819
/* Check if creating the server object succeeded */
821
fprintf(stderr, "Failed to create server: %s\n",
822
avahi_strerror(error));
823
returncode = EXIT_FAILURE;
827
/* Create the service browser */
828
sb = avahi_s_service_browser_new(mc.server, if_index,
830
"_mandos._tcp", NULL, 0,
831
browse_callback, &mc);
833
fprintf(stderr, "Failed to create service browser: %s\n",
834
avahi_strerror(avahi_server_errno(mc.server)));
835
returncode = EXIT_FAILURE;
839
/* Run the main loop */
842
fprintf(stderr, "Starting avahi loop search\n");
845
avahi_simple_poll_loop(simple_poll);
850
fprintf(stderr, "%s exiting\n", argv[0]);
855
avahi_s_service_browser_free(sb);
858
avahi_server_free(mc.server);
861
avahi_simple_poll_free(simple_poll);
1661
/* Check if creating the Avahi server object succeeded */
1662
if(mc.server == NULL){
1663
fprintf(stderr, "Failed to create Avahi server: %s\n",
1664
avahi_strerror(error));
1665
exitcode = EX_UNAVAILABLE;
1673
/* Create the Avahi service browser */
1674
sb = avahi_s_service_browser_new(mc.server, if_index,
1675
AVAHI_PROTO_UNSPEC, "_mandos._tcp",
1676
NULL, 0, browse_callback, NULL);
1678
fprintf(stderr, "Failed to create service browser: %s\n",
1679
avahi_strerror(avahi_server_errno(mc.server)));
1680
exitcode = EX_UNAVAILABLE;
1688
/* Run the main loop */
1691
fprintf(stderr, "Starting Avahi loop search\n");
1694
avahi_simple_poll_loop(mc.simple_poll);
1699
fprintf(stderr, "%s exiting\n", argv[0]);
1702
/* Cleanup things */
1704
avahi_s_service_browser_free(sb);
1706
if(mc.server != NULL)
1707
avahi_server_free(mc.server);
1709
if(mc.simple_poll != NULL)
1710
avahi_simple_poll_free(mc.simple_poll);
1712
if(gnutls_initialized){
1713
gnutls_certificate_free_credentials(mc.cred);
1714
gnutls_global_deinit();
1715
gnutls_dh_params_deinit(mc.dh_params);
1718
if(gpgme_initialized){
1719
gpgme_release(mc.ctx);
1722
/* Take down the network interface */
1723
if(take_down_interface){
1724
/* Re-raise priviliges */
1731
ret = ioctl(sd, SIOCGIFFLAGS, &network);
1733
perror("ioctl SIOCGIFFLAGS");
1734
} else if(network.ifr_flags & IFF_UP) {
1735
network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1736
ret = ioctl(sd, SIOCSIFFLAGS, &network);
1738
perror("ioctl SIOCSIFFLAGS -IFF_UP");
1741
ret = (int)TEMP_FAILURE_RETRY(close(sd));
1745
/* Lower privileges permanently */
1754
/* Removes the temp directory used by GPGME */
1755
if(tempdir_created){
1757
struct dirent *direntry;
1758
d = opendir(tempdir);
1760
if(errno != ENOENT){
1765
direntry = readdir(d);
1766
if(direntry == NULL){
1769
/* Skip "." and ".." */
1770
if(direntry->d_name[0] == '.'
1771
and (direntry->d_name[1] == '\0'
1772
or (direntry->d_name[1] == '.'
1773
and direntry->d_name[2] == '\0'))){
1776
char *fullname = NULL;
1777
ret = asprintf(&fullname, "%s/%s", tempdir,
1783
ret = remove(fullname);
1785
fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
1792
ret = rmdir(tempdir);
1793
if(ret == -1 and errno != ENOENT){
1799
sigemptyset(&old_sigterm_action.sa_mask);
1800
old_sigterm_action.sa_handler = SIG_DFL;
1801
ret = (int)TEMP_FAILURE_RETRY(sigaction(signal_received,
1802
&old_sigterm_action,
1805
perror("sigaction");
1808
ret = raise(signal_received);
1809
} while(ret != 0 and errno == EINTR);
1814
TEMP_FAILURE_RETRY(pause());