/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to plugins.d/mandos-client.c

  • Committer: Teddy Hogeborn
  • Date: 2010-09-12 03:00:40 UTC
  • Revision ID: teddy@fukt.bsnet.se-20100912030040-b0uopyennste9fdh
Documentation changes:

* DBUS-API: New file documenting the server D-Bus interface.

* clients.conf: Add examples of new approval settings.

* debian/mandos.docs: Added "DBUS-API".

* mandos-clients.conf.xml (OPTIONS): Added "approved_by_default",
                                     "approval_delay", and
                                     "approval_duration".
* mandos.xml (D-BUS INTERFACE): Refer to the "DBUS-API" file.
  (BUGS): Remove mention of lack of a remote query interface.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*  -*- coding: utf-8 -*- */
2
2
/*
3
 
 * Mandos client - get and decrypt data from a Mandos server
 
3
 * Mandos-client - get and decrypt data from a Mandos server
4
4
 *
5
5
 * This program is partly derived from an example program for an Avahi
6
6
 * service browser, downloaded from
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
11
 * Everything else is
12
 
 * Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
 
12
 * Copyright © 2008,2009 Teddy Hogeborn
 
13
 * Copyright © 2008,2009 Björn Påhlsson
13
14
 * 
14
15
 * This program is free software: you can redistribute it and/or
15
16
 * modify it under the terms of the GNU General Public License as
29
30
 */
30
31
 
31
32
/* Needed by GPGME, specifically gpgme_data_seek() */
 
33
#ifndef _LARGEFILE_SOURCE
32
34
#define _LARGEFILE_SOURCE
 
35
#endif
 
36
#ifndef _FILE_OFFSET_BITS
33
37
#define _FILE_OFFSET_BITS 64
34
 
 
35
 
#include <stdio.h>
36
 
#include <assert.h>
37
 
#include <stdlib.h>
38
 
#include <time.h>
39
 
#include <net/if.h>             /* if_nametoindex */
40
 
 
 
38
#endif
 
39
 
 
40
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
 
41
 
 
42
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
 
43
                                   stdout, ferror(), remove() */
 
44
#include <stdint.h>             /* uint16_t, uint32_t */
 
45
#include <stddef.h>             /* NULL, size_t, ssize_t */
 
46
#include <stdlib.h>             /* free(), EXIT_SUCCESS, srand(),
 
47
                                   strtof(), abort() */
 
48
#include <stdbool.h>            /* bool, false, true */
 
49
#include <string.h>             /* memset(), strcmp(), strlen(),
 
50
                                   strerror(), asprintf(), strcpy() */
 
51
#include <sys/ioctl.h>          /* ioctl */
 
52
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
 
53
                                   sockaddr_in6, PF_INET6,
 
54
                                   SOCK_STREAM, uid_t, gid_t, open(),
 
55
                                   opendir(), DIR */
 
56
#include <sys/stat.h>           /* open() */
 
57
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
58
                                   inet_pton(), connect() */
 
59
#include <fcntl.h>              /* open() */
 
60
#include <dirent.h>             /* opendir(), struct dirent, readdir()
 
61
                                 */
 
62
#include <inttypes.h>           /* PRIu16, PRIdMAX, intmax_t,
 
63
                                   strtoimax() */
 
64
#include <assert.h>             /* assert() */
 
65
#include <errno.h>              /* perror(), errno */
 
66
#include <time.h>               /* nanosleep(), time() */
 
67
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
 
68
                                   SIOCSIFFLAGS, if_indextoname(),
 
69
                                   if_nametoindex(), IF_NAMESIZE */
 
70
#include <netinet/in.h>         /* IN6_IS_ADDR_LINKLOCAL,
 
71
                                   INET_ADDRSTRLEN, INET6_ADDRSTRLEN
 
72
                                */
 
73
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
 
74
                                   getuid(), getgid(), seteuid(),
 
75
                                   setgid(), pause() */
 
76
#include <arpa/inet.h>          /* inet_pton(), htons */
 
77
#include <iso646.h>             /* not, or, and */
 
78
#include <argp.h>               /* struct argp_option, error_t, struct
 
79
                                   argp_state, struct argp,
 
80
                                   argp_parse(), ARGP_KEY_ARG,
 
81
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
 
82
#include <signal.h>             /* sigemptyset(), sigaddset(),
 
83
                                   sigaction(), SIGTERM, sig_atomic_t,
 
84
                                   raise() */
 
85
#include <sysexits.h>           /* EX_OSERR, EX_USAGE, EX_UNAVAILABLE,
 
86
                                   EX_NOHOST, EX_IOERR, EX_PROTOCOL */
 
87
 
 
88
#ifdef __linux__
 
89
#include <sys/klog.h>           /* klogctl() */
 
90
#endif  /* __linux__ */
 
91
 
 
92
/* Avahi */
 
93
/* All Avahi types, constants and functions
 
94
 Avahi*, avahi_*,
 
95
 AVAHI_* */
41
96
#include <avahi-core/core.h>
42
97
#include <avahi-core/lookup.h>
43
98
#include <avahi-core/log.h>
45
100
#include <avahi-common/malloc.h>
46
101
#include <avahi-common/error.h>
47
102
 
48
 
//mandos client part
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 */
54
 
 
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 */
61
 
 
62
 
// gpgme
63
 
#include <errno.h>              /* perror() */
64
 
#include <gpgme.h>
65
 
 
66
 
// getopt_long
67
 
#include <getopt.h>
 
103
/* GnuTLS */
 
104
#include <gnutls/gnutls.h>      /* All GnuTLS types, constants and
 
105
                                   functions:
 
106
                                   gnutls_*
 
107
                                   init_gnutls_session(),
 
108
                                   GNUTLS_* */
 
109
#include <gnutls/openpgp.h>
 
110
                          /* gnutls_certificate_set_openpgp_key_file(),
 
111
                                   GNUTLS_OPENPGP_FMT_BASE64 */
 
112
 
 
113
/* GPGME */
 
114
#include <gpgme.h>              /* All GPGME types, constants and
 
115
                                   functions:
 
116
                                   gpgme_*
 
117
                                   GPGME_PROTOCOL_OpenPGP,
 
118
                                   GPG_ERR_NO_* */
68
119
 
69
120
#define BUFFER_SIZE 256
70
121
 
71
 
static int dh_bits = 1024;
72
 
 
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"
76
125
 
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;
78
132
 
79
 
/* Used for  */
 
133
/* Used for passing in values through the Avahi callback functions */
80
134
typedef struct {
81
 
  gnutls_session_t session;
 
135
  AvahiSimplePoll *simple_poll;
 
136
  AvahiServer *server;
82
137
  gnutls_certificate_credentials_t cred;
 
138
  unsigned int dh_bits;
83
139
  gnutls_dh_params_t dh_params;
84
 
} encrypted_session;
85
 
 
86
 
 
87
 
static ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
 
                                   char **new_packet,
89
 
                                   const char *homedir){
90
 
  gpgme_data_t dh_crypto, dh_plain;
 
140
  const char *priority;
91
141
  gpgme_ctx_t ctx;
 
142
} mandos_context;
 
143
 
 
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" };
 
148
 
 
149
sig_atomic_t quit_now = 0;
 
150
int signal_received = 0;
 
151
 
 
152
/*
 
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.
 
156
 */
 
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);
 
161
    if(buffer == NULL){
 
162
      return 0;
 
163
    }
 
164
    buffer_capacity += BUFFER_SIZE;
 
165
  }
 
166
  return buffer_capacity;
 
167
}
 
168
 
 
169
/* 
 
170
 * Initialize GPGME.
 
171
 */
 
172
static bool init_gpgme(const char *seckey,
 
173
                       const char *pubkey, const char *tempdir){
92
174
  gpgme_error_t rc;
93
 
  ssize_t ret;
94
 
  ssize_t new_packet_capacity = 0;
95
 
  ssize_t new_packet_length = 0;
96
175
  gpgme_engine_info_t engine_info;
97
 
 
98
 
  if (debug){
99
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
 
176
  
 
177
  
 
178
  /*
 
179
   * Helper function to insert pub and seckey to the engine keyring.
 
180
   */
 
181
  bool import_key(const char *filename){
 
182
    int ret;
 
183
    int fd;
 
184
    gpgme_data_t pgp_data;
 
185
    
 
186
    fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
 
187
    if(fd == -1){
 
188
      perror("open");
 
189
      return false;
 
190
    }
 
191
    
 
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));
 
196
      return false;
 
197
    }
 
198
    
 
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));
 
203
      return false;
 
204
    }
 
205
    
 
206
    ret = (int)TEMP_FAILURE_RETRY(close(fd));
 
207
    if(ret == -1){
 
208
      perror("close");
 
209
    }
 
210
    gpgme_data_release(pgp_data);
 
211
    return true;
 
212
  }
 
213
  
 
214
  if(debug){
 
215
    fprintf(stderr, "Initializing GPGME\n");
100
216
  }
101
217
  
102
218
  /* Init GPGME */
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));
108
 
    return -1;
 
224
    return false;
109
225
  }
110
226
  
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));
116
 
    return -1;
 
232
    return false;
117
233
  }
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);
122
238
      break;
123
239
    }
124
240
    engine_info = engine_info->next;
125
241
  }
126
242
  if(engine_info == NULL){
127
 
    fprintf(stderr, "Could not set home dir to %s\n", homedir);
128
 
    return -1;
129
 
  }
130
 
  
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);
 
244
    return false;
 
245
  }
 
246
  
 
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));
 
252
    return false;
 
253
  }
 
254
  
 
255
  if(not import_key(pubkey) or not import_key(seckey)){
 
256
    return false;
 
257
  }
 
258
  
 
259
  return true;
 
260
}
 
261
 
 
262
/* 
 
263
 * Decrypt OpenPGP data.
 
264
 * Returns -1 on error
 
265
 */
 
266
static ssize_t pgp_packet_decrypt(const char *cryptotext,
 
267
                                  size_t crypto_size,
 
268
                                  char **plaintext){
 
269
  gpgme_data_t dh_crypto, dh_plain;
 
270
  gpgme_error_t rc;
 
271
  ssize_t ret;
 
272
  size_t plaintext_capacity = 0;
 
273
  ssize_t plaintext_length = 0;
 
274
  
 
275
  if(debug){
 
276
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
277
  }
 
278
  
 
279
  /* Create new GPGME data buffer from memory cryptotext */
 
280
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
 
281
                               0);
 
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));
136
285
    return -1;
138
287
  
139
288
  /* Create new empty GPGME data buffer for the plaintext */
140
289
  rc = gpgme_data_new(&dh_plain);
141
 
  if (rc != GPG_ERR_NO_ERROR){
 
290
  if(rc != GPG_ERR_NO_ERROR){
142
291
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
143
292
            gpgme_strsource(rc), gpgme_strerror(rc));
144
 
    return -1;
145
 
  }
146
 
  
147
 
  /* Create new GPGME "context" */
148
 
  rc = gpgme_new(&ctx);
149
 
  if (rc != GPG_ERR_NO_ERROR){
150
 
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
151
 
            gpgme_strsource(rc), gpgme_strerror(rc));
152
 
    return -1;
153
 
  }
154
 
  
155
 
  /* Decrypt data from the FILE pointer to the plaintext data
156
 
     buffer */
157
 
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
158
 
  if (rc != GPG_ERR_NO_ERROR){
 
293
    gpgme_data_release(dh_crypto);
 
294
    return -1;
 
295
  }
 
296
  
 
297
  /* Decrypt data from the cryptotext data buffer to the plaintext
 
298
     data buffer */
 
299
  rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
 
300
  if(rc != GPG_ERR_NO_ERROR){
159
301
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
160
302
            gpgme_strsource(rc), gpgme_strerror(rc));
161
 
    return -1;
162
 
  }
163
 
 
164
 
  if(debug){
165
 
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
166
 
  }
167
 
 
168
 
  if (debug){
169
 
    gpgme_decrypt_result_t result;
170
 
    result = gpgme_op_decrypt_result(ctx);
171
 
    if (result == NULL){
172
 
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
173
 
    } else {
174
 
      fprintf(stderr, "Unsupported algorithm: %s\n",
175
 
              result->unsupported_algorithm);
176
 
      fprintf(stderr, "Wrong key usage: %d\n",
177
 
              result->wrong_key_usage);
178
 
      if(result->file_name != NULL){
179
 
        fprintf(stderr, "File name: %s\n", result->file_name);
180
 
      }
181
 
      gpgme_recipient_t recipient;
182
 
      recipient = result->recipients;
183
 
      if(recipient){
 
303
    plaintext_length = -1;
 
304
    if(debug){
 
305
      gpgme_decrypt_result_t result;
 
306
      result = gpgme_op_decrypt_result(mc.ctx);
 
307
      if(result == NULL){
 
308
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
309
      } else {
 
310
        fprintf(stderr, "Unsupported algorithm: %s\n",
 
311
                result->unsupported_algorithm);
 
312
        fprintf(stderr, "Wrong key usage: %u\n",
 
313
                result->wrong_key_usage);
 
314
        if(result->file_name != NULL){
 
315
          fprintf(stderr, "File name: %s\n", result->file_name);
 
316
        }
 
317
        gpgme_recipient_t recipient;
 
318
        recipient = result->recipients;
184
319
        while(recipient != NULL){
185
320
          fprintf(stderr, "Public key algorithm: %s\n",
186
321
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
192
327
        }
193
328
      }
194
329
    }
 
330
    goto decrypt_end;
195
331
  }
196
332
  
197
 
  /* Delete the GPGME FILE pointer cryptotext data buffer */
198
 
  gpgme_data_release(dh_crypto);
 
333
  if(debug){
 
334
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
 
335
  }
199
336
  
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;
 
341
    goto decrypt_end;
203
342
  }
204
343
  
205
 
  *new_packet = 0;
 
344
  *plaintext = NULL;
206
345
  while(true){
207
 
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
208
 
      *new_packet = realloc(*new_packet,
209
 
                            (unsigned int)new_packet_capacity
210
 
                            + BUFFER_SIZE);
211
 
      if (*new_packet == NULL){
212
 
        perror("realloc");
213
 
        return -1;
214
 
      }
215
 
      new_packet_capacity += BUFFER_SIZE;
 
346
    plaintext_capacity = incbuffer(plaintext,
 
347
                                      (size_t)plaintext_length,
 
348
                                      plaintext_capacity);
 
349
    if(plaintext_capacity == 0){
 
350
        perror("incbuffer");
 
351
        plaintext_length = -1;
 
352
        goto decrypt_end;
216
353
    }
217
354
    
218
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
355
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
219
356
                          BUFFER_SIZE);
220
357
    /* Print the data, if any */
221
 
    if (ret == 0){
 
358
    if(ret == 0){
 
359
      /* EOF */
222
360
      break;
223
361
    }
224
362
    if(ret < 0){
225
363
      perror("gpgme_data_read");
226
 
      return -1;
227
 
    }
228
 
    new_packet_length += ret;
229
 
  }
230
 
 
231
 
  /* FIXME: check characters before printing to screen so to not print
232
 
     terminal control characters */
233
 
  /*   if(debug){ */
234
 
  /*     fprintf(stderr, "decrypted password is: "); */
235
 
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
236
 
  /*     fprintf(stderr, "\n"); */
237
 
  /*   } */
 
364
      plaintext_length = -1;
 
365
      goto decrypt_end;
 
366
    }
 
367
    plaintext_length += ret;
 
368
  }
 
369
  
 
370
  if(debug){
 
371
    fprintf(stderr, "Decrypted password is: ");
 
372
    for(ssize_t i = 0; i < plaintext_length; i++){
 
373
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
 
374
    }
 
375
    fprintf(stderr, "\n");
 
376
  }
 
377
  
 
378
 decrypt_end:
 
379
  
 
380
  /* Delete the GPGME cryptotext data buffer */
 
381
  gpgme_data_release(dh_crypto);
238
382
  
239
383
  /* Delete the GPGME plaintext data buffer */
240
384
  gpgme_data_release(dh_plain);
241
 
  return new_packet_length;
 
385
  return plaintext_length;
242
386
}
243
387
 
244
 
static const char * safer_gnutls_strerror (int value) {
245
 
  const char *ret = gnutls_strerror (value);
246
 
  if (ret == NULL)
 
388
static const char * safer_gnutls_strerror(int value){
 
389
  const char *ret = gnutls_strerror(value); /* Spurious warning from
 
390
                                               -Wunreachable-code */
 
391
  if(ret == NULL)
247
392
    ret = "(unknown)";
248
393
  return ret;
249
394
}
250
395
 
 
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);
254
400
}
255
401
 
256
 
static int initgnutls(encrypted_session *es){
257
 
  const char *err;
 
402
static int init_gnutls_global(const char *pubkeyfilename,
 
403
                              const char *seckeyfilename){
258
404
  int ret;
259
405
  
260
406
  if(debug){
261
407
    fprintf(stderr, "Initializing GnuTLS\n");
262
408
  }
263
 
 
264
 
  if ((ret = gnutls_global_init ())
265
 
      != GNUTLS_E_SUCCESS) {
266
 
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
 
409
  
 
410
  ret = gnutls_global_init();
 
411
  if(ret != GNUTLS_E_SUCCESS){
 
412
    fprintf(stderr, "GnuTLS global_init: %s\n",
 
413
            safer_gnutls_strerror(ret));
267
414
    return -1;
268
415
  }
269
 
 
270
 
  if (debug){
 
416
  
 
417
  if(debug){
 
418
    /* "Use a log level over 10 to enable all debugging options."
 
419
     * - GnuTLS manual
 
420
     */
271
421
    gnutls_global_set_log_level(11);
272
422
    gnutls_global_set_log_function(debuggnutls);
273
423
  }
274
424
  
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
 
429
                                                    from
 
430
                                                    -Wunreachable-code
 
431
                                                 */
 
432
            safer_gnutls_strerror(ret));
 
433
    gnutls_global_deinit();
280
434
    return -1;
281
435
  }
282
436
  
283
437
  if(debug){
284
 
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
285
 
            " and keyfile %s as GnuTLS credentials\n", pubkeyfile,
286
 
            seckeyfile);
 
438
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
 
439
            " secret key %s as GnuTLS credentials\n", pubkeyfilename,
 
440
            seckeyfilename);
287
441
  }
288
442
  
289
443
  ret = gnutls_certificate_set_openpgp_key_file
290
 
    (es->cred, pubkeyfile, seckeyfile, GNUTLS_OPENPGP_FMT_BASE64);
291
 
  if (ret != GNUTLS_E_SUCCESS) {
292
 
    fprintf
293
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
294
 
       " '%s')\n",
295
 
       ret, pubkeyfile, seckeyfile);
296
 
    fprintf(stdout, "The Error is: %s\n",
297
 
            safer_gnutls_strerror(ret));
298
 
    return -1;
299
 
  }
300
 
  
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));
306
 
    return -1;
307
 
  }
308
 
  
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));
313
 
    return -1;
314
 
  }
315
 
  
316
 
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
317
 
  
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){
 
447
    fprintf(stderr,
 
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));
 
452
    goto globalfail;
 
453
  }
 
454
  
 
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));
 
460
    goto globalfail;
 
461
  }
 
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));
 
466
    goto globalfail;
 
467
  }
 
468
  
 
469
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
 
470
  
 
471
  return 0;
 
472
  
 
473
 globalfail:
 
474
  
 
475
  gnutls_certificate_free_credentials(mc.cred);
 
476
  gnutls_global_deinit();
 
477
  gnutls_dh_params_deinit(mc.dh_params);
 
478
  return -1;
 
479
}
 
480
 
 
481
static int init_gnutls_session(gnutls_session_t *session){
 
482
  int ret;
 
483
  /* GnuTLS session creation */
 
484
  do {
 
485
    ret = gnutls_init(session, GNUTLS_SERVER);
 
486
    if(quit_now){
 
487
      return -1;
 
488
    }
 
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));
323
493
  }
324
494
  
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));
330
 
    return -1;
 
495
  {
 
496
    const char *err;
 
497
    do {
 
498
      ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
499
      if(quit_now){
 
500
        gnutls_deinit(*session);
 
501
        return -1;
 
502
      }
 
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);
 
509
      return -1;
 
510
    }
331
511
  }
332
512
  
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",
 
513
  do {
 
514
    ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
515
                                 mc.cred);
 
516
    if(quit_now){
 
517
      gnutls_deinit(*session);
 
518
      return -1;
 
519
    }
 
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);
338
525
    return -1;
339
526
  }
340
527
  
341
528
  /* ignore client certificate if any. */
342
 
  gnutls_certificate_server_set_request (es->session,
343
 
                                         GNUTLS_CERT_IGNORE);
 
529
  gnutls_certificate_server_set_request(*session, GNUTLS_CERT_IGNORE);
344
530
  
345
 
  gnutls_dh_set_prime_bits (es->session, dh_bits);
 
531
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
346
532
  
347
533
  return 0;
348
534
}
349
535
 
 
536
/* Avahi log function callback */
350
537
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
351
538
                      __attribute__((unused)) const char *txt){}
352
539
 
 
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){
355
 
  int ret, tcp_sd;
356
 
  struct sockaddr_in6 to;
357
 
  encrypted_session es;
 
542
                                      AvahiIfIndex if_index,
 
543
                                      int af){
 
544
  int ret, tcp_sd = -1;
 
545
  ssize_t sret;
 
546
  union {
 
547
    struct sockaddr_in in;
 
548
    struct sockaddr_in6 in6;
 
549
  } to;
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;
363
 
  size_t written = 0;
364
 
  int retval = 0;
365
 
  char interface[IF_NAMESIZE];
 
554
  size_t written;
 
555
  int retval = -1;
 
556
  gnutls_session_t session;
 
557
  int pf;                       /* Protocol family */
 
558
  
 
559
  errno = 0;
 
560
  
 
561
  if(quit_now){
 
562
    errno = EINTR;
 
563
    return -1;
 
564
  }
 
565
  
 
566
  switch(af){
 
567
  case AF_INET6:
 
568
    pf = PF_INET6;
 
569
    break;
 
570
  case AF_INET:
 
571
    pf = PF_INET;
 
572
    break;
 
573
  default:
 
574
    fprintf(stderr, "Bad address family: %d\n", af);
 
575
    errno = EINVAL;
 
576
    return -1;
 
577
  }
 
578
  
 
579
  ret = init_gnutls_session(&session);
 
580
  if(ret != 0){
 
581
    return -1;
 
582
  }
366
583
  
367
584
  if(debug){
368
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
369
 
            ip, port);
 
585
    fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
 
586
            "\n", ip, port);
370
587
  }
371
588
  
372
 
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
373
 
  if(tcp_sd < 0) {
 
589
  tcp_sd = socket(pf, SOCK_STREAM, 0);
 
590
  if(tcp_sd < 0){
 
591
    int e = errno;
374
592
    perror("socket");
375
 
    return -1;
376
 
  }
377
 
  
378
 
  if(if_indextoname((unsigned int)if_index, interface) == NULL){
379
 
    if(debug){
380
 
      perror("if_indextoname");
381
 
    }
382
 
    return -1;
383
 
  }
384
 
  
385
 
  if(debug){
386
 
    fprintf(stderr, "Binding to interface %s\n", interface);
387
 
  }
388
 
  
389
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
390
 
  to.sin6_family = AF_INET6;
391
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
392
 
  if (ret < 0 ){
 
593
    errno = e;
 
594
    goto mandos_end;
 
595
  }
 
596
  
 
597
  if(quit_now){
 
598
    errno = EINTR;
 
599
    goto mandos_end;
 
600
  }
 
601
  
 
602
  memset(&to, 0, sizeof(to));
 
603
  if(af == AF_INET6){
 
604
    to.in6.sin6_family = (sa_family_t)af;
 
605
    ret = inet_pton(af, ip, &to.in6.sin6_addr);
 
606
  } else {                      /* IPv4 */
 
607
    to.in.sin_family = (sa_family_t)af;
 
608
    ret = inet_pton(af, ip, &to.in.sin_addr);
 
609
  }
 
610
  if(ret < 0 ){
 
611
    int e = errno;
393
612
    perror("inet_pton");
394
 
    return -1;
395
 
  }  
 
613
    errno = e;
 
614
    goto mandos_end;
 
615
  }
396
616
  if(ret == 0){
 
617
    int e = errno;
397
618
    fprintf(stderr, "Bad address: %s\n", ip);
398
 
    return -1;
399
 
  }
400
 
  to.sin6_port = htons(port);   /* Spurious warning */
 
619
    errno = e;
 
620
    goto mandos_end;
 
621
  }
 
622
  if(af == AF_INET6){
 
623
    to.in6.sin6_port = htons(port); /* Spurious warnings from
 
624
                                       -Wconversion and
 
625
                                       -Wunreachable-code */
 
626
    
 
627
    if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
 
628
       (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
 
629
                              -Wunreachable-code*/
 
630
      if(if_index == AVAHI_IF_UNSPEC){
 
631
        fprintf(stderr, "An IPv6 link-local address is incomplete"
 
632
                " without a network interface\n");
 
633
        errno = EINVAL;
 
634
        goto mandos_end;
 
635
      }
 
636
      /* Set the network interface number as scope */
 
637
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
638
    }
 
639
  } else {
 
640
    to.in.sin_port = htons(port); /* Spurious warnings from
 
641
                                     -Wconversion and
 
642
                                     -Wunreachable-code */
 
643
  }
401
644
  
402
 
  to.sin6_scope_id = (uint32_t)if_index;
 
645
  if(quit_now){
 
646
    errno = EINTR;
 
647
    goto mandos_end;
 
648
  }
403
649
  
404
650
  if(debug){
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");
 
655
      } else {
 
656
        fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
 
657
                ip, interface, port);
 
658
      }
 
659
    } else {
 
660
      fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
 
661
              port);
 
662
    }
 
663
    char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
 
664
                 INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
 
665
    const char *pcret;
 
666
    if(af == AF_INET6){
 
667
      pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
 
668
                        sizeof(addrstr));
 
669
    } else {
 
670
      pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
 
671
                        sizeof(addrstr));
 
672
    }
 
673
    if(pcret == NULL){
409
674
      perror("inet_ntop");
410
675
    } else {
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);
414
678
      }
415
679
    }
416
680
  }
417
681
  
418
 
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
419
 
  if (ret < 0){
 
682
  if(quit_now){
 
683
    errno = EINTR;
 
684
    goto mandos_end;
 
685
  }
 
686
  
 
687
  if(af == AF_INET6){
 
688
    ret = connect(tcp_sd, &to.in6, sizeof(to));
 
689
  } else {
 
690
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
 
691
  }
 
692
  if(ret < 0){
 
693
    int e = errno;
420
694
    perror("connect");
421
 
    return -1;
422
 
  }
423
 
  
424
 
  ret = initgnutls (&es);
425
 
  if (ret != 0){
426
 
    retval = -1;
427
 
    return -1;
428
 
  }
429
 
  
430
 
  gnutls_transport_set_ptr (es.session,
431
 
                            (gnutls_transport_ptr_t) tcp_sd);
 
695
    errno = e;
 
696
    goto mandos_end;
 
697
  }
 
698
  
 
699
  if(quit_now){
 
700
    errno = EINTR;
 
701
    goto mandos_end;
 
702
  }
 
703
  
 
704
  const char *out = mandos_protocol_version;
 
705
  written = 0;
 
706
  while(true){
 
707
    size_t out_size = strlen(out);
 
708
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
709
                                   out_size - written));
 
710
    if(ret == -1){
 
711
      int e = errno;
 
712
      perror("write");
 
713
      errno = e;
 
714
      goto mandos_end;
 
715
    }
 
716
    written += (size_t)ret;
 
717
    if(written < out_size){
 
718
      continue;
 
719
    } else {
 
720
      if(out == mandos_protocol_version){
 
721
        written = 0;
 
722
        out = "\r\n";
 
723
      } else {
 
724
        break;
 
725
      }
 
726
    }
 
727
  
 
728
    if(quit_now){
 
729
      errno = EINTR;
 
730
      goto mandos_end;
 
731
    }
 
732
  }
432
733
  
433
734
  if(debug){
434
735
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
435
736
  }
436
737
  
437
 
  ret = gnutls_handshake (es.session);
438
 
  
439
 
  if (ret != GNUTLS_E_SUCCESS){
 
738
  if(quit_now){
 
739
    errno = EINTR;
 
740
    goto mandos_end;
 
741
  }
 
742
  
 
743
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
 
744
  
 
745
  if(quit_now){
 
746
    errno = EINTR;
 
747
    goto mandos_end;
 
748
  }
 
749
  
 
750
  do {
 
751
    ret = gnutls_handshake(session);
 
752
    if(quit_now){
 
753
      errno = EINTR;
 
754
      goto mandos_end;
 
755
    }
 
756
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
757
  
 
758
  if(ret != GNUTLS_E_SUCCESS){
440
759
    if(debug){
441
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
442
 
      gnutls_perror (ret);
 
760
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
 
761
      gnutls_perror(ret);
443
762
    }
444
 
    retval = -1;
445
 
    goto exit;
 
763
    errno = EPROTO;
 
764
    goto mandos_end;
446
765
  }
447
766
  
448
 
  //Retrieve OpenPGP packet that contains the wanted password
 
767
  /* Read OpenPGP packet that contains the wanted password */
449
768
  
450
769
  if(debug){
451
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
770
    fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
452
771
            ip);
453
772
  }
454
 
 
 
773
  
455
774
  while(true){
456
 
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
457
 
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
458
 
      if (buffer == NULL){
459
 
        perror("realloc");
460
 
        goto exit;
461
 
      }
462
 
      buffer_capacity += BUFFER_SIZE;
463
 
    }
464
 
    
465
 
    ret = gnutls_record_recv
466
 
      (es.session, buffer+buffer_length, BUFFER_SIZE);
467
 
    if (ret == 0){
 
775
    
 
776
    if(quit_now){
 
777
      errno = EINTR;
 
778
      goto mandos_end;
 
779
    }
 
780
    
 
781
    buffer_capacity = incbuffer(&buffer, buffer_length,
 
782
                                   buffer_capacity);
 
783
    if(buffer_capacity == 0){
 
784
      int e = errno;
 
785
      perror("incbuffer");
 
786
      errno = e;
 
787
      goto mandos_end;
 
788
    }
 
789
    
 
790
    if(quit_now){
 
791
      errno = EINTR;
 
792
      goto mandos_end;
 
793
    }
 
794
    
 
795
    sret = gnutls_record_recv(session, buffer+buffer_length,
 
796
                              BUFFER_SIZE);
 
797
    if(sret == 0){
468
798
      break;
469
799
    }
470
 
    if (ret < 0){
471
 
      switch(ret){
 
800
    if(sret < 0){
 
801
      switch(sret){
472
802
      case GNUTLS_E_INTERRUPTED:
473
803
      case GNUTLS_E_AGAIN:
474
804
        break;
475
805
      case GNUTLS_E_REHANDSHAKE:
476
 
        ret = gnutls_handshake (es.session);
477
 
        if (ret < 0){
478
 
          fprintf(stderr, "\n*** Handshake failed ***\n");
479
 
          gnutls_perror (ret);
480
 
          retval = -1;
481
 
          goto exit;
 
806
        do {
 
807
          ret = gnutls_handshake(session);
 
808
          
 
809
          if(quit_now){
 
810
            errno = EINTR;
 
811
            goto mandos_end;
 
812
          }
 
813
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
814
        if(ret < 0){
 
815
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
816
          gnutls_perror(ret);
 
817
          errno = EPROTO;
 
818
          goto mandos_end;
482
819
        }
483
820
        break;
484
821
      default:
485
822
        fprintf(stderr, "Unknown error while reading data from"
486
 
                " encrypted session with mandos server\n");
487
 
        retval = -1;
488
 
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
489
 
        goto exit;
 
823
                " encrypted session with Mandos server\n");
 
824
        gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
825
        errno = EIO;
 
826
        goto mandos_end;
490
827
      }
491
828
    } else {
492
 
      buffer_length += (size_t) ret;
493
 
    }
494
 
  }
495
 
  
496
 
  if (buffer_length > 0){
 
829
      buffer_length += (size_t) sret;
 
830
    }
 
831
  }
 
832
  
 
833
  if(debug){
 
834
    fprintf(stderr, "Closing TLS session\n");
 
835
  }
 
836
  
 
837
  if(quit_now){
 
838
    errno = EINTR;
 
839
    goto mandos_end;
 
840
  }
 
841
  
 
842
  do {
 
843
    ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
844
    if(quit_now){
 
845
      errno = EINTR;
 
846
      goto mandos_end;
 
847
    }
 
848
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
849
  
 
850
  if(buffer_length > 0){
 
851
    ssize_t decrypted_buffer_size;
497
852
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
498
853
                                               buffer_length,
499
 
                                               &decrypted_buffer,
500
 
                                               keydir);
501
 
    if (decrypted_buffer_size >= 0){
 
854
                                               &decrypted_buffer);
 
855
    if(decrypted_buffer_size >= 0){
 
856
      
 
857
      written = 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,
505
 
                           stdout);
 
859
        if(quit_now){
 
860
          errno = EINTR;
 
861
          goto mandos_end;
 
862
        }
 
863
        
 
864
        ret = (int)fwrite(decrypted_buffer + written, 1,
 
865
                          (size_t)decrypted_buffer_size - written,
 
866
                          stdout);
506
867
        if(ret == 0 and ferror(stdout)){
 
868
          int e = errno;
507
869
          if(debug){
508
870
            fprintf(stderr, "Error writing encrypted data: %s\n",
509
871
                    strerror(errno));
510
872
          }
511
 
          retval = -1;
512
 
          break;
 
873
          errno = e;
 
874
          goto mandos_end;
513
875
        }
514
876
        written += (size_t)ret;
515
877
      }
516
 
      free(decrypted_buffer);
517
 
    } else {
 
878
      retval = 0;
 
879
    }
 
880
  }
 
881
  
 
882
  /* Shutdown procedure */
 
883
  
 
884
 mandos_end:
 
885
  {
 
886
    int e = errno;
 
887
    free(decrypted_buffer);
 
888
    free(buffer);
 
889
    if(tcp_sd >= 0){
 
890
      ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
 
891
    }
 
892
    if(ret == -1){
 
893
      if(e == 0){
 
894
        e = errno;
 
895
      }
 
896
      perror("close");
 
897
    }
 
898
    gnutls_deinit(session);
 
899
    if(quit_now){
 
900
      e = EINTR;
518
901
      retval = -1;
519
902
    }
520
 
  }
521
 
 
522
 
  //shutdown procedure
523
 
 
524
 
  if(debug){
525
 
    fprintf(stderr, "Closing TLS session\n");
526
 
  }
527
 
 
528
 
  free(buffer);
529
 
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
530
 
 exit:
531
 
  close(tcp_sd);
532
 
  gnutls_deinit (es.session);
533
 
  gnutls_certificate_free_credentials (es.cred);
534
 
  gnutls_global_deinit ();
 
903
    errno = e;
 
904
  }
535
905
  return retval;
536
906
}
537
907
 
538
 
static AvahiSimplePoll *simple_poll = NULL;
539
 
static AvahiServer *server = NULL;
540
 
 
541
 
static void resolve_callback(
542
 
    AvahiSServiceResolver *r,
543
 
    AvahiIfIndex interface,
544
 
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
545
 
    AvahiResolverEvent event,
546
 
    const char *name,
547
 
    const char *type,
548
 
    const char *domain,
549
 
    const char *host_name,
550
 
    const AvahiAddress *address,
551
 
    uint16_t port,
552
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
553
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
554
 
    AVAHI_GCC_UNUSED void* userdata) {
555
 
    
556
 
  assert(r);                    /* Spurious warning */
 
908
static void resolve_callback(AvahiSServiceResolver *r,
 
909
                             AvahiIfIndex interface,
 
910
                             AvahiProtocol proto,
 
911
                             AvahiResolverEvent event,
 
912
                             const char *name,
 
913
                             const char *type,
 
914
                             const char *domain,
 
915
                             const char *host_name,
 
916
                             const AvahiAddress *address,
 
917
                             uint16_t port,
 
918
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
 
919
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
920
                             flags,
 
921
                             AVAHI_GCC_UNUSED void* userdata){
 
922
  assert(r);
557
923
  
558
924
  /* Called whenever a service has been resolved successfully or
559
925
     timed out */
560
926
  
561
 
  switch (event) {
 
927
  if(quit_now){
 
928
    return;
 
929
  }
 
930
  
 
931
  switch(event){
562
932
  default:
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)));
567
937
    break;
568
938
    
569
939
  case AVAHI_RESOLVER_FOUND:
571
941
      char ip[AVAHI_ADDRESS_STR_MAX];
572
942
      avahi_address_snprint(ip, sizeof(ip), address);
573
943
      if(debug){
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);
576
947
      }
577
 
      int ret = start_mandos_communication(ip, port, interface);
578
 
      if (ret == 0){
579
 
        exit(EXIT_SUCCESS);
 
948
      int ret = start_mandos_communication(ip, port, interface,
 
949
                                           avahi_proto_to_af(proto));
 
950
      if(ret == 0){
 
951
        avahi_simple_poll_quit(mc.simple_poll);
580
952
      }
581
953
    }
582
954
  }
583
955
  avahi_s_service_resolver_free(r);
584
956
}
585
957
 
586
 
static void browse_callback(
587
 
    AvahiSServiceBrowser *b,
588
 
    AvahiIfIndex interface,
589
 
    AvahiProtocol protocol,
590
 
    AvahiBrowserEvent event,
591
 
    const char *name,
592
 
    const char *type,
593
 
    const char *domain,
594
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
595
 
    void* userdata) {
596
 
    
597
 
    AvahiServer *s = userdata;
598
 
    assert(b);                  /* Spurious warning */
599
 
    
600
 
    /* Called whenever a new services becomes available on the LAN or
601
 
       is removed from the LAN */
602
 
    
603
 
    switch (event) {
 
958
static void browse_callback(AvahiSServiceBrowser *b,
 
959
                            AvahiIfIndex interface,
 
960
                            AvahiProtocol protocol,
 
961
                            AvahiBrowserEvent event,
 
962
                            const char *name,
 
963
                            const char *type,
 
964
                            const char *domain,
 
965
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
966
                            flags,
 
967
                            AVAHI_GCC_UNUSED void* userdata){
 
968
  assert(b);
 
969
  
 
970
  /* Called whenever a new services becomes available on the LAN or
 
971
     is removed from the LAN */
 
972
  
 
973
  if(quit_now){
 
974
    return;
 
975
  }
 
976
  
 
977
  switch(event){
 
978
  default:
 
979
  case AVAHI_BROWSER_FAILURE:
 
980
    
 
981
    fprintf(stderr, "(Avahi browser) %s\n",
 
982
            avahi_strerror(avahi_server_errno(mc.server)));
 
983
    avahi_simple_poll_quit(mc.simple_poll);
 
984
    return;
 
985
    
 
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
 
990
       resolver for us. */
 
991
    
 
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)));
 
997
    break;
 
998
    
 
999
  case AVAHI_BROWSER_REMOVE:
 
1000
    break;
 
1001
    
 
1002
  case AVAHI_BROWSER_ALL_FOR_NOW:
 
1003
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
1004
    if(debug){
 
1005
      fprintf(stderr, "No Mandos server found, still searching...\n");
 
1006
    }
 
1007
    break;
 
1008
  }
 
1009
}
 
1010
 
 
1011
/* stop main loop after sigterm has been called */
 
1012
static void handle_sigterm(int sig){
 
1013
  if(quit_now){
 
1014
    return;
 
1015
  }
 
1016
  quit_now = 1;
 
1017
  signal_received = sig;
 
1018
  int old_errno = errno;
 
1019
  if(mc.simple_poll != NULL){
 
1020
    avahi_simple_poll_quit(mc.simple_poll);
 
1021
  }
 
1022
  errno = old_errno;
 
1023
}
 
1024
 
 
1025
/* 
 
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.)
 
1029
 */
 
1030
int good_interface(const struct dirent *if_entry){
 
1031
  ssize_t ssret;
 
1032
  char *flagname = NULL;
 
1033
  int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
 
1034
                     if_entry->d_name);
 
1035
  if(ret < 0){
 
1036
    perror("asprintf");
 
1037
    return 0;
 
1038
  }
 
1039
  if(if_entry->d_name[0] == '.'){
 
1040
    return 0;
 
1041
  }
 
1042
  int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
 
1043
  if(flags_fd == -1){
 
1044
    perror("open");
 
1045
    return 0;
 
1046
  }
 
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){
 
1053
    perror("malloc");
 
1054
    close(flags_fd);
 
1055
    return 0;
 
1056
  }
 
1057
  while(to_read > 0){
 
1058
    ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
 
1059
                                             (size_t)to_read));
 
1060
    if(ssret == -1){
 
1061
      perror("read");
 
1062
      free(flagstring);
 
1063
      close(flags_fd);
 
1064
      return 0;
 
1065
    }
 
1066
    to_read -= ssret;
 
1067
    if(ssret == 0){
 
1068
      break;
 
1069
    }
 
1070
  }
 
1071
  close(flags_fd);
 
1072
  intmax_t tmpmax;
 
1073
  char *tmp;
 
1074
  errno = 0;
 
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){
 
1079
    if(debug){
 
1080
      fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
 
1081
              flagstring, if_entry->d_name);
 
1082
    }
 
1083
    free(flagstring);
 
1084
    return 0;
 
1085
  }
 
1086
  free(flagstring);
 
1087
  ifreq_flags flags = (ifreq_flags)tmpmax;
 
1088
  /* Reject the loopback device */
 
1089
  if(flags & IFF_LOOPBACK){
 
1090
    if(debug){
 
1091
      fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
 
1092
              if_entry->d_name);
 
1093
    }
 
1094
    return 0;
 
1095
  }
 
1096
  /* Accept point-to-point devices only if connect_to is specified */
 
1097
  if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
 
1098
    if(debug){
 
1099
      fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
 
1100
              if_entry->d_name);
 
1101
    }
 
1102
    return 1;
 
1103
  }
 
1104
  /* Otherwise, reject non-broadcast-capable devices */
 
1105
  if(not (flags & IFF_BROADCAST)){
 
1106
    if(debug){
 
1107
      fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
 
1108
              if_entry->d_name);
 
1109
    }
 
1110
    return 0;
 
1111
  }
 
1112
  /* Accept this device */
 
1113
  if(debug){
 
1114
    fprintf(stderr, "Interface \"%s\" is acceptable\n",
 
1115
            if_entry->d_name);
 
1116
  }
 
1117
  return 1;
 
1118
}
 
1119
 
 
1120
int main(int argc, char *argv[]){
 
1121
  AvahiSServiceBrowser *sb = NULL;
 
1122
  int error;
 
1123
  int ret;
 
1124
  intmax_t tmpmax;
 
1125
  char *tmp;
 
1126
  int exitcode = EXIT_SUCCESS;
 
1127
  const char *interface = "";
 
1128
  struct ifreq network;
 
1129
  int sd = -1;
 
1130
  bool take_down_interface = false;
 
1131
  uid_t uid;
 
1132
  gid_t gid;
 
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;
 
1138
  
 
1139
  bool gnutls_initialized = false;
 
1140
  bool gpgme_initialized = false;
 
1141
  float delay = 2.5f;
 
1142
  
 
1143
  struct sigaction old_sigterm_action = { .sa_handler = SIG_DFL };
 
1144
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
 
1145
  
 
1146
  uid = getuid();
 
1147
  gid = getgid();
 
1148
  
 
1149
  /* Lower any group privileges we might have, just to be safe */
 
1150
  errno = 0;
 
1151
  ret = setgid(gid);
 
1152
  if(ret == -1){
 
1153
    perror("setgid");
 
1154
  }
 
1155
  
 
1156
  /* Lower user privileges (temporarily) */
 
1157
  errno = 0;
 
1158
  ret = seteuid(uid);
 
1159
  if(ret == -1){
 
1160
    perror("seteuid");
 
1161
  }
 
1162
  
 
1163
  if(quit_now){
 
1164
    goto end;
 
1165
  }
 
1166
  
 
1167
  {
 
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",
 
1174
        .group = 1 },
 
1175
      { .name = "interface", .key = 'i',
 
1176
        .arg = "NAME",
 
1177
        .doc = "Network interface that will be used to search for"
 
1178
        " Mandos servers",
 
1179
        .group = 1 },
 
1180
      { .name = "seckey", .key = 's',
 
1181
        .arg = "FILE",
 
1182
        .doc = "OpenPGP secret key file base name",
 
1183
        .group = 1 },
 
1184
      { .name = "pubkey", .key = 'p',
 
1185
        .arg = "FILE",
 
1186
        .doc = "OpenPGP public key file base name",
 
1187
        .group = 2 },
 
1188
      { .name = "dh-bits", .key = 129,
 
1189
        .arg = "BITS",
 
1190
        .doc = "Bit length of the prime number used in the"
 
1191
        " Diffie-Hellman key exchange",
 
1192
        .group = 2 },
 
1193
      { .name = "priority", .key = 130,
 
1194
        .arg = "STRING",
 
1195
        .doc = "GnuTLS priority string for the TLS handshake",
 
1196
        .group = 1 },
 
1197
      { .name = "delay", .key = 131,
 
1198
        .arg = "SECONDS",
 
1199
        .doc = "Maximum delay to wait for interface startup",
 
1200
        .group = 2 },
 
1201
      /*
 
1202
       * These reproduce what we would get without ARGP_NO_HELP
 
1203
       */
 
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 },
 
1210
      { .name = NULL }
 
1211
    };
 
1212
    
 
1213
    error_t parse_opt(int key, char *arg,
 
1214
                      struct argp_state *state){
 
1215
      errno = 0;
 
1216
      switch(key){
 
1217
      case 128:                 /* --debug */
 
1218
        debug = true;
 
1219
        break;
 
1220
      case 'c':                 /* --connect */
 
1221
        connect_to = arg;
 
1222
        break;
 
1223
      case 'i':                 /* --interface */
 
1224
        interface = arg;
 
1225
        break;
 
1226
      case 's':                 /* --seckey */
 
1227
        seckey = arg;
 
1228
        break;
 
1229
      case 'p':                 /* --pubkey */
 
1230
        pubkey = arg;
 
1231
        break;
 
1232
      case 129:                 /* --dh-bits */
 
1233
        errno = 0;
 
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");
 
1238
        }
 
1239
        mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
 
1240
        break;
 
1241
      case 130:                 /* --priority */
 
1242
        mc.priority = arg;
 
1243
        break;
 
1244
      case 131:                 /* --delay */
 
1245
        errno = 0;
 
1246
        delay = strtof(arg, &tmp);
 
1247
        if(errno != 0 or tmp == arg or *tmp != '\0'){
 
1248
          argp_error(state, "Bad delay");
 
1249
        }
 
1250
        break;
 
1251
        /*
 
1252
         * These reproduce what we would get without ARGP_NO_HELP
 
1253
         */
 
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);
 
1264
        break;
 
1265
      default:
 
1266
        return ARGP_ERR_UNKNOWN;
 
1267
      }
 
1268
      return errno;
 
1269
    }
 
1270
    
 
1271
    struct argp argp = { .options = options, .parser = parse_opt,
 
1272
                         .args_doc = "",
 
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);
 
1277
    switch(ret){
 
1278
    case 0:
 
1279
      break;
 
1280
    case ENOMEM:
604
1281
    default:
605
 
    case AVAHI_BROWSER_FAILURE:
606
 
      
607
 
      fprintf(stderr, "(Browser) %s\n",
608
 
              avahi_strerror(avahi_server_errno(server)));
609
 
      avahi_simple_poll_quit(simple_poll);
610
 
      return;
611
 
      
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. */
617
 
      
618
 
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
619
 
                                         type, domain,
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)));
624
 
      break;
625
 
      
626
 
    case AVAHI_BROWSER_REMOVE:
627
 
      break;
628
 
      
629
 
    case AVAHI_BROWSER_ALL_FOR_NOW:
630
 
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
631
 
      break;
632
 
    }
633
 
}
634
 
 
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);
641
 
  if (tmp == NULL){
642
 
    return NULL;
643
 
  }
644
 
  if(f_len > 0){
645
 
    memcpy(tmp, first, f_len);
646
 
  }
647
 
  tmp[f_len] = '/';
648
 
  if(s_len > 0){
649
 
    memcpy(tmp + f_len + 1, second, s_len);
650
 
  }
651
 
  tmp[f_len + 1 + s_len] = '\0';
652
 
  return tmp;
653
 
}
654
 
 
655
 
 
656
 
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
 
1282
      errno = ret;
 
1283
      perror("argp_parse");
 
1284
      exitcode = EX_OSERR;
 
1285
      goto end;
 
1286
    case EINVAL:
 
1287
      exitcode = EX_USAGE;
 
1288
      goto end;
 
1289
    }
 
1290
  }
 
1291
  
 
1292
  if(not debug){
 
1293
    avahi_set_log_function(empty_log);
 
1294
  }
 
1295
 
 
1296
  if(interface[0] == '\0'){
 
1297
    struct dirent **direntries;
 
1298
    ret = scandir(sys_class_net, &direntries, good_interface,
 
1299
                  alphasort);
 
1300
    if(ret >= 1){
 
1301
      /* Pick the first good interface */
 
1302
      interface = strdup(direntries[0]->d_name);
 
1303
      if(debug){
 
1304
        fprintf(stderr, "Using interface \"%s\"\n", interface);
 
1305
      }
 
1306
      if(interface == NULL){
 
1307
        perror("malloc");
 
1308
        free(direntries);
 
1309
        exitcode = EXIT_FAILURE;
 
1310
        goto end;
 
1311
      }
 
1312
      free(direntries);
 
1313
    } else {
 
1314
      free(direntries);
 
1315
      fprintf(stderr, "Could not find a network interface\n");
 
1316
      exitcode = EXIT_FAILURE;
 
1317
      goto end;
 
1318
    }
 
1319
  }
 
1320
  
 
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;
 
1329
    goto end;
 
1330
  }
 
1331
  
 
1332
  sigemptyset(&sigterm_action.sa_mask);
 
1333
  ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
 
1334
  if(ret == -1){
 
1335
    perror("sigaddset");
 
1336
    exitcode = EX_OSERR;
 
1337
    goto end;
 
1338
  }
 
1339
  ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
 
1340
  if(ret == -1){
 
1341
    perror("sigaddset");
 
1342
    exitcode = EX_OSERR;
 
1343
    goto end;
 
1344
  }
 
1345
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
 
1346
  if(ret == -1){
 
1347
    perror("sigaddset");
 
1348
    exitcode = EX_OSERR;
 
1349
    goto end;
 
1350
  }
 
1351
  /* Need to check if the handler is SIG_IGN before handling:
 
1352
     | [[info:libc:Initial Signal Actions]] |
 
1353
     | [[info:libc:Basic Signal Handling]]  |
 
1354
  */
 
1355
  ret = sigaction(SIGINT, NULL, &old_sigterm_action);
 
1356
  if(ret == -1){
 
1357
    perror("sigaction");
 
1358
    return EX_OSERR;
 
1359
  }
 
1360
  if(old_sigterm_action.sa_handler != SIG_IGN){
 
1361
    ret = sigaction(SIGINT, &sigterm_action, NULL);
 
1362
    if(ret == -1){
 
1363
      perror("sigaction");
 
1364
      exitcode = EX_OSERR;
 
1365
      goto end;
 
1366
    }
 
1367
  }
 
1368
  ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
 
1369
  if(ret == -1){
 
1370
    perror("sigaction");
 
1371
    return EX_OSERR;
 
1372
  }
 
1373
  if(old_sigterm_action.sa_handler != SIG_IGN){
 
1374
    ret = sigaction(SIGHUP, &sigterm_action, NULL);
 
1375
    if(ret == -1){
 
1376
      perror("sigaction");
 
1377
      exitcode = EX_OSERR;
 
1378
      goto end;
 
1379
    }
 
1380
  }
 
1381
  ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
 
1382
  if(ret == -1){
 
1383
    perror("sigaction");
 
1384
    return EX_OSERR;
 
1385
  }
 
1386
  if(old_sigterm_action.sa_handler != SIG_IGN){
 
1387
    ret = sigaction(SIGTERM, &sigterm_action, NULL);
 
1388
    if(ret == -1){
 
1389
      perror("sigaction");
 
1390
      exitcode = EX_OSERR;
 
1391
      goto end;
 
1392
    }
 
1393
  }
 
1394
  
 
1395
  /* If the interface is down, bring it up */
 
1396
  if(strcmp(interface, "none") != 0){
 
1397
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
1398
    if(if_index == 0){
 
1399
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
 
1400
      exitcode = EX_UNAVAILABLE;
 
1401
      goto end;
 
1402
    }
 
1403
    
 
1404
    if(quit_now){
 
1405
      goto end;
 
1406
    }
 
1407
    
 
1408
    /* Re-raise priviliges */
 
1409
    errno = 0;
 
1410
    ret = seteuid(0);
 
1411
    if(ret == -1){
 
1412
      perror("seteuid");
 
1413
    }
 
1414
    
 
1415
#ifdef __linux__
 
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;
 
1420
    if(ret == -1){
 
1421
      restore_loglevel = false;
 
1422
      perror("klogctl");
 
1423
    }
 
1424
#endif  /* __linux__ */
 
1425
    
 
1426
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1427
    if(sd < 0){
 
1428
      perror("socket");
 
1429
      exitcode = EX_OSERR;
 
1430
#ifdef __linux__
 
1431
      if(restore_loglevel){
 
1432
        ret = klogctl(7, NULL, 0);
 
1433
        if(ret == -1){
 
1434
          perror("klogctl");
 
1435
        }
 
1436
      }
 
1437
#endif  /* __linux__ */
 
1438
      /* Lower privileges */
 
1439
      errno = 0;
 
1440
      ret = seteuid(uid);
 
1441
      if(ret == -1){
 
1442
        perror("seteuid");
 
1443
      }
 
1444
      goto end;
 
1445
    }
 
1446
    strcpy(network.ifr_name, interface);
 
1447
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1448
    if(ret == -1){
 
1449
      perror("ioctl SIOCGIFFLAGS");
 
1450
#ifdef __linux__
 
1451
      if(restore_loglevel){
 
1452
        ret = klogctl(7, NULL, 0);
 
1453
        if(ret == -1){
 
1454
          perror("klogctl");
 
1455
        }
 
1456
      }
 
1457
#endif  /* __linux__ */
 
1458
      exitcode = EX_OSERR;
 
1459
      /* Lower privileges */
 
1460
      errno = 0;
 
1461
      ret = seteuid(uid);
 
1462
      if(ret == -1){
 
1463
        perror("seteuid");
 
1464
      }
 
1465
      goto end;
 
1466
    }
 
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);
 
1471
      if(ret == -1){
 
1472
        take_down_interface = false;
 
1473
        perror("ioctl SIOCSIFFLAGS +IFF_UP");
 
1474
        exitcode = EX_OSERR;
 
1475
#ifdef __linux__
 
1476
        if(restore_loglevel){
 
1477
          ret = klogctl(7, NULL, 0);
 
1478
          if(ret == -1){
 
1479
            perror("klogctl");
 
1480
          }
 
1481
        }
 
1482
#endif  /* __linux__ */
 
1483
        /* Lower privileges */
 
1484
        errno = 0;
 
1485
        ret = seteuid(uid);
 
1486
        if(ret == -1){
 
1487
          perror("seteuid");
 
1488
        }
 
1489
        goto end;
 
1490
      }
 
1491
    }
 
1492
    /* sleep checking until interface is running */
 
1493
    for(int i=0; i < delay * 4; i++){
 
1494
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1495
      if(ret == -1){
 
1496
        perror("ioctl SIOCGIFFLAGS");
 
1497
      } else if(network.ifr_flags & IFF_RUNNING){
 
1498
        break;
 
1499
      }
 
1500
      struct timespec sleeptime = { .tv_nsec = 250000000 };
 
1501
      ret = nanosleep(&sleeptime, NULL);
 
1502
      if(ret == -1 and errno != EINTR){
 
1503
        perror("nanosleep");
 
1504
      }
 
1505
    }
 
1506
    if(not take_down_interface){
 
1507
      /* We won't need the socket anymore */
 
1508
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1509
      if(ret == -1){
 
1510
        perror("close");
 
1511
      }
 
1512
    }
 
1513
#ifdef __linux__
 
1514
    if(restore_loglevel){
 
1515
      /* Restores kernel loglevel to default */
 
1516
      ret = klogctl(7, NULL, 0);
 
1517
      if(ret == -1){
 
1518
        perror("klogctl");
 
1519
      }
 
1520
    }
 
1521
#endif  /* __linux__ */
 
1522
    /* Lower privileges */
 
1523
    errno = 0;
 
1524
    if(take_down_interface){
 
1525
      /* Lower privileges */
 
1526
      ret = seteuid(uid);
 
1527
      if(ret == -1){
 
1528
        perror("seteuid");
 
1529
      }
 
1530
    } else {
 
1531
      /* Lower privileges permanently */
 
1532
      ret = setuid(uid);
 
1533
      if(ret == -1){
 
1534
        perror("setuid");
 
1535
      }
 
1536
    }
 
1537
  }
 
1538
  
 
1539
  if(quit_now){
 
1540
    goto end;
 
1541
  }
 
1542
  
 
1543
  ret = init_gnutls_global(pubkey, seckey);
 
1544
  if(ret == -1){
 
1545
    fprintf(stderr, "init_gnutls_global failed\n");
 
1546
    exitcode = EX_UNAVAILABLE;
 
1547
    goto end;
 
1548
  } else {
 
1549
    gnutls_initialized = true;
 
1550
  }
 
1551
  
 
1552
  if(quit_now){
 
1553
    goto end;
 
1554
  }
 
1555
  
 
1556
  tempdir_created = true;
 
1557
  if(mkdtemp(tempdir) == NULL){
 
1558
    tempdir_created = false;
 
1559
    perror("mkdtemp");
 
1560
    goto end;
 
1561
  }
 
1562
  
 
1563
  if(quit_now){
 
1564
    goto end;
 
1565
  }
 
1566
  
 
1567
  if(not init_gpgme(pubkey, seckey, tempdir)){
 
1568
    fprintf(stderr, "init_gpgme failed\n");
 
1569
    exitcode = EX_UNAVAILABLE;
 
1570
    goto end;
 
1571
  } else {
 
1572
    gpgme_initialized = true;
 
1573
  }
 
1574
  
 
1575
  if(quit_now){
 
1576
    goto end;
 
1577
  }
 
1578
  
 
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;
 
1586
      goto end;
 
1587
    }
 
1588
    
 
1589
    if(quit_now){
 
1590
      goto end;
 
1591
    }
 
1592
    
 
1593
    uint16_t port;
 
1594
    errno = 0;
 
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;
 
1600
      goto end;
 
1601
    }
 
1602
  
 
1603
    if(quit_now){
 
1604
      goto end;
 
1605
    }
 
1606
    
 
1607
    port = (uint16_t)tmpmax;
 
1608
    *address = '\0';
 
1609
    address = connect_to;
 
1610
    /* Colon in address indicates IPv6 */
 
1611
    int af;
 
1612
    if(strchr(address, ':') != NULL){
 
1613
      af = AF_INET6;
 
1614
    } else {
 
1615
      af = AF_INET;
 
1616
    }
 
1617
    
 
1618
    if(quit_now){
 
1619
      goto end;
 
1620
    }
 
1621
    
 
1622
    ret = start_mandos_communication(address, port, if_index, af);
 
1623
    if(ret < 0){
 
1624
      switch(errno){
 
1625
      case ENETUNREACH:
 
1626
      case EHOSTDOWN:
 
1627
      case EHOSTUNREACH:
 
1628
        exitcode = EX_NOHOST;
 
1629
        break;
 
1630
      case EINVAL:
 
1631
        exitcode = EX_USAGE;
 
1632
        break;
 
1633
      case EIO:
 
1634
        exitcode = EX_IOERR;
 
1635
        break;
 
1636
      case EPROTO:
 
1637
        exitcode = EX_PROTOCOL;
 
1638
        break;
 
1639
      default:
 
1640
        exitcode = EX_OSERR;
 
1641
        break;
 
1642
      }
 
1643
    } else {
 
1644
      exitcode = EXIT_SUCCESS;
 
1645
    }
 
1646
    goto end;
 
1647
  }
 
1648
  
 
1649
  if(quit_now){
 
1650
    goto end;
 
1651
  }
 
1652
  
 
1653
  {
657
1654
    AvahiServerConfig config;
658
 
    AvahiSServiceBrowser *sb = NULL;
659
 
    int error;
660
 
    int ret;
661
 
    int debug_int = 0;
662
 
    int returncode = EXIT_SUCCESS;
663
 
    const char *interface = NULL;
664
 
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
665
 
    char *connect_to = NULL;
666
 
    
667
 
    debug_int = debug ? 1 : 0;
668
 
    while (true){
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'},
677
 
        {0, 0, 0, 0} };
678
 
      
679
 
      int option_index = 0;
680
 
      ret = getopt_long (argc, argv, "i:", long_options,
681
 
                         &option_index);
682
 
      
683
 
      if (ret == -1){
684
 
        break;
685
 
      }
686
 
      
687
 
      switch(ret){
688
 
      case 0:
689
 
        break;
690
 
      case 'i':
691
 
        interface = optarg;
692
 
        break;
693
 
      case 'C':
694
 
        connect_to = optarg;
695
 
        break;
696
 
      case 'd':
697
 
        keydir = optarg;
698
 
        break;
699
 
      case 'c':
700
 
        pubkeyfile = optarg;
701
 
        break;
702
 
      case 'k':
703
 
        seckeyfile = optarg;
704
 
        break;
705
 
      case 'D':
706
 
        dh_bits = atoi(optarg);
707
 
        break;
708
 
      case '?':
709
 
        break
710
 
      default:
711
 
        exit(EXIT_FAILURE);
712
 
      }
713
 
    }
714
 
    debug = debug_int ? true : false;
715
 
    
716
 
    pubkeyfile = combinepath(keydir, pubkeyfile);
717
 
    if (pubkeyfile == NULL){
718
 
      perror("combinepath");
719
 
      goto exit;
720
 
    }
721
 
    
722
 
    if(interface != NULL){
723
 
      if_index = (AvahiIfIndex) if_nametoindex(interface);
724
 
      if(if_index == 0){
725
 
        fprintf(stderr, "No such interface: \"%s\"\n", interface);
726
 
        exit(EXIT_FAILURE);
727
 
      }
728
 
    }
729
 
    
730
 
    if(connect_to != NULL){
731
 
      /* Connect directly, do not use Zeroconf */
732
 
      /* (Mainly meant for debugging) */
733
 
      char *address = strrchr(connect_to, ':');
734
 
      if(address == NULL){
735
 
        fprintf(stderr, "No colon in address\n");
736
 
        exit(EXIT_FAILURE);
737
 
      }
738
 
      errno = 0;
739
 
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
740
 
      if(errno){
741
 
        perror("Bad port number");
742
 
        exit(EXIT_FAILURE);
743
 
      }
744
 
      *address = '\0';
745
 
      address = connect_to;
746
 
      ret = start_mandos_communication(address, port, if_index);
747
 
      if(ret < 0){
748
 
        exit(EXIT_FAILURE);
749
 
      } else {
750
 
        exit(EXIT_SUCCESS);
751
 
      }
752
 
    }
753
 
    
754
 
    seckeyfile = combinepath(keydir, seckeyfile);
755
 
    if (seckeyfile == NULL){
756
 
      perror("combinepath");
757
 
      goto exit;
758
 
    }
759
 
    
760
 
    if (not debug){
761
 
      avahi_set_log_function(empty_log);
762
 
    }
763
 
    
764
 
    /* Initialize the psuedo-RNG */
765
 
    srand((unsigned int) time(NULL));
766
 
 
767
 
    /* Allocate main loop object */
768
 
    if (!(simple_poll = avahi_simple_poll_new())) {
769
 
        fprintf(stderr, "Failed to create simple poll object.\n");
770
 
        
771
 
        goto exit;
772
 
    }
773
 
 
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;
780
 
 
 
1661
    
781
1662
    /* Allocate a new server */
782
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
783
 
                              &config, NULL, NULL, &error);
784
 
 
785
 
    /* Free the configuration data */
 
1663
    mc.server = avahi_server_new(avahi_simple_poll_get
 
1664
                                 (mc.simple_poll), &config, NULL,
 
1665
                                 NULL, &error);
 
1666
    
 
1667
    /* Free the Avahi configuration data */
786
1668
    avahi_server_config_free(&config);
787
 
 
788
 
    /* Check if creating the server object succeeded */
789
 
    if (!server) {
790
 
        fprintf(stderr, "Failed to create server: %s\n",
791
 
                avahi_strerror(error));
792
 
        returncode = EXIT_FAILURE;
793
 
        goto exit;
794
 
    }
795
 
    
796
 
    /* Create the service browser */
797
 
    sb = avahi_s_service_browser_new(server, if_index,
798
 
                                     AVAHI_PROTO_INET6,
799
 
                                     "_mandos._tcp", NULL, 0,
800
 
                                     browse_callback, server);
801
 
    if (!sb) {
802
 
        fprintf(stderr, "Failed to create service browser: %s\n",
803
 
                avahi_strerror(avahi_server_errno(server)));
804
 
        returncode = EXIT_FAILURE;
805
 
        goto exit;
806
 
    }
807
 
    
808
 
    /* Run the main loop */
809
 
 
810
 
    if (debug){
811
 
      fprintf(stderr, "Starting avahi loop search\n");
812
 
    }
813
 
    
814
 
    avahi_simple_poll_loop(simple_poll);
815
 
    
816
 
 exit:
817
 
 
818
 
    if (debug){
819
 
      fprintf(stderr, "%s exiting\n", argv[0]);
820
 
    }
821
 
    
822
 
    /* Cleanup things */
823
 
    if (sb)
824
 
        avahi_s_service_browser_free(sb);
825
 
    
826
 
    if (server)
827
 
        avahi_server_free(server);
828
 
 
829
 
    if (simple_poll)
830
 
        avahi_simple_poll_free(simple_poll);
831
 
    free(pubkeyfile);
832
 
    free(seckeyfile);
833
 
    
834
 
    return returncode;
 
1669
  }
 
1670
  
 
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;
 
1676
    goto end;
 
1677
  }
 
1678
  
 
1679
  if(quit_now){
 
1680
    goto end;
 
1681
  }
 
1682
  
 
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);
 
1687
  if(sb == NULL){
 
1688
    fprintf(stderr, "Failed to create service browser: %s\n",
 
1689
            avahi_strerror(avahi_server_errno(mc.server)));
 
1690
    exitcode = EX_UNAVAILABLE;
 
1691
    goto end;
 
1692
  }
 
1693
  
 
1694
  if(quit_now){
 
1695
    goto end;
 
1696
  }
 
1697
  
 
1698
  /* Run the main loop */
 
1699
  
 
1700
  if(debug){
 
1701
    fprintf(stderr, "Starting Avahi loop search\n");
 
1702
  }
 
1703
  
 
1704
  avahi_simple_poll_loop(mc.simple_poll);
 
1705
  
 
1706
 end:
 
1707
  
 
1708
  if(debug){
 
1709
    fprintf(stderr, "%s exiting\n", argv[0]);
 
1710
  }
 
1711
  
 
1712
  /* Cleanup things */
 
1713
  if(sb != NULL)
 
1714
    avahi_s_service_browser_free(sb);
 
1715
  
 
1716
  if(mc.server != NULL)
 
1717
    avahi_server_free(mc.server);
 
1718
  
 
1719
  if(mc.simple_poll != NULL)
 
1720
    avahi_simple_poll_free(mc.simple_poll);
 
1721
  
 
1722
  if(gnutls_initialized){
 
1723
    gnutls_certificate_free_credentials(mc.cred);
 
1724
    gnutls_global_deinit();
 
1725
    gnutls_dh_params_deinit(mc.dh_params);
 
1726
  }
 
1727
  
 
1728
  if(gpgme_initialized){
 
1729
    gpgme_release(mc.ctx);
 
1730
  }
 
1731
  
 
1732
  /* Take down the network interface */
 
1733
  if(take_down_interface){
 
1734
    /* Re-raise priviliges */
 
1735
    errno = 0;
 
1736
    ret = seteuid(0);
 
1737
    if(ret == -1){
 
1738
      perror("seteuid");
 
1739
    }
 
1740
    if(geteuid() == 0){
 
1741
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1742
      if(ret == -1){
 
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);
 
1747
        if(ret == -1){
 
1748
          perror("ioctl SIOCSIFFLAGS -IFF_UP");
 
1749
        }
 
1750
      }
 
1751
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1752
      if(ret == -1){
 
1753
        perror("close");
 
1754
      }
 
1755
      /* Lower privileges permanently */
 
1756
      errno = 0;
 
1757
      ret = setuid(uid);
 
1758
      if(ret == -1){
 
1759
        perror("setuid");
 
1760
      }
 
1761
    }
 
1762
  }
 
1763
  
 
1764
  /* Removes the temp directory used by GPGME */
 
1765
  if(tempdir_created){
 
1766
    DIR *d;
 
1767
    struct dirent *direntry;
 
1768
    d = opendir(tempdir);
 
1769
    if(d == NULL){
 
1770
      if(errno != ENOENT){
 
1771
        perror("opendir");
 
1772
      }
 
1773
    } else {
 
1774
      while(true){
 
1775
        direntry = readdir(d);
 
1776
        if(direntry == NULL){
 
1777
          break;
 
1778
        }
 
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'))){
 
1784
          continue;
 
1785
        }
 
1786
        char *fullname = NULL;
 
1787
        ret = asprintf(&fullname, "%s/%s", tempdir,
 
1788
                       direntry->d_name);
 
1789
        if(ret < 0){
 
1790
          perror("asprintf");
 
1791
          continue;
 
1792
        }
 
1793
        ret = remove(fullname);
 
1794
        if(ret == -1){
 
1795
          fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
 
1796
                  strerror(errno));
 
1797
        }
 
1798
        free(fullname);
 
1799
      }
 
1800
      closedir(d);
 
1801
    }
 
1802
    ret = rmdir(tempdir);
 
1803
    if(ret == -1 and errno != ENOENT){
 
1804
      perror("rmdir");
 
1805
    }
 
1806
  }
 
1807
  
 
1808
  if(quit_now){
 
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,
 
1813
                                            NULL));
 
1814
    if(ret == -1){
 
1815
      perror("sigaction");
 
1816
    }
 
1817
    do {
 
1818
      ret = raise(signal_received);
 
1819
    } while(ret != 0 and errno == EINTR);
 
1820
    if(ret != 0){
 
1821
      perror("raise");
 
1822
      abort();
 
1823
    }
 
1824
    TEMP_FAILURE_RETRY(pause());
 
1825
  }
 
1826
  
 
1827
  return exitcode;
835
1828
}