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
72
const char *certdir = "/conf/conf.d/cryptkeyreq/";
73
const char *certfile = "openpgp-client.txt";
74
const char *certkey = "openpgp-client-key.txt";
122
#define PATHDIR "/conf/conf.d/mandos"
123
#define SECKEY "seckey.txt"
124
#define PUBKEY "pubkey.txt"
76
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 */
79
gnutls_session_t session;
135
AvahiSimplePoll *simple_poll;
80
137
gnutls_certificate_credentials_t cred;
138
unsigned int dh_bits;
81
139
gnutls_dh_params_t dh_params;
85
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
86
char **new_packet, const char *homedir){
87
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){
91
ssize_t new_packet_capacity = 0;
92
ssize_t new_packet_length = 0;
93
175
gpgme_engine_info_t engine_info;
96
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");
100
219
gpgme_check_version(NULL);
101
220
rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
102
if (rc != GPG_ERR_NO_ERROR){
221
if(rc != GPG_ERR_NO_ERROR){
103
222
fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
104
223
gpgme_strsource(rc), gpgme_strerror(rc));
108
/* Set GPGME home directory */
109
rc = gpgme_get_engine_info (&engine_info);
110
if (rc != GPG_ERR_NO_ERROR){
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){
111
230
fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
112
231
gpgme_strsource(rc), gpgme_strerror(rc));
115
234
while(engine_info != NULL){
116
235
if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
117
236
gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
118
engine_info->file_name, homedir);
237
engine_info->file_name, tempdir);
121
240
engine_info = engine_info->next;
123
242
if(engine_info == NULL){
124
fprintf(stderr, "Could not set home dir to %s\n", homedir);
128
/* Create new GPGME data buffer from packet buffer */
129
rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
130
if (rc != GPG_ERR_NO_ERROR){
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){
131
283
fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
132
284
gpgme_strsource(rc), gpgme_strerror(rc));
194
/* Delete the GPGME FILE pointer cryptotext data buffer */
195
gpgme_data_release(dh_crypto);
334
fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
197
337
/* Seek back to the beginning of the GPGME plaintext data buffer */
198
if (gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET) == -1){
199
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;
204
if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
205
*new_packet = realloc(*new_packet,
206
(unsigned int)new_packet_capacity
208
if (*new_packet == NULL){
212
new_packet_capacity += BUFFER_SIZE;
346
plaintext_capacity = incbuffer(plaintext,
347
(size_t)plaintext_length,
349
if(plaintext_capacity == 0){
351
plaintext_length = -1;
215
ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
355
ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
217
357
/* Print the data, if any */
222
363
perror("gpgme_data_read");
225
new_packet_length += ret;
228
/* FIXME: check characters before printing to screen so to not print
229
terminal control characters */
231
/* fprintf(stderr, "decrypted password is: "); */
232
/* fwrite(*new_packet, 1, new_packet_length, stderr); */
233
/* 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);
236
383
/* Delete the GPGME plaintext data buffer */
237
384
gpgme_data_release(dh_plain);
238
return new_packet_length;
385
return plaintext_length;
241
static const char * safer_gnutls_strerror (int value) {
242
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 */
244
392
ret = "(unknown)";
248
void debuggnutls(__attribute__((unused)) int level,
250
fprintf(stderr, "%s", string);
396
/* GnuTLS log function callback */
397
static void debuggnutls(__attribute__((unused)) int level,
399
fprintf(stderr, "GnuTLS: %s", string);
253
int initgnutls(encrypted_session *es){
402
static int init_gnutls_global(const char *pubkeyfilename,
403
const char *seckeyfilename){
258
407
fprintf(stderr, "Initializing GnuTLS\n");
261
if ((ret = gnutls_global_init ())
262
!= GNUTLS_E_SUCCESS) {
263
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."
268
421
gnutls_global_set_log_level(11);
269
422
gnutls_global_set_log_function(debuggnutls);
272
/* openpgp credentials */
273
if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
274
!= GNUTLS_E_SUCCESS) {
275
fprintf (stderr, "memory error: %s\n",
276
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();
281
fprintf(stderr, "Attempting to use OpenPGP certificate %s"
282
" 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,
286
443
ret = gnutls_certificate_set_openpgp_key_file
287
(es->cred, certfile, certkey, GNUTLS_OPENPGP_FMT_BASE64);
288
if (ret != GNUTLS_E_SUCCESS) {
290
(stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
292
ret, certfile, certkey);
293
fprintf(stdout, "The Error is: %s\n",
294
safer_gnutls_strerror(ret));
298
//GnuTLS server initialization
299
if ((ret = gnutls_dh_params_init (&es->dh_params))
300
!= GNUTLS_E_SUCCESS) {
301
fprintf (stderr, "Error in dh parameter initialization: %s\n",
302
safer_gnutls_strerror(ret));
306
if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
307
!= GNUTLS_E_SUCCESS) {
308
fprintf (stderr, "Error in prime generation: %s\n",
309
safer_gnutls_strerror(ret));
313
gnutls_certificate_set_dh_params (es->cred, es->dh_params);
315
// GnuTLS session creation
316
if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
317
!= 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){
318
491
fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
319
492
safer_gnutls_strerror(ret));
322
if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
323
!= GNUTLS_E_SUCCESS) {
324
fprintf(stderr, "Syntax error at: %s\n", err);
325
fprintf(stderr, "GnuTLS error: %s\n",
326
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);
330
if ((ret = gnutls_credentials_set
331
(es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
332
!= GNUTLS_E_SUCCESS) {
333
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",
334
523
safer_gnutls_strerror(ret));
524
gnutls_deinit(*session);
338
528
/* ignore client certificate if any. */
339
gnutls_certificate_server_set_request (es->session,
529
gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
342
gnutls_dh_set_prime_bits (es->session, DH_BITS);
531
gnutls_dh_set_prime_bits(*session, mc.dh_bits);
347
void empty_log(__attribute__((unused)) AvahiLogLevel level,
348
__attribute__((unused)) const char *txt){}
536
/* Avahi log function callback */
537
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
538
__attribute__((unused)) const char *txt){}
350
int start_mandos_communication(const char *ip, uint16_t port,
351
AvahiIfIndex if_index){
353
struct sockaddr_in6 to;
354
encrypted_session es;
540
/* Called when a Mandos server is found */
541
static int start_mandos_communication(const char *ip, uint16_t port,
542
AvahiIfIndex if_index,
544
int ret, tcp_sd = -1;
547
struct sockaddr_in in;
548
struct sockaddr_in6 in6;
355
550
char *buffer = NULL;
356
char *decrypted_buffer;
551
char *decrypted_buffer = NULL;
357
552
size_t buffer_length = 0;
358
553
size_t buffer_capacity = 0;
359
ssize_t decrypted_buffer_size;
362
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);
365
fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
585
fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
369
tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
589
tcp_sd = socket(pf, SOCK_STREAM, 0);
371
592
perror("socket");
375
if(if_indextoname((unsigned int)if_index, interface) == NULL){
377
perror("if_indextoname");
383
fprintf(stderr, "Binding to interface %s\n", interface);
386
memset(&to,0,sizeof(to)); /* Spurious warning */
387
to.sin6_family = AF_INET6;
388
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);
390
612
perror("inet_pton");
394
618
fprintf(stderr, "Bad address: %s\n", ip);
397
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 */
399
to.sin6_scope_id = (uint32_t)if_index;
402
fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
403
/* char addrstr[INET6_ADDRSTRLEN]; */
404
/* if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
405
/* sizeof(addrstr)) == NULL){ */
406
/* perror("inet_ntop"); */
408
/* fprintf(stderr, "Really connecting to: %s, port %d\n", */
409
/* addrstr, ntohs(to.sin6_port)); */
413
ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
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 */
415
694
perror("connect");
419
ret = initgnutls (&es);
425
gnutls_transport_set_ptr (es.session,
426
(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){
429
735
fprintf(stderr, "Establishing TLS session with %s\n", ip);
432
ret = gnutls_handshake (es.session);
434
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){
436
fprintf(stderr, "\n*** Handshake failed ***\n");
760
fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
443
//Retrieve OpenPGP packet that contains the wanted password
767
/* Read OpenPGP packet that contains the wanted password */
446
fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
770
fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
451
if (buffer_length + BUFFER_SIZE > buffer_capacity){
452
buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
457
buffer_capacity += BUFFER_SIZE;
460
ret = gnutls_record_recv
461
(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,
467
802
case GNUTLS_E_INTERRUPTED:
468
803
case GNUTLS_E_AGAIN:
470
805
case GNUTLS_E_REHANDSHAKE:
471
ret = gnutls_handshake (es.session);
473
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");
480
822
fprintf(stderr, "Unknown error while reading data from"
481
" encrypted session with mandos server\n");
483
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
823
" encrypted session with Mandos server\n");
824
gnutls_bye(session, GNUTLS_SHUT_RDWR);
487
buffer_length += (size_t) ret;
491
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;
492
852
decrypted_buffer_size = pgp_packet_decrypt(buffer,
496
if (decrypted_buffer_size >= 0){
855
if(decrypted_buffer_size >= 0){
497
858
while(written < (size_t) decrypted_buffer_size){
498
ret = (int)fwrite (decrypted_buffer + written, 1,
499
(size_t)decrypted_buffer_size - written,
864
ret = (int)fwrite(decrypted_buffer + written, 1,
865
(size_t)decrypted_buffer_size - written,
501
867
if(ret == 0 and ferror(stdout)){
503
870
fprintf(stderr, "Error writing encrypted data: %s\n",
504
871
strerror(errno));
509
876
written += (size_t)ret;
511
free(decrypted_buffer);
882
/* Shutdown procedure */
887
free(decrypted_buffer);
890
ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
898
gnutls_deinit(session);
520
fprintf(stderr, "Closing TLS session\n");
524
gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
527
gnutls_deinit (es.session);
528
gnutls_certificate_free_credentials (es.cred);
529
gnutls_global_deinit ();
533
static AvahiSimplePoll *simple_poll = NULL;
534
static AvahiServer *server = NULL;
536
static void resolve_callback(
537
AvahiSServiceResolver *r,
538
AvahiIfIndex interface,
539
AVAHI_GCC_UNUSED AvahiProtocol protocol,
540
AvahiResolverEvent event,
544
const char *host_name,
545
const AvahiAddress *address,
547
AVAHI_GCC_UNUSED AvahiStringList *txt,
548
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
549
AVAHI_GCC_UNUSED void* userdata) {
551
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){
553
924
/* Called whenever a service has been resolved successfully or
558
933
case AVAHI_RESOLVER_FAILURE:
559
fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
560
" type '%s' in domain '%s': %s\n", name, type, domain,
561
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)));
564
939
case AVAHI_RESOLVER_FOUND:
566
941
char ip[AVAHI_ADDRESS_STR_MAX];
567
942
avahi_address_snprint(ip, sizeof(ip), address);
569
fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
570
" 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);
572
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);
578
955
avahi_s_service_resolver_free(r);
581
static void browse_callback(
582
AvahiSServiceBrowser *b,
583
AvahiIfIndex interface,
584
AvahiProtocol protocol,
585
AvahiBrowserEvent event,
589
AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
592
AvahiServer *s = userdata;
593
assert(b); /* Spurious warning */
595
/* Called whenever a new services becomes available on the LAN or
596
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);
600
case AVAHI_BROWSER_FAILURE:
602
fprintf(stderr, "(Browser) %s\n",
603
avahi_strerror(avahi_server_errno(server)));
604
avahi_simple_poll_quit(simple_poll);
607
case AVAHI_BROWSER_NEW:
608
/* We ignore the returned resolver object. In the callback
609
function we free it. If the server is terminated before
610
the callback function is called the server will free
611
the resolver for us. */
613
if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
615
AVAHI_PROTO_INET6, 0,
616
resolve_callback, s)))
617
fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
618
avahi_strerror(avahi_server_errno(s)));
621
case AVAHI_BROWSER_REMOVE:
624
case AVAHI_BROWSER_ALL_FOR_NOW:
625
case AVAHI_BROWSER_CACHE_EXHAUSTED:
630
/* combinds file name and path and returns the malloced new string. som sane checks could/should be added */
631
const char *combinepath(const char *first, const char *second){
633
tmp = malloc(strlen(first) + strlen(second) + 2);
639
if (first[0] != '\0' and first[strlen(first) - 1] != '/'){
647
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;
648
1654
AvahiServerConfig config;
649
AvahiSServiceBrowser *sb = NULL;
652
int returncode = EXIT_SUCCESS;
653
const char *interface = NULL;
654
AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
655
char *connect_to = NULL;
658
static struct option long_options[] = {
659
{"debug", no_argument, (int *)&debug, 1},
660
{"connect", required_argument, 0, 'C'},
661
{"interface", required_argument, 0, 'i'},
662
{"certdir", required_argument, 0, 'd'},
663
{"certkey", required_argument, 0, 'c'},
664
{"certfile", required_argument, 0, 'k'},
667
int option_index = 0;
668
ret = getopt_long (argc, argv, "i:", long_options,
698
certfile = combinepath(certdir, certfile);
699
if (certfile == NULL){
703
if(interface != NULL){
704
if_index = (AvahiIfIndex) if_nametoindex(interface);
706
fprintf(stderr, "No such interface: \"%s\"\n", interface);
711
if(connect_to != NULL){
712
/* Connect directly, do not use Zeroconf */
713
/* (Mainly meant for debugging) */
714
char *address = strrchr(connect_to, ':');
716
fprintf(stderr, "No colon in address\n");
720
uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
722
perror("Bad port number");
726
address = connect_to;
727
ret = start_mandos_communication(address, port, if_index);
735
certkey = combinepath(certdir, certkey);
736
if (certkey == NULL){
741
avahi_set_log_function(empty_log);
744
/* Initialize the psuedo-RNG */
745
srand((unsigned int) time(NULL));
747
/* Allocate main loop object */
748
if (!(simple_poll = avahi_simple_poll_new())) {
749
fprintf(stderr, "Failed to create simple poll object.\n");
754
/* Do not publish any local records */
1655
/* Do not publish any local Zeroconf records */
755
1656
avahi_server_config_init(&config);
756
1657
config.publish_hinfo = 0;
757
1658
config.publish_addresses = 0;
758
1659
config.publish_workstation = 0;
759
1660
config.publish_domain = 0;
761
1662
/* Allocate a new server */
762
server = avahi_server_new(avahi_simple_poll_get(simple_poll),
763
&config, NULL, NULL, &error);
765
/* 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 */
766
1668
avahi_server_config_free(&config);
768
/* Check if creating the server object succeeded */
770
fprintf(stderr, "Failed to create server: %s\n",
771
avahi_strerror(error));
772
returncode = EXIT_FAILURE;
776
/* Create the service browser */
777
sb = avahi_s_service_browser_new(server, if_index,
779
"_mandos._tcp", NULL, 0,
780
browse_callback, server);
782
fprintf(stderr, "Failed to create service browser: %s\n",
783
avahi_strerror(avahi_server_errno(server)));
784
returncode = EXIT_FAILURE;
788
/* Run the main loop */
791
fprintf(stderr, "Starting avahi loop search\n");
794
avahi_simple_poll_loop(simple_poll);
799
fprintf(stderr, "%s exiting\n", argv[0]);
804
avahi_s_service_browser_free(sb);
807
avahi_server_free(server);
810
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());