/mandos/release

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

« back to all changes in this revision

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

  • Committer: Björn Påhlsson
  • Date: 2009-02-09 05:09:39 UTC
  • mto: (237.7.1 mandos) (24.1.154 mandos)
  • mto: This revision was merged to the branch mainline in revision 250.
  • Revision ID: belorn@braxen-20090209050939-ml95liuwtbn9kjtb
plugin-runner: Added support for empty string arguments
               Fixed bug where IP:port argument failed
mandos-client: Fixed bug where files wasnt removed after sigterm signal

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
25
26
 * along with this program.  If not, see
26
27
 * <http://www.gnu.org/licenses/>.
27
28
 * 
28
 
 * Contact the authors at <https://www.fukt.bsnet.se/~belorn/> and
29
 
 * <https://www.fukt.bsnet.se/~teddy/>.
 
29
 * Contact the authors at <mandos@fukt.bsnet.se>.
30
30
 */
31
31
 
32
32
/* Needed by GPGME, specifically gpgme_data_seek() */
33
33
#define _LARGEFILE_SOURCE
34
34
#define _FILE_OFFSET_BITS 64
35
35
 
36
 
#include <stdio.h>
37
 
#include <assert.h>
38
 
#include <stdlib.h>
39
 
#include <time.h>
40
 
#include <net/if.h>             /* if_nametoindex */
41
 
 
 
36
#define _GNU_SOURCE             /* TEMP_FAILURE_RETRY(), asprintf() */
 
37
 
 
38
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
 
39
                                   stdout, ferror(), sscanf(),
 
40
                                   remove() */
 
41
#include <stdint.h>             /* uint16_t, uint32_t */
 
42
#include <stddef.h>             /* NULL, size_t, ssize_t */
 
43
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
 
44
                                   srand() */
 
45
#include <stdbool.h>            /* bool, false, true */
 
46
#include <string.h>             /* memset(), strcmp(), strlen(),
 
47
                                   strerror(), asprintf(), strcpy() */
 
48
#include <sys/ioctl.h>          /* ioctl */
 
49
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
 
50
                                   sockaddr_in6, PF_INET6,
 
51
                                   SOCK_STREAM, uid_t, gid_t, open(),
 
52
                                   opendir(), DIR */
 
53
#include <sys/stat.h>           /* open() */
 
54
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
 
55
                                   inet_pton(), connect() */
 
56
#include <fcntl.h>              /* open() */
 
57
#include <dirent.h>             /* opendir(), struct dirent, readdir()
 
58
                                 */
 
59
#include <inttypes.h>           /* PRIu16, intmax_t, SCNdMAX */
 
60
#include <assert.h>             /* assert() */
 
61
#include <errno.h>              /* perror(), errno */
 
62
#include <time.h>               /* nanosleep(), time() */
 
63
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
 
64
                                   SIOCSIFFLAGS, if_indextoname(),
 
65
                                   if_nametoindex(), IF_NAMESIZE */
 
66
#include <netinet/in.h>         /* IN6_IS_ADDR_LINKLOCAL,
 
67
                                   INET_ADDRSTRLEN, INET6_ADDRSTRLEN
 
68
                                */
 
69
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
 
70
                                   getuid(), getgid(), setuid(),
 
71
                                   setgid() */
 
72
#include <arpa/inet.h>          /* inet_pton(), htons */
 
73
#include <iso646.h>             /* not, or, and */
 
74
#include <argp.h>               /* struct argp_option, error_t, struct
 
75
                                   argp_state, struct argp,
 
76
                                   argp_parse(), ARGP_KEY_ARG,
 
77
                                   ARGP_KEY_END, ARGP_ERR_UNKNOWN */
 
78
#include <signal.h>             /* sigemptyset(), sigaddset(), sigaction(), SIGTERM, sigaction */
 
79
#ifdef __linux__
 
80
#include <sys/klog.h>           /* klogctl() */
 
81
#endif
 
82
 
 
83
/* Avahi */
 
84
/* All Avahi types, constants and functions
 
85
 Avahi*, avahi_*,
 
86
 AVAHI_* */
42
87
#include <avahi-core/core.h>
43
88
#include <avahi-core/lookup.h>
44
89
#include <avahi-core/log.h>
46
91
#include <avahi-common/malloc.h>
47
92
#include <avahi-common/error.h>
48
93
 
49
 
//mandos client part
50
 
#include <sys/types.h>          /* socket(), inet_pton() */
51
 
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
52
 
                                   struct in6_addr, inet_pton() */
53
 
#include <gnutls/gnutls.h>      /* All GnuTLS stuff */
54
 
#include <gnutls/openpgp.h>     /* GnuTLS with openpgp stuff */
55
 
 
56
 
#include <unistd.h>             /* close() */
57
 
#include <netinet/in.h>
58
 
#include <stdbool.h>            /* true */
59
 
#include <string.h>             /* memset */
60
 
#include <arpa/inet.h>          /* inet_pton() */
61
 
#include <iso646.h>             /* not */
62
 
 
63
 
// gpgme
64
 
#include <errno.h>              /* perror() */
65
 
#include <gpgme.h>
66
 
 
67
 
// getopt long
68
 
#include <getopt.h>
69
 
 
70
 
#ifndef CERT_ROOT
71
 
#define CERT_ROOT "/conf/conf.d/cryptkeyreq/"
72
 
#endif
73
 
#define CERTFILE CERT_ROOT "openpgp-client.txt"
74
 
#define KEYFILE CERT_ROOT "openpgp-client-key.txt"
 
94
/* GnuTLS */
 
95
#include <gnutls/gnutls.h>      /* All GnuTLS types, constants and
 
96
                                   functions:
 
97
                                   gnutls_*
 
98
                                   init_gnutls_session(),
 
99
                                   GNUTLS_* */
 
100
#include <gnutls/openpgp.h>
 
101
                          /* gnutls_certificate_set_openpgp_key_file(),
 
102
                                   GNUTLS_OPENPGP_FMT_BASE64 */
 
103
 
 
104
/* GPGME */
 
105
#include <gpgme.h>              /* All GPGME types, constants and
 
106
                                   functions:
 
107
                                   gpgme_*
 
108
                                   GPGME_PROTOCOL_OpenPGP,
 
109
                                   GPG_ERR_NO_* */
 
110
 
75
111
#define BUFFER_SIZE 256
76
 
#define DH_BITS 1024
 
112
 
 
113
#define PATHDIR "/conf/conf.d/mandos"
 
114
#define SECKEY "seckey.txt"
 
115
#define PUBKEY "pubkey.txt"
77
116
 
78
117
bool debug = false;
 
118
static const char mandos_protocol_version[] = "1";
 
119
const char *argp_program_version = "mandos-client " VERSION;
 
120
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
79
121
 
 
122
/* Used for passing in values through the Avahi callback functions */
80
123
typedef struct {
81
 
  gnutls_session_t session;
 
124
  AvahiSimplePoll *simple_poll;
 
125
  AvahiServer *server;
82
126
  gnutls_certificate_credentials_t cred;
 
127
  unsigned int dh_bits;
83
128
  gnutls_dh_params_t dh_params;
84
 
} encrypted_session;
85
 
 
86
 
 
87
 
ssize_t pgp_packet_decrypt (char *packet, size_t packet_size,
88
 
                            char **new_packet, const char *homedir){
89
 
  gpgme_data_t dh_crypto, dh_plain;
 
129
  const char *priority;
90
130
  gpgme_ctx_t ctx;
 
131
} mandos_context;
 
132
 
 
133
/* global context so signal handler can reach it*/
 
134
mandos_context mc;
 
135
 
 
136
/*
 
137
 * Make additional room in "buffer" for at least BUFFER_SIZE
 
138
 * additional bytes. "buffer_capacity" is how much is currently
 
139
 * allocated, "buffer_length" is how much is already used.
 
140
 */
 
141
size_t incbuffer(char **buffer, size_t buffer_length,
 
142
                  size_t buffer_capacity){
 
143
  if(buffer_length + BUFFER_SIZE > buffer_capacity){
 
144
    *buffer = realloc(*buffer, buffer_capacity + BUFFER_SIZE);
 
145
    if(buffer == NULL){
 
146
      return 0;
 
147
    }
 
148
    buffer_capacity += BUFFER_SIZE;
 
149
  }
 
150
  return buffer_capacity;
 
151
}
 
152
 
 
153
/* 
 
154
 * Initialize GPGME.
 
155
 */
 
156
static bool init_gpgme(const char *seckey,
 
157
                       const char *pubkey, const char *tempdir){
 
158
  int ret;
91
159
  gpgme_error_t rc;
92
 
  ssize_t ret;
93
 
  ssize_t new_packet_capacity = 0;
94
 
  ssize_t new_packet_length = 0;
95
160
  gpgme_engine_info_t engine_info;
96
 
 
97
 
  if (debug){
98
 
    fprintf(stderr, "Trying to decrypt OpenPGP packet\n");
 
161
  
 
162
  
 
163
  /*
 
164
   * Helper function to insert pub and seckey to the engine keyring.
 
165
   */
 
166
  bool import_key(const char *filename){
 
167
    int fd;
 
168
    gpgme_data_t pgp_data;
 
169
    
 
170
    fd = (int)TEMP_FAILURE_RETRY(open(filename, O_RDONLY));
 
171
    if(fd == -1){
 
172
      perror("open");
 
173
      return false;
 
174
    }
 
175
    
 
176
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
 
177
    if(rc != GPG_ERR_NO_ERROR){
 
178
      fprintf(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
 
179
              gpgme_strsource(rc), gpgme_strerror(rc));
 
180
      return false;
 
181
    }
 
182
    
 
183
    rc = gpgme_op_import(mc.ctx, pgp_data);
 
184
    if(rc != GPG_ERR_NO_ERROR){
 
185
      fprintf(stderr, "bad gpgme_op_import: %s: %s\n",
 
186
              gpgme_strsource(rc), gpgme_strerror(rc));
 
187
      return false;
 
188
    }
 
189
    
 
190
    ret = (int)TEMP_FAILURE_RETRY(close(fd));
 
191
    if(ret == -1){
 
192
      perror("close");
 
193
    }
 
194
    gpgme_data_release(pgp_data);
 
195
    return true;
 
196
  }
 
197
  
 
198
  if(debug){
 
199
    fprintf(stderr, "Initialize gpgme\n");
99
200
  }
100
201
  
101
202
  /* Init GPGME */
102
203
  gpgme_check_version(NULL);
103
 
  gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
204
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
 
205
  if(rc != GPG_ERR_NO_ERROR){
 
206
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
 
207
            gpgme_strsource(rc), gpgme_strerror(rc));
 
208
    return false;
 
209
  }
104
210
  
105
 
  /* Set GPGME home directory */
106
 
  rc = gpgme_get_engine_info (&engine_info);
107
 
  if (rc != GPG_ERR_NO_ERROR){
 
211
    /* Set GPGME home directory for the OpenPGP engine only */
 
212
  rc = gpgme_get_engine_info(&engine_info);
 
213
  if(rc != GPG_ERR_NO_ERROR){
108
214
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
109
215
            gpgme_strsource(rc), gpgme_strerror(rc));
110
 
    return -1;
 
216
    return false;
111
217
  }
112
218
  while(engine_info != NULL){
113
219
    if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
114
220
      gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
115
 
                            engine_info->file_name, homedir);
 
221
                            engine_info->file_name, tempdir);
116
222
      break;
117
223
    }
118
224
    engine_info = engine_info->next;
119
225
  }
120
226
  if(engine_info == NULL){
121
 
    fprintf(stderr, "Could not set home dir to %s\n", homedir);
122
 
    return -1;
123
 
  }
124
 
  
125
 
  /* Create new GPGME data buffer from packet buffer */
126
 
  rc = gpgme_data_new_from_mem(&dh_crypto, packet, packet_size, 0);
127
 
  if (rc != GPG_ERR_NO_ERROR){
 
227
    fprintf(stderr, "Could not set GPGME home dir to %s\n", tempdir);
 
228
    return false;
 
229
  }
 
230
  
 
231
  /* Create new GPGME "context" */
 
232
  rc = gpgme_new(&(mc.ctx));
 
233
  if(rc != GPG_ERR_NO_ERROR){
 
234
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
 
235
            gpgme_strsource(rc), gpgme_strerror(rc));
 
236
    return false;
 
237
  }
 
238
  
 
239
  if(not import_key(pubkey) or not import_key(seckey)){
 
240
    return false;
 
241
  }
 
242
  
 
243
  return true; 
 
244
}
 
245
 
 
246
/* 
 
247
 * Decrypt OpenPGP data.
 
248
 * Returns -1 on error
 
249
 */
 
250
static ssize_t pgp_packet_decrypt(const char *cryptotext,
 
251
                                  size_t crypto_size,
 
252
                                  char **plaintext){
 
253
  gpgme_data_t dh_crypto, dh_plain;
 
254
  gpgme_error_t rc;
 
255
  ssize_t ret;
 
256
  size_t plaintext_capacity = 0;
 
257
  ssize_t plaintext_length = 0;
 
258
  
 
259
  if(debug){
 
260
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
 
261
  }
 
262
  
 
263
  /* Create new GPGME data buffer from memory cryptotext */
 
264
  rc = gpgme_data_new_from_mem(&dh_crypto, cryptotext, crypto_size,
 
265
                               0);
 
266
  if(rc != GPG_ERR_NO_ERROR){
128
267
    fprintf(stderr, "bad gpgme_data_new_from_mem: %s: %s\n",
129
268
            gpgme_strsource(rc), gpgme_strerror(rc));
130
269
    return -1;
132
271
  
133
272
  /* Create new empty GPGME data buffer for the plaintext */
134
273
  rc = gpgme_data_new(&dh_plain);
135
 
  if (rc != GPG_ERR_NO_ERROR){
 
274
  if(rc != GPG_ERR_NO_ERROR){
136
275
    fprintf(stderr, "bad gpgme_data_new: %s: %s\n",
137
276
            gpgme_strsource(rc), gpgme_strerror(rc));
138
 
    return -1;
139
 
  }
140
 
  
141
 
  /* Create new GPGME "context" */
142
 
  rc = gpgme_new(&ctx);
143
 
  if (rc != GPG_ERR_NO_ERROR){
144
 
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
145
 
            gpgme_strsource(rc), gpgme_strerror(rc));
146
 
    return -1;
147
 
  }
148
 
  
149
 
  /* Decrypt data from the FILE pointer to the plaintext data
150
 
     buffer */
151
 
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
152
 
  if (rc != GPG_ERR_NO_ERROR){
 
277
    gpgme_data_release(dh_crypto);
 
278
    return -1;
 
279
  }
 
280
  
 
281
  /* Decrypt data from the cryptotext data buffer to the plaintext
 
282
     data buffer */
 
283
  rc = gpgme_op_decrypt(mc.ctx, dh_crypto, dh_plain);
 
284
  if(rc != GPG_ERR_NO_ERROR){
153
285
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
154
286
            gpgme_strsource(rc), gpgme_strerror(rc));
155
 
    return -1;
 
287
    plaintext_length = -1;
 
288
    if(debug){
 
289
      gpgme_decrypt_result_t result;
 
290
      result = gpgme_op_decrypt_result(mc.ctx);
 
291
      if(result == NULL){
 
292
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
 
293
      } else {
 
294
        fprintf(stderr, "Unsupported algorithm: %s\n",
 
295
                result->unsupported_algorithm);
 
296
        fprintf(stderr, "Wrong key usage: %u\n",
 
297
                result->wrong_key_usage);
 
298
        if(result->file_name != NULL){
 
299
          fprintf(stderr, "File name: %s\n", result->file_name);
 
300
        }
 
301
        gpgme_recipient_t recipient;
 
302
        recipient = result->recipients;
 
303
        if(recipient){
 
304
          while(recipient != NULL){
 
305
            fprintf(stderr, "Public key algorithm: %s\n",
 
306
                    gpgme_pubkey_algo_name(recipient->pubkey_algo));
 
307
            fprintf(stderr, "Key ID: %s\n", recipient->keyid);
 
308
            fprintf(stderr, "Secret key available: %s\n",
 
309
                    recipient->status == GPG_ERR_NO_SECKEY
 
310
                    ? "No" : "Yes");
 
311
            recipient = recipient->next;
 
312
          }
 
313
        }
 
314
      }
 
315
    }
 
316
    goto decrypt_end;
156
317
  }
157
 
 
 
318
  
158
319
  if(debug){
159
 
    fprintf(stderr, "Decryption of OpenPGP packet succeeded\n");
160
 
  }
161
 
 
162
 
  if (debug){
163
 
    gpgme_decrypt_result_t result;
164
 
    result = gpgme_op_decrypt_result(ctx);
165
 
    if (result == NULL){
166
 
      fprintf(stderr, "gpgme_op_decrypt_result failed\n");
167
 
    } else {
168
 
      fprintf(stderr, "Unsupported algorithm: %s\n",
169
 
              result->unsupported_algorithm);
170
 
      fprintf(stderr, "Wrong key usage: %d\n",
171
 
              result->wrong_key_usage);
172
 
      if(result->file_name != NULL){
173
 
        fprintf(stderr, "File name: %s\n", result->file_name);
174
 
      }
175
 
      gpgme_recipient_t recipient;
176
 
      recipient = result->recipients;
177
 
      if(recipient){
178
 
        while(recipient != NULL){
179
 
          fprintf(stderr, "Public key algorithm: %s\n",
180
 
                  gpgme_pubkey_algo_name(recipient->pubkey_algo));
181
 
          fprintf(stderr, "Key ID: %s\n", recipient->keyid);
182
 
          fprintf(stderr, "Secret key available: %s\n",
183
 
                  recipient->status == GPG_ERR_NO_SECKEY
184
 
                  ? "No" : "Yes");
185
 
          recipient = recipient->next;
186
 
        }
187
 
      }
188
 
    }
189
 
  }
190
 
  
191
 
  /* Delete the GPGME FILE pointer cryptotext data buffer */
192
 
  gpgme_data_release(dh_crypto);
 
320
    fprintf(stderr, "Decryption of OpenPGP data succeeded\n");
 
321
  }
193
322
  
194
323
  /* Seek back to the beginning of the GPGME plaintext data buffer */
195
 
  gpgme_data_seek(dh_plain, (off_t) 0, SEEK_SET);
196
 
 
197
 
  *new_packet = 0;
 
324
  if(gpgme_data_seek(dh_plain, (off_t)0, SEEK_SET) == -1){
 
325
    perror("gpgme_data_seek");
 
326
    plaintext_length = -1;
 
327
    goto decrypt_end;
 
328
  }
 
329
  
 
330
  *plaintext = NULL;
198
331
  while(true){
199
 
    if (new_packet_length + BUFFER_SIZE > new_packet_capacity){
200
 
      *new_packet = realloc(*new_packet,
201
 
                            (unsigned int)new_packet_capacity
202
 
                            + BUFFER_SIZE);
203
 
      if (*new_packet == NULL){
204
 
        perror("realloc");
205
 
        return -1;
206
 
      }
207
 
      new_packet_capacity += BUFFER_SIZE;
 
332
    plaintext_capacity = incbuffer(plaintext,
 
333
                                      (size_t)plaintext_length,
 
334
                                      plaintext_capacity);
 
335
    if(plaintext_capacity == 0){
 
336
        perror("incbuffer");
 
337
        plaintext_length = -1;
 
338
        goto decrypt_end;
208
339
    }
209
340
    
210
 
    ret = gpgme_data_read(dh_plain, *new_packet + new_packet_length,
 
341
    ret = gpgme_data_read(dh_plain, *plaintext + plaintext_length,
211
342
                          BUFFER_SIZE);
212
343
    /* Print the data, if any */
213
 
    if (ret == 0){
 
344
    if(ret == 0){
 
345
      /* EOF */
214
346
      break;
215
347
    }
216
348
    if(ret < 0){
217
349
      perror("gpgme_data_read");
218
 
      return -1;
219
 
    }
220
 
    new_packet_length += ret;
221
 
  }
222
 
 
223
 
  /* FIXME: check characters before printing to screen so to not print
224
 
     terminal control characters */
225
 
  /*   if(debug){ */
226
 
  /*     fprintf(stderr, "decrypted password is: "); */
227
 
  /*     fwrite(*new_packet, 1, new_packet_length, stderr); */
228
 
  /*     fprintf(stderr, "\n"); */
229
 
  /*   } */
 
350
      plaintext_length = -1;
 
351
      goto decrypt_end;
 
352
    }
 
353
    plaintext_length += ret;
 
354
  }
 
355
  
 
356
  if(debug){
 
357
    fprintf(stderr, "Decrypted password is: ");
 
358
    for(ssize_t i = 0; i < plaintext_length; i++){
 
359
      fprintf(stderr, "%02hhX ", (*plaintext)[i]);
 
360
    }
 
361
    fprintf(stderr, "\n");
 
362
  }
 
363
  
 
364
 decrypt_end:
 
365
  
 
366
  /* Delete the GPGME cryptotext data buffer */
 
367
  gpgme_data_release(dh_crypto);
230
368
  
231
369
  /* Delete the GPGME plaintext data buffer */
232
370
  gpgme_data_release(dh_plain);
233
 
  return new_packet_length;
 
371
  return plaintext_length;
234
372
}
235
373
 
236
 
static const char * safer_gnutls_strerror (int value) {
237
 
  const char *ret = gnutls_strerror (value);
238
 
  if (ret == NULL)
 
374
static const char * safer_gnutls_strerror(int value){
 
375
  const char *ret = gnutls_strerror(value); /* Spurious warning from
 
376
                                               -Wunreachable-code */
 
377
  if(ret == NULL)
239
378
    ret = "(unknown)";
240
379
  return ret;
241
380
}
242
381
 
243
 
void debuggnutls(__attribute__((unused)) int level,
244
 
                 const char* string){
245
 
  fprintf(stderr, "%s", string);
 
382
/* GnuTLS log function callback */
 
383
static void debuggnutls(__attribute__((unused)) int level,
 
384
                        const char* string){
 
385
  fprintf(stderr, "GnuTLS: %s", string);
246
386
}
247
387
 
248
 
int initgnutls(encrypted_session *es){
249
 
  const char *err;
 
388
static int init_gnutls_global(const char *pubkeyfilename,
 
389
                              const char *seckeyfilename){
250
390
  int ret;
251
391
  
252
392
  if(debug){
253
393
    fprintf(stderr, "Initializing GnuTLS\n");
254
394
  }
255
395
  
256
 
  if ((ret = gnutls_global_init ())
257
 
      != GNUTLS_E_SUCCESS) {
258
 
    fprintf (stderr, "global_init: %s\n", safer_gnutls_strerror(ret));
 
396
  ret = gnutls_global_init();
 
397
  if(ret != GNUTLS_E_SUCCESS){
 
398
    fprintf(stderr, "GnuTLS global_init: %s\n",
 
399
            safer_gnutls_strerror(ret));
259
400
    return -1;
260
401
  }
261
 
 
262
 
  if (debug){
 
402
  
 
403
  if(debug){
 
404
    /* "Use a log level over 10 to enable all debugging options."
 
405
     * - GnuTLS manual
 
406
     */
263
407
    gnutls_global_set_log_level(11);
264
408
    gnutls_global_set_log_function(debuggnutls);
265
409
  }
266
410
  
267
 
  /* openpgp credentials */
268
 
  if ((ret = gnutls_certificate_allocate_credentials (&es->cred))
269
 
      != GNUTLS_E_SUCCESS) {
270
 
    fprintf (stderr, "memory error: %s\n",
271
 
             safer_gnutls_strerror(ret));
 
411
  /* OpenPGP credentials */
 
412
  gnutls_certificate_allocate_credentials(&mc.cred);
 
413
  if(ret != GNUTLS_E_SUCCESS){
 
414
    fprintf(stderr, "GnuTLS memory error: %s\n", /* Spurious warning
 
415
                                                    from
 
416
                                                    -Wunreachable-code
 
417
                                                 */
 
418
            safer_gnutls_strerror(ret));
 
419
    gnutls_global_deinit();
272
420
    return -1;
273
421
  }
274
422
  
275
423
  if(debug){
276
 
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
277
 
            " and keyfile %s as GnuTLS credentials\n", CERTFILE,
278
 
            KEYFILE);
 
424
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
 
425
            " secret key %s as GnuTLS credentials\n", pubkeyfilename,
 
426
            seckeyfilename);
279
427
  }
280
428
  
281
429
  ret = gnutls_certificate_set_openpgp_key_file
282
 
    (es->cred, CERTFILE, KEYFILE, GNUTLS_OPENPGP_FMT_BASE64);
283
 
  if (ret != GNUTLS_E_SUCCESS) {
284
 
    fprintf
285
 
      (stderr, "Error[%d] while reading the OpenPGP key pair ('%s',"
286
 
       " '%s')\n",
287
 
       ret, CERTFILE, KEYFILE);
288
 
    fprintf(stdout, "The Error is: %s\n",
289
 
            safer_gnutls_strerror(ret));
290
 
    return -1;
291
 
  }
292
 
  
293
 
  //GnuTLS server initialization
294
 
  if ((ret = gnutls_dh_params_init (&es->dh_params))
295
 
      != GNUTLS_E_SUCCESS) {
296
 
    fprintf (stderr, "Error in dh parameter initialization: %s\n",
297
 
             safer_gnutls_strerror(ret));
298
 
    return -1;
299
 
  }
300
 
  
301
 
  if ((ret = gnutls_dh_params_generate2 (es->dh_params, DH_BITS))
302
 
      != GNUTLS_E_SUCCESS) {
303
 
    fprintf (stderr, "Error in prime generation: %s\n",
304
 
             safer_gnutls_strerror(ret));
305
 
    return -1;
306
 
  }
307
 
  
308
 
  gnutls_certificate_set_dh_params (es->cred, es->dh_params);
309
 
  
310
 
  // GnuTLS session creation
311
 
  if ((ret = gnutls_init (&es->session, GNUTLS_SERVER))
312
 
      != GNUTLS_E_SUCCESS){
 
430
    (mc.cred, pubkeyfilename, seckeyfilename,
 
431
     GNUTLS_OPENPGP_FMT_BASE64);
 
432
  if(ret != GNUTLS_E_SUCCESS){
 
433
    fprintf(stderr,
 
434
            "Error[%d] while reading the OpenPGP key pair ('%s',"
 
435
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
 
436
    fprintf(stderr, "The GnuTLS error is: %s\n",
 
437
            safer_gnutls_strerror(ret));
 
438
    goto globalfail;
 
439
  }
 
440
  
 
441
  /* GnuTLS server initialization */
 
442
  ret = gnutls_dh_params_init(&mc.dh_params);
 
443
  if(ret != GNUTLS_E_SUCCESS){
 
444
    fprintf(stderr, "Error in GnuTLS DH parameter initialization:"
 
445
            " %s\n", safer_gnutls_strerror(ret));
 
446
    goto globalfail;
 
447
  }
 
448
  ret = gnutls_dh_params_generate2(mc.dh_params, mc.dh_bits);
 
449
  if(ret != GNUTLS_E_SUCCESS){
 
450
    fprintf(stderr, "Error in GnuTLS prime generation: %s\n",
 
451
            safer_gnutls_strerror(ret));
 
452
    goto globalfail;
 
453
  }
 
454
  
 
455
  gnutls_certificate_set_dh_params(mc.cred, mc.dh_params);
 
456
  
 
457
  return 0;
 
458
  
 
459
 globalfail:
 
460
  
 
461
  gnutls_certificate_free_credentials(mc.cred);
 
462
  gnutls_global_deinit();
 
463
  gnutls_dh_params_deinit(mc.dh_params);
 
464
  return -1;
 
465
}
 
466
 
 
467
static int init_gnutls_session(gnutls_session_t *session){
 
468
  int ret;
 
469
  /* GnuTLS session creation */
 
470
  ret = gnutls_init(session, GNUTLS_SERVER);
 
471
  if(ret != GNUTLS_E_SUCCESS){
313
472
    fprintf(stderr, "Error in GnuTLS session initialization: %s\n",
314
473
            safer_gnutls_strerror(ret));
315
474
  }
316
475
  
317
 
  if ((ret = gnutls_priority_set_direct (es->session, "NORMAL", &err))
318
 
      != GNUTLS_E_SUCCESS) {
319
 
    fprintf(stderr, "Syntax error at: %s\n", err);
320
 
    fprintf(stderr, "GnuTLS error: %s\n",
321
 
            safer_gnutls_strerror(ret));
322
 
    return -1;
 
476
  {
 
477
    const char *err;
 
478
    ret = gnutls_priority_set_direct(*session, mc.priority, &err);
 
479
    if(ret != GNUTLS_E_SUCCESS){
 
480
      fprintf(stderr, "Syntax error at: %s\n", err);
 
481
      fprintf(stderr, "GnuTLS error: %s\n",
 
482
              safer_gnutls_strerror(ret));
 
483
      gnutls_deinit(*session);
 
484
      return -1;
 
485
    }
323
486
  }
324
487
  
325
 
  if ((ret = gnutls_credentials_set
326
 
       (es->session, GNUTLS_CRD_CERTIFICATE, es->cred))
327
 
      != GNUTLS_E_SUCCESS) {
328
 
    fprintf(stderr, "Error setting a credentials set: %s\n",
 
488
  ret = gnutls_credentials_set(*session, GNUTLS_CRD_CERTIFICATE,
 
489
                               mc.cred);
 
490
  if(ret != GNUTLS_E_SUCCESS){
 
491
    fprintf(stderr, "Error setting GnuTLS credentials: %s\n",
329
492
            safer_gnutls_strerror(ret));
 
493
    gnutls_deinit(*session);
330
494
    return -1;
331
495
  }
332
496
  
333
497
  /* ignore client certificate if any. */
334
 
  gnutls_certificate_server_set_request (es->session,
335
 
                                         GNUTLS_CERT_IGNORE);
 
498
  gnutls_certificate_server_set_request(*session,
 
499
                                        GNUTLS_CERT_IGNORE);
336
500
  
337
 
  gnutls_dh_set_prime_bits (es->session, DH_BITS);
 
501
  gnutls_dh_set_prime_bits(*session, mc.dh_bits);
338
502
  
339
503
  return 0;
340
504
}
341
505
 
342
 
void empty_log(__attribute__((unused)) AvahiLogLevel level,
343
 
               __attribute__((unused)) const char *txt){}
 
506
/* Avahi log function callback */
 
507
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
 
508
                      __attribute__((unused)) const char *txt){}
344
509
 
345
 
int start_mandos_communication(const char *ip, uint16_t port,
346
 
                               unsigned int if_index){
 
510
/* Called when a Mandos server is found */
 
511
static int start_mandos_communication(const char *ip, uint16_t port,
 
512
                                      AvahiIfIndex if_index,
 
513
                                      int af){
347
514
  int ret, tcp_sd;
348
 
  struct sockaddr_in6 to;
349
 
  encrypted_session es;
 
515
  ssize_t sret;
 
516
  union {
 
517
    struct sockaddr_in in;
 
518
    struct sockaddr_in6 in6;
 
519
  } to;
350
520
  char *buffer = NULL;
351
521
  char *decrypted_buffer;
352
522
  size_t buffer_length = 0;
353
523
  size_t buffer_capacity = 0;
354
524
  ssize_t decrypted_buffer_size;
355
 
  size_t written = 0;
 
525
  size_t written;
356
526
  int retval = 0;
357
 
  char interface[IF_NAMESIZE];
 
527
  gnutls_session_t session;
 
528
  int pf;                       /* Protocol family */
 
529
  
 
530
  switch(af){
 
531
  case AF_INET6:
 
532
    pf = PF_INET6;
 
533
    break;
 
534
  case AF_INET:
 
535
    pf = PF_INET;
 
536
    break;
 
537
  default:
 
538
    fprintf(stderr, "Bad address family: %d\n", af);
 
539
    return -1;
 
540
  }
 
541
  
 
542
  ret = init_gnutls_session(&session);
 
543
  if(ret != 0){
 
544
    return -1;
 
545
  }
358
546
  
359
547
  if(debug){
360
 
    fprintf(stderr, "Setting up a tcp connection to %s, port %d\n",
361
 
            ip, port);
 
548
    fprintf(stderr, "Setting up a TCP connection to %s, port %" PRIu16
 
549
            "\n", ip, port);
362
550
  }
363
551
  
364
 
  tcp_sd = socket(PF_INET6, SOCK_STREAM, 0);
365
 
  if(tcp_sd < 0) {
 
552
  tcp_sd = socket(pf, SOCK_STREAM, 0);
 
553
  if(tcp_sd < 0){
366
554
    perror("socket");
367
555
    return -1;
368
556
  }
369
557
  
370
 
  if(if_indextoname(if_index, interface) == NULL){
371
 
    if(debug){
372
 
      perror("if_indextoname");
373
 
    }
374
 
    return -1;
375
 
  }
376
 
  
377
 
  if(debug){
378
 
    fprintf(stderr, "Binding to interface %s\n", interface);
379
 
  }
380
 
  
381
 
  memset(&to,0,sizeof(to));     /* Spurious warning */
382
 
  to.sin6_family = AF_INET6;
383
 
  ret = inet_pton(AF_INET6, ip, &to.sin6_addr);
384
 
  if (ret < 0 ){
 
558
  memset(&to, 0, sizeof(to));
 
559
  if(af == AF_INET6){
 
560
    to.in6.sin6_family = (uint16_t)af;
 
561
    ret = inet_pton(af, ip, &to.in6.sin6_addr);
 
562
  } else {                      /* IPv4 */
 
563
    to.in.sin_family = (sa_family_t)af;
 
564
    ret = inet_pton(af, ip, &to.in.sin_addr);
 
565
  }
 
566
  if(ret < 0 ){
385
567
    perror("inet_pton");
386
568
    return -1;
387
 
  }  
 
569
  }
388
570
  if(ret == 0){
389
571
    fprintf(stderr, "Bad address: %s\n", ip);
390
572
    return -1;
391
573
  }
392
 
  to.sin6_port = htons(port);   /* Spurious warning */
393
 
  
394
 
  to.sin6_scope_id = (uint32_t)if_index;
 
574
  if(af == AF_INET6){
 
575
    to.in6.sin6_port = htons(port); /* Spurious warnings from
 
576
                                       -Wconversion and
 
577
                                       -Wunreachable-code */
 
578
    
 
579
    if(IN6_IS_ADDR_LINKLOCAL /* Spurious warnings from */
 
580
       (&to.in6.sin6_addr)){ /* -Wstrict-aliasing=2 or lower and
 
581
                              -Wunreachable-code*/
 
582
      if(if_index == AVAHI_IF_UNSPEC){
 
583
        fprintf(stderr, "An IPv6 link-local address is incomplete"
 
584
                " without a network interface\n");
 
585
        return -1;
 
586
      }
 
587
      /* Set the network interface number as scope */
 
588
      to.in6.sin6_scope_id = (uint32_t)if_index;
 
589
    }
 
590
  } else {
 
591
    to.in.sin_port = htons(port); /* Spurious warnings from
 
592
                                     -Wconversion and
 
593
                                     -Wunreachable-code */
 
594
  }
395
595
  
396
596
  if(debug){
397
 
    fprintf(stderr, "Connection to: %s, port %d\n", ip, port);
398
 
/*     char addrstr[INET6_ADDRSTRLEN]; */
399
 
/*     if(inet_ntop(to.sin6_family, &(to.sin6_addr), addrstr, */
400
 
/*               sizeof(addrstr)) == NULL){ */
401
 
/*       perror("inet_ntop"); */
402
 
/*     } else { */
403
 
/*       fprintf(stderr, "Really connecting to: %s, port %d\n", */
404
 
/*            addrstr, ntohs(to.sin6_port)); */
405
 
/*     } */
 
597
    if(af == AF_INET6 and if_index != AVAHI_IF_UNSPEC){
 
598
      char interface[IF_NAMESIZE];
 
599
      if(if_indextoname((unsigned int)if_index, interface) == NULL){
 
600
        perror("if_indextoname");
 
601
      } else {
 
602
        fprintf(stderr, "Connection to: %s%%%s, port %" PRIu16 "\n",
 
603
                ip, interface, port);
 
604
      }
 
605
    } else {
 
606
      fprintf(stderr, "Connection to: %s, port %" PRIu16 "\n", ip,
 
607
              port);
 
608
    }
 
609
    char addrstr[(INET_ADDRSTRLEN > INET6_ADDRSTRLEN) ?
 
610
                 INET_ADDRSTRLEN : INET6_ADDRSTRLEN] = "";
 
611
    const char *pcret;
 
612
    if(af == AF_INET6){
 
613
      pcret = inet_ntop(af, &(to.in6.sin6_addr), addrstr,
 
614
                        sizeof(addrstr));
 
615
    } else {
 
616
      pcret = inet_ntop(af, &(to.in.sin_addr), addrstr,
 
617
                        sizeof(addrstr));
 
618
    }
 
619
    if(pcret == NULL){
 
620
      perror("inet_ntop");
 
621
    } else {
 
622
      if(strcmp(addrstr, ip) != 0){
 
623
        fprintf(stderr, "Canonical address form: %s\n", addrstr);
 
624
      }
 
625
    }
406
626
  }
407
627
  
408
 
  ret = connect(tcp_sd, (struct sockaddr *) &to, sizeof(to));
409
 
  if (ret < 0){
 
628
  if(af == AF_INET6){
 
629
    ret = connect(tcp_sd, &to.in6, sizeof(to));
 
630
  } else {
 
631
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
 
632
  }
 
633
  if(ret < 0){
410
634
    perror("connect");
411
635
    return -1;
412
636
  }
413
637
  
414
 
  ret = initgnutls (&es);
415
 
  if (ret != 0){
416
 
    retval = -1;
417
 
    return -1;
 
638
  const char *out = mandos_protocol_version;
 
639
  written = 0;
 
640
  while(true){
 
641
    size_t out_size = strlen(out);
 
642
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
 
643
                                   out_size - written));
 
644
    if(ret == -1){
 
645
      perror("write");
 
646
      retval = -1;
 
647
      goto mandos_end;
 
648
    }
 
649
    written += (size_t)ret;
 
650
    if(written < out_size){
 
651
      continue;
 
652
    } else {
 
653
      if(out == mandos_protocol_version){
 
654
        written = 0;
 
655
        out = "\r\n";
 
656
      } else {
 
657
        break;
 
658
      }
 
659
    }
418
660
  }
419
661
  
420
 
  gnutls_transport_set_ptr (es.session,
421
 
                            (gnutls_transport_ptr_t) tcp_sd);
422
 
  
423
662
  if(debug){
424
663
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
425
664
  }
426
665
  
427
 
  ret = gnutls_handshake (es.session);
428
 
  
429
 
  if (ret != GNUTLS_E_SUCCESS){
 
666
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
 
667
  
 
668
  do{
 
669
    ret = gnutls_handshake(session);
 
670
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
671
  
 
672
  if(ret != GNUTLS_E_SUCCESS){
430
673
    if(debug){
431
 
      fprintf(stderr, "\n*** Handshake failed ***\n");
432
 
      gnutls_perror (ret);
 
674
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
 
675
      gnutls_perror(ret);
433
676
    }
434
677
    retval = -1;
435
 
    goto exit;
 
678
    goto mandos_end;
436
679
  }
437
680
  
438
 
  //Retrieve OpenPGP packet that contains the wanted password
 
681
  /* Read OpenPGP packet that contains the wanted password */
439
682
  
440
683
  if(debug){
441
 
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
 
684
    fprintf(stderr, "Retrieving OpenPGP encrypted password from %s\n",
442
685
            ip);
443
686
  }
444
 
 
 
687
  
445
688
  while(true){
446
 
    if (buffer_length + BUFFER_SIZE > buffer_capacity){
447
 
      buffer = realloc(buffer, buffer_capacity + BUFFER_SIZE);
448
 
      if (buffer == NULL){
449
 
        perror("realloc");
450
 
        goto exit;
451
 
      }
452
 
      buffer_capacity += BUFFER_SIZE;
 
689
    buffer_capacity = incbuffer(&buffer, buffer_length,
 
690
                                   buffer_capacity);
 
691
    if(buffer_capacity == 0){
 
692
      perror("incbuffer");
 
693
      retval = -1;
 
694
      goto mandos_end;
453
695
    }
454
696
    
455
 
    ret = gnutls_record_recv
456
 
      (es.session, buffer+buffer_length, BUFFER_SIZE);
457
 
    if (ret == 0){
 
697
    sret = gnutls_record_recv(session, buffer+buffer_length,
 
698
                              BUFFER_SIZE);
 
699
    if(sret == 0){
458
700
      break;
459
701
    }
460
 
    if (ret < 0){
461
 
      switch(ret){
 
702
    if(sret < 0){
 
703
      switch(sret){
462
704
      case GNUTLS_E_INTERRUPTED:
463
705
      case GNUTLS_E_AGAIN:
464
706
        break;
465
707
      case GNUTLS_E_REHANDSHAKE:
466
 
        ret = gnutls_handshake (es.session);
467
 
        if (ret < 0){
468
 
          fprintf(stderr, "\n*** Handshake failed ***\n");
469
 
          gnutls_perror (ret);
 
708
        do{
 
709
          ret = gnutls_handshake(session);
 
710
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
 
711
        if(ret < 0){
 
712
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
 
713
          gnutls_perror(ret);
470
714
          retval = -1;
471
 
          goto exit;
 
715
          goto mandos_end;
472
716
        }
473
717
        break;
474
718
      default:
475
719
        fprintf(stderr, "Unknown error while reading data from"
476
 
                " encrypted session with mandos server\n");
 
720
                " encrypted session with Mandos server\n");
477
721
        retval = -1;
478
 
        gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
479
 
        goto exit;
 
722
        gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
723
        goto mandos_end;
480
724
      }
481
725
    } else {
482
 
      buffer_length += (size_t) ret;
 
726
      buffer_length += (size_t) sret;
483
727
    }
484
728
  }
485
729
  
486
 
  if (buffer_length > 0){
 
730
  if(debug){
 
731
    fprintf(stderr, "Closing TLS session\n");
 
732
  }
 
733
  
 
734
  gnutls_bye(session, GNUTLS_SHUT_RDWR);
 
735
  
 
736
  if(buffer_length > 0){
487
737
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
488
738
                                               buffer_length,
489
 
                                               &decrypted_buffer,
490
 
                                               CERT_ROOT);
491
 
    if (decrypted_buffer_size >= 0){
 
739
                                               &decrypted_buffer);
 
740
    if(decrypted_buffer_size >= 0){
 
741
      written = 0;
492
742
      while(written < (size_t) decrypted_buffer_size){
493
 
        ret = (int)fwrite (decrypted_buffer + written, 1,
494
 
                           (size_t)decrypted_buffer_size - written,
495
 
                           stdout);
 
743
        ret = (int)fwrite(decrypted_buffer + written, 1,
 
744
                          (size_t)decrypted_buffer_size - written,
 
745
                          stdout);
496
746
        if(ret == 0 and ferror(stdout)){
497
747
          if(debug){
498
748
            fprintf(stderr, "Error writing encrypted data: %s\n",
507
757
    } else {
508
758
      retval = -1;
509
759
    }
510
 
  }
511
 
 
512
 
  //shutdown procedure
513
 
 
514
 
  if(debug){
515
 
    fprintf(stderr, "Closing TLS session\n");
516
 
  }
517
 
 
 
760
  } else {
 
761
    retval = -1;
 
762
  }
 
763
  
 
764
  /* Shutdown procedure */
 
765
  
 
766
 mandos_end:
518
767
  free(buffer);
519
 
  gnutls_bye (es.session, GNUTLS_SHUT_RDWR);
520
 
 exit:
521
 
  close(tcp_sd);
522
 
  gnutls_deinit (es.session);
523
 
  gnutls_certificate_free_credentials (es.cred);
524
 
  gnutls_global_deinit ();
 
768
  ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
 
769
  if(ret == -1){
 
770
    perror("close");
 
771
  }
 
772
  gnutls_deinit(session);
525
773
  return retval;
526
774
}
527
775
 
528
 
static AvahiSimplePoll *simple_poll = NULL;
529
 
static AvahiServer *server = NULL;
530
 
 
531
 
static void resolve_callback(
532
 
    AvahiSServiceResolver *r,
533
 
    AvahiIfIndex interface,
534
 
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
535
 
    AvahiResolverEvent event,
536
 
    const char *name,
537
 
    const char *type,
538
 
    const char *domain,
539
 
    const char *host_name,
540
 
    const AvahiAddress *address,
541
 
    uint16_t port,
542
 
    AVAHI_GCC_UNUSED AvahiStringList *txt,
543
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
544
 
    AVAHI_GCC_UNUSED void* userdata) {
545
 
    
546
 
  assert(r);                    /* Spurious warning */
 
776
static void resolve_callback(AvahiSServiceResolver *r,
 
777
                             AvahiIfIndex interface,
 
778
                             AvahiProtocol proto,
 
779
                             AvahiResolverEvent event,
 
780
                             const char *name,
 
781
                             const char *type,
 
782
                             const char *domain,
 
783
                             const char *host_name,
 
784
                             const AvahiAddress *address,
 
785
                             uint16_t port,
 
786
                             AVAHI_GCC_UNUSED AvahiStringList *txt,
 
787
                             AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
788
                             flags,
 
789
                             __attribute__((unused)) void* userdata){
 
790
  assert(r);
547
791
  
548
792
  /* Called whenever a service has been resolved successfully or
549
793
     timed out */
550
794
  
551
 
  switch (event) {
 
795
  switch(event){
552
796
  default:
553
797
  case AVAHI_RESOLVER_FAILURE:
554
 
    fprintf(stderr, "(Resolver) Failed to resolve service '%s' of"
555
 
            " type '%s' in domain '%s': %s\n", name, type, domain,
556
 
            avahi_strerror(avahi_server_errno(server)));
 
798
    fprintf(stderr, "(Avahi Resolver) Failed to resolve service '%s'"
 
799
            " of type '%s' in domain '%s': %s\n", name, type, domain,
 
800
            avahi_strerror(avahi_server_errno(mc.server)));
557
801
    break;
558
802
    
559
803
  case AVAHI_RESOLVER_FOUND:
561
805
      char ip[AVAHI_ADDRESS_STR_MAX];
562
806
      avahi_address_snprint(ip, sizeof(ip), address);
563
807
      if(debug){
564
 
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s) on"
565
 
                " port %d\n", name, host_name, ip, port);
 
808
        fprintf(stderr, "Mandos server \"%s\" found on %s (%s, %"
 
809
                PRIdMAX ") on port %" PRIu16 "\n", name, host_name,
 
810
                ip, (intmax_t)interface, port);
566
811
      }
567
 
      int ret = start_mandos_communication(ip, port,
568
 
                                           (unsigned int) interface);
569
 
      if (ret == 0){
570
 
        exit(EXIT_SUCCESS);
 
812
      int ret = start_mandos_communication(ip, port, interface,
 
813
                                           avahi_proto_to_af(proto));
 
814
      if(ret == 0){
 
815
        avahi_simple_poll_quit(mc.simple_poll);
571
816
      }
572
817
    }
573
818
  }
574
819
  avahi_s_service_resolver_free(r);
575
820
}
576
821
 
577
 
static void browse_callback(
578
 
    AvahiSServiceBrowser *b,
579
 
    AvahiIfIndex interface,
580
 
    AvahiProtocol protocol,
581
 
    AvahiBrowserEvent event,
582
 
    const char *name,
583
 
    const char *type,
584
 
    const char *domain,
585
 
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
586
 
    void* userdata) {
587
 
    
588
 
    AvahiServer *s = userdata;
589
 
    assert(b);                  /* Spurious warning */
590
 
    
591
 
    /* Called whenever a new services becomes available on the LAN or
592
 
       is removed from the LAN */
593
 
    
594
 
    switch (event) {
595
 
    default:
596
 
    case AVAHI_BROWSER_FAILURE:
597
 
      
598
 
      fprintf(stderr, "(Browser) %s\n",
599
 
              avahi_strerror(avahi_server_errno(server)));
600
 
      avahi_simple_poll_quit(simple_poll);
601
 
      return;
602
 
      
603
 
    case AVAHI_BROWSER_NEW:
604
 
      /* We ignore the returned resolver object. In the callback
605
 
         function we free it. If the server is terminated before
606
 
         the callback function is called the server will free
607
 
         the resolver for us. */
608
 
      
609
 
      if (!(avahi_s_service_resolver_new(s, interface, protocol, name,
610
 
                                         type, domain,
611
 
                                         AVAHI_PROTO_INET6, 0,
612
 
                                         resolve_callback, s)))
613
 
        fprintf(stderr, "Failed to resolve service '%s': %s\n", name,
614
 
                avahi_strerror(avahi_server_errno(s)));
615
 
      break;
616
 
      
617
 
    case AVAHI_BROWSER_REMOVE:
618
 
      break;
619
 
      
620
 
    case AVAHI_BROWSER_ALL_FOR_NOW:
621
 
    case AVAHI_BROWSER_CACHE_EXHAUSTED:
622
 
      break;
 
822
static void browse_callback(AvahiSServiceBrowser *b,
 
823
                            AvahiIfIndex interface,
 
824
                            AvahiProtocol protocol,
 
825
                            AvahiBrowserEvent event,
 
826
                            const char *name,
 
827
                            const char *type,
 
828
                            const char *domain,
 
829
                            AVAHI_GCC_UNUSED AvahiLookupResultFlags
 
830
                            flags,
 
831
                            __attribute__((unused)) void* userdata){
 
832
  assert(b);
 
833
  
 
834
  /* Called whenever a new services becomes available on the LAN or
 
835
     is removed from the LAN */
 
836
  
 
837
  switch(event){
 
838
  default:
 
839
  case AVAHI_BROWSER_FAILURE:
 
840
    
 
841
    fprintf(stderr, "(Avahi browser) %s\n",
 
842
            avahi_strerror(avahi_server_errno(mc.server)));
 
843
    avahi_simple_poll_quit(mc.simple_poll);
 
844
    return;
 
845
    
 
846
  case AVAHI_BROWSER_NEW:
 
847
    /* We ignore the returned Avahi resolver object. In the callback
 
848
       function we free it. If the Avahi server is terminated before
 
849
       the callback function is called the Avahi server will free the
 
850
       resolver for us. */
 
851
    
 
852
    if(!(avahi_s_service_resolver_new(mc.server, interface,
 
853
                                       protocol, name, type, domain,
 
854
                                       AVAHI_PROTO_INET6, 0,
 
855
                                       resolve_callback, NULL)))
 
856
      fprintf(stderr, "Avahi: Failed to resolve service '%s': %s\n",
 
857
              name, avahi_strerror(avahi_server_errno(mc.server)));
 
858
    break;
 
859
    
 
860
  case AVAHI_BROWSER_REMOVE:
 
861
    break;
 
862
    
 
863
  case AVAHI_BROWSER_ALL_FOR_NOW:
 
864
  case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
865
    if(debug){
 
866
      fprintf(stderr, "No Mandos server found, still searching...\n");
623
867
    }
624
 
}
625
 
 
626
 
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
627
 
    AvahiServerConfig config;
628
 
    AvahiSServiceBrowser *sb = NULL;
629
 
    int error;
630
 
    int ret;
631
 
    int returncode = EXIT_SUCCESS;
632
 
    const char *interface = "eth0";
633
 
    unsigned int if_index;
634
 
    char *connect_to = NULL;
 
868
    break;
 
869
  }
 
870
}
 
871
 
 
872
static void handle_sigterm(__attribute__((unused)) int sig){
 
873
  int old_errno = errno;
 
874
  avahi_simple_poll_quit(mc.simple_poll);
 
875
  errno = old_errno;
 
876
}
 
877
 
 
878
int main(int argc, char *argv[]){
 
879
  AvahiSServiceBrowser *sb = NULL;
 
880
  int error;
 
881
  int ret;
 
882
  intmax_t tmpmax;
 
883
  int numchars;
 
884
  int exitcode = EXIT_SUCCESS;
 
885
  const char *interface = "eth0";
 
886
  struct ifreq network;
 
887
  int sd;
 
888
  uid_t uid;
 
889
  gid_t gid;
 
890
  char *connect_to = NULL;
 
891
  char tempdir[] = "/tmp/mandosXXXXXX";
 
892
  bool tempdir_created = false;
 
893
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
 
894
  const char *seckey = PATHDIR "/" SECKEY;
 
895
  const char *pubkey = PATHDIR "/" PUBKEY;
 
896
  
 
897
  bool gnutls_initialized = false;
 
898
  bool gpgme_initialized = false;
 
899
  double delay = 2.5;
 
900
 
 
901
  struct sigaction old_sigterm_action;
 
902
  struct sigaction sigterm_action = { .sa_handler = handle_sigterm };
 
903
 
 
904
  /* Initialize mandos context */
 
905
  mc = (mandos_context){ .simple_poll = NULL, .server = NULL,
 
906
                         .dh_bits = 1024, .priority = "SECURE256"
 
907
                         ":!CTYPE-X.509:+CTYPE-OPENPGP" };
 
908
  
 
909
  {
 
910
    struct argp_option options[] = {
 
911
      { .name = "debug", .key = 128,
 
912
        .doc = "Debug mode", .group = 3 },
 
913
      { .name = "connect", .key = 'c',
 
914
        .arg = "ADDRESS:PORT",
 
915
        .doc = "Connect directly to a specific Mandos server",
 
916
        .group = 1 },
 
917
      { .name = "interface", .key = 'i',
 
918
        .arg = "NAME",
 
919
        .doc = "Network interface that will be used to search for"
 
920
        " Mandos servers",
 
921
        .group = 1 },
 
922
      { .name = "seckey", .key = 's',
 
923
        .arg = "FILE",
 
924
        .doc = "OpenPGP secret key file base name",
 
925
        .group = 1 },
 
926
      { .name = "pubkey", .key = 'p',
 
927
        .arg = "FILE",
 
928
        .doc = "OpenPGP public key file base name",
 
929
        .group = 2 },
 
930
      { .name = "dh-bits", .key = 129,
 
931
        .arg = "BITS",
 
932
        .doc = "Bit length of the prime number used in the"
 
933
        " Diffie-Hellman key exchange",
 
934
        .group = 2 },
 
935
      { .name = "priority", .key = 130,
 
936
        .arg = "STRING",
 
937
        .doc = "GnuTLS priority string for the TLS handshake",
 
938
        .group = 1 },
 
939
      { .name = "delay", .key = 131,
 
940
        .arg = "SECONDS",
 
941
        .doc = "Maximum delay to wait for interface startup",
 
942
        .group = 2 },
 
943
      { .name = NULL }
 
944
    };
635
945
    
636
 
    while (true){
637
 
      static struct option long_options[] = {
638
 
        {"debug", no_argument, (int *)&debug, 1},
639
 
        {"connect", required_argument, 0, 'c'},
640
 
        {"interface", required_argument, 0, 'i'},
641
 
        {0, 0, 0, 0} };
642
 
      
643
 
      int option_index = 0;
644
 
      ret = getopt_long (argc, argv, "i:", long_options,
645
 
                         &option_index);
646
 
      
647
 
      if (ret == -1){
648
 
        break;
649
 
      }
650
 
      
651
 
      switch(ret){
652
 
      case 0:
653
 
        break;
654
 
      case 'i':
655
 
        interface = optarg;
656
 
        break;
657
 
      case 'c':
658
 
        connect_to = optarg;
 
946
    error_t parse_opt(int key, char *arg,
 
947
                      struct argp_state *state){
 
948
      switch(key){
 
949
      case 128:                 /* --debug */
 
950
        debug = true;
 
951
        break;
 
952
      case 'c':                 /* --connect */
 
953
        connect_to = arg;
 
954
        break;
 
955
      case 'i':                 /* --interface */
 
956
        interface = arg;
 
957
        break;
 
958
      case 's':                 /* --seckey */
 
959
        seckey = arg;
 
960
        break;
 
961
      case 'p':                 /* --pubkey */
 
962
        pubkey = arg;
 
963
        break;
 
964
      case 129:                 /* --dh-bits */
 
965
        ret = sscanf(arg, "%" SCNdMAX "%n", &tmpmax, &numchars);
 
966
        if(ret < 1 or tmpmax != (typeof(mc.dh_bits))tmpmax
 
967
           or arg[numchars] != '\0'){
 
968
          fprintf(stderr, "Bad number of DH bits\n");
 
969
          exit(EXIT_FAILURE);
 
970
        }
 
971
        mc.dh_bits = (typeof(mc.dh_bits))tmpmax;
 
972
        break;
 
973
      case 130:                 /* --priority */
 
974
        mc.priority = arg;
 
975
        break;
 
976
      case 131:                 /* --delay */
 
977
        ret = sscanf(arg, "%lf%n", &delay, &numchars);
 
978
        if(ret < 1 or arg[numchars] != '\0'){
 
979
          fprintf(stderr, "Bad delay\n");
 
980
          exit(EXIT_FAILURE);
 
981
        }
 
982
        break;
 
983
      case ARGP_KEY_ARG:
 
984
        argp_usage(state);
 
985
      case ARGP_KEY_END:
659
986
        break;
660
987
      default:
661
 
        exit(EXIT_FAILURE);
662
 
      }
663
 
    }
664
 
    
665
 
    if_index = if_nametoindex(interface);
 
988
        return ARGP_ERR_UNKNOWN;
 
989
      }
 
990
      return 0;
 
991
    }
 
992
    
 
993
    struct argp argp = { .options = options, .parser = parse_opt,
 
994
                         .args_doc = "",
 
995
                         .doc = "Mandos client -- Get and decrypt"
 
996
                         " passwords from a Mandos server" };
 
997
    ret = argp_parse(&argp, argc, argv, 0, 0, NULL);
 
998
    if(ret == ARGP_ERR_UNKNOWN){
 
999
      fprintf(stderr, "Unknown error while parsing arguments\n");
 
1000
      exitcode = EXIT_FAILURE;
 
1001
      goto end;
 
1002
    }
 
1003
  }
 
1004
  
 
1005
  /* If the interface is down, bring it up */
 
1006
  if(interface[0] != '\0'){
 
1007
#ifdef __linux__
 
1008
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
 
1009
       messages to mess up the prompt */
 
1010
    ret = klogctl(8, NULL, 5);
 
1011
    bool restore_loglevel = true;
 
1012
    if(ret == -1){
 
1013
      restore_loglevel = false;
 
1014
      perror("klogctl");
 
1015
    }
 
1016
#endif
 
1017
    
 
1018
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1019
    if(sd < 0){
 
1020
      perror("socket");
 
1021
      exitcode = EXIT_FAILURE;
 
1022
#ifdef __linux__
 
1023
      if(restore_loglevel){
 
1024
        ret = klogctl(7, NULL, 0);
 
1025
        if(ret == -1){
 
1026
          perror("klogctl");
 
1027
        }
 
1028
      }
 
1029
#endif
 
1030
      goto end;
 
1031
    }
 
1032
    strcpy(network.ifr_name, interface);
 
1033
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1034
    if(ret == -1){
 
1035
      perror("ioctl SIOCGIFFLAGS");
 
1036
#ifdef __linux__
 
1037
      if(restore_loglevel){
 
1038
        ret = klogctl(7, NULL, 0);
 
1039
        if(ret == -1){
 
1040
          perror("klogctl");
 
1041
        }
 
1042
      }
 
1043
#endif
 
1044
      exitcode = EXIT_FAILURE;
 
1045
      goto end;
 
1046
    }
 
1047
    if((network.ifr_flags & IFF_UP) == 0){
 
1048
      network.ifr_flags |= IFF_UP;
 
1049
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
1050
      if(ret == -1){
 
1051
        perror("ioctl SIOCSIFFLAGS");
 
1052
        exitcode = EXIT_FAILURE;
 
1053
#ifdef __linux__
 
1054
        if(restore_loglevel){
 
1055
          ret = klogctl(7, NULL, 0);
 
1056
          if(ret == -1){
 
1057
            perror("klogctl");
 
1058
          }
 
1059
        }
 
1060
#endif
 
1061
        goto end;
 
1062
      }
 
1063
    }
 
1064
    /* sleep checking until interface is running */
 
1065
    for(int i=0; i < delay * 4; i++){
 
1066
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1067
      if(ret == -1){
 
1068
        perror("ioctl SIOCGIFFLAGS");
 
1069
      } else if(network.ifr_flags & IFF_RUNNING){
 
1070
        break;
 
1071
      }
 
1072
      struct timespec sleeptime = { .tv_nsec = 250000000 };
 
1073
      ret = nanosleep(&sleeptime, NULL);
 
1074
      if(ret == -1 and errno != EINTR){
 
1075
        perror("nanosleep");
 
1076
      }
 
1077
    }
 
1078
    ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
1079
    if(ret == -1){
 
1080
      perror("close");
 
1081
    }
 
1082
#ifdef __linux__
 
1083
    if(restore_loglevel){
 
1084
      /* Restores kernel loglevel to default */
 
1085
      ret = klogctl(7, NULL, 0);
 
1086
      if(ret == -1){
 
1087
        perror("klogctl");
 
1088
      }
 
1089
    }
 
1090
#endif
 
1091
  }
 
1092
  
 
1093
  uid = getuid();
 
1094
  gid = getgid();
 
1095
  
 
1096
  errno = 0;
 
1097
  setgid(gid);
 
1098
  if(ret == -1){
 
1099
    perror("setgid");
 
1100
  }
 
1101
  
 
1102
  ret = setuid(uid);
 
1103
  if(ret == -1){
 
1104
    perror("setuid");
 
1105
  }
 
1106
  
 
1107
  ret = init_gnutls_global(pubkey, seckey);
 
1108
  if(ret == -1){
 
1109
    fprintf(stderr, "init_gnutls_global failed\n");
 
1110
    exitcode = EXIT_FAILURE;
 
1111
    goto end;
 
1112
  } else {
 
1113
    gnutls_initialized = true;
 
1114
  }
 
1115
  
 
1116
  if(mkdtemp(tempdir) == NULL){
 
1117
    perror("mkdtemp");
 
1118
    goto end;
 
1119
  }
 
1120
  tempdir_created = true;
 
1121
  
 
1122
  if(not init_gpgme(pubkey, seckey, tempdir)){
 
1123
    fprintf(stderr, "init_gpgme failed\n");
 
1124
    exitcode = EXIT_FAILURE;
 
1125
    goto end;
 
1126
  } else {
 
1127
    gpgme_initialized = true;
 
1128
  }
 
1129
  
 
1130
  if(interface[0] != '\0'){
 
1131
    if_index = (AvahiIfIndex) if_nametoindex(interface);
666
1132
    if(if_index == 0){
667
1133
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
668
 
      exit(EXIT_FAILURE);
669
 
    }
670
 
    
671
 
    if(connect_to != NULL){
672
 
      /* Connect directly, do not use Zeroconf */
673
 
      /* (Mainly meant for debugging) */
674
 
      char *address = strrchr(connect_to, ':');
675
 
      if(address == NULL){
676
 
        fprintf(stderr, "No colon in address\n");
677
 
        exit(EXIT_FAILURE);
678
 
      }
679
 
      errno = 0;
680
 
      uint16_t port = (uint16_t) strtol(address+1, NULL, 10);
681
 
      if(errno){
682
 
        perror("Bad port number");
683
 
        exit(EXIT_FAILURE);
684
 
      }
685
 
      *address = '\0';
686
 
      address = connect_to;
687
 
      ret = start_mandos_communication(address, port, if_index);
688
 
      if(ret < 0){
689
 
        exit(EXIT_FAILURE);
690
 
      } else {
691
 
        exit(EXIT_SUCCESS);
692
 
      }
693
 
    }
694
 
    
695
 
    if (not debug){
696
 
      avahi_set_log_function(empty_log);
697
 
    }
698
 
    
699
 
    /* Initialize the psuedo-RNG */
700
 
    srand((unsigned int) time(NULL));
701
 
 
702
 
    /* Allocate main loop object */
703
 
    if (!(simple_poll = avahi_simple_poll_new())) {
704
 
        fprintf(stderr, "Failed to create simple poll object.\n");
705
 
        
706
 
        goto exit;
707
 
    }
708
 
 
709
 
    /* Do not publish any local records */
 
1134
      exitcode = EXIT_FAILURE;
 
1135
      goto end;
 
1136
    }
 
1137
  }
 
1138
  
 
1139
  if(connect_to != NULL){
 
1140
    /* Connect directly, do not use Zeroconf */
 
1141
    /* (Mainly meant for debugging) */
 
1142
    char *address = strrchr(connect_to, ':');
 
1143
    if(address == NULL){
 
1144
      fprintf(stderr, "No colon in address\n");
 
1145
      exitcode = EXIT_FAILURE;
 
1146
      goto end;
 
1147
    }
 
1148
    uint16_t port;
 
1149
    ret = sscanf(address+1, "%" SCNdMAX "%n", &tmpmax, &numchars);
 
1150
    if(ret < 1 or tmpmax != (uint16_t)tmpmax
 
1151
       or address[numchars+1] != '\0'){
 
1152
      fprintf(stderr, "Bad port number\n");
 
1153
      exitcode = EXIT_FAILURE;
 
1154
      goto end;
 
1155
    }
 
1156
    port = (uint16_t)tmpmax;
 
1157
    *address = '\0';
 
1158
    address = connect_to;
 
1159
    /* Colon in address indicates IPv6 */
 
1160
    int af;
 
1161
    if(strchr(address, ':') != NULL){
 
1162
      af = AF_INET6;
 
1163
    } else {
 
1164
      af = AF_INET;
 
1165
    }
 
1166
    ret = start_mandos_communication(address, port, if_index,
 
1167
                                     af);
 
1168
    if(ret < 0){
 
1169
      exitcode = EXIT_FAILURE;
 
1170
    } else {
 
1171
      exitcode = EXIT_SUCCESS;
 
1172
    }
 
1173
    goto end;
 
1174
  }
 
1175
  
 
1176
  if(not debug){
 
1177
    avahi_set_log_function(empty_log);
 
1178
  }
 
1179
  
 
1180
  /* Initialize the pseudo-RNG for Avahi */
 
1181
  srand((unsigned int) time(NULL));
 
1182
  
 
1183
  /* Allocate main Avahi loop object */
 
1184
  mc.simple_poll = avahi_simple_poll_new();
 
1185
  if(mc.simple_poll == NULL){
 
1186
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
 
1187
    exitcode = EXIT_FAILURE;
 
1188
    goto end;
 
1189
  }
 
1190
  
 
1191
  {
 
1192
    AvahiServerConfig config;
 
1193
    /* Do not publish any local Zeroconf records */
710
1194
    avahi_server_config_init(&config);
711
1195
    config.publish_hinfo = 0;
712
1196
    config.publish_addresses = 0;
713
1197
    config.publish_workstation = 0;
714
1198
    config.publish_domain = 0;
715
 
 
 
1199
    
716
1200
    /* Allocate a new server */
717
 
    server = avahi_server_new(avahi_simple_poll_get(simple_poll),
718
 
                              &config, NULL, NULL, &error);
719
 
 
720
 
    /* Free the configuration data */
 
1201
    mc.server = avahi_server_new(avahi_simple_poll_get
 
1202
                                 (mc.simple_poll), &config, NULL,
 
1203
                                 NULL, &error);
 
1204
    
 
1205
    /* Free the Avahi configuration data */
721
1206
    avahi_server_config_free(&config);
722
 
 
723
 
    /* Check if creating the server object succeeded */
724
 
    if (!server) {
725
 
        fprintf(stderr, "Failed to create server: %s\n",
726
 
                avahi_strerror(error));
727
 
        returncode = EXIT_FAILURE;
728
 
        goto exit;
729
 
    }
730
 
    
731
 
    /* Create the service browser */
732
 
    sb = avahi_s_service_browser_new(server, (AvahiIfIndex)if_index,
733
 
                                     AVAHI_PROTO_INET6,
734
 
                                     "_mandos._tcp", NULL, 0,
735
 
                                     browse_callback, server);
736
 
    if (!sb) {
737
 
        fprintf(stderr, "Failed to create service browser: %s\n",
738
 
                avahi_strerror(avahi_server_errno(server)));
739
 
        returncode = EXIT_FAILURE;
740
 
        goto exit;
741
 
    }
742
 
    
743
 
    /* Run the main loop */
744
 
 
745
 
    if (debug){
746
 
      fprintf(stderr, "Starting avahi loop search\n");
747
 
    }
748
 
    
749
 
    avahi_simple_poll_loop(simple_poll);
750
 
    
751
 
 exit:
752
 
 
753
 
    if (debug){
754
 
      fprintf(stderr, "%s exiting\n", argv[0]);
755
 
    }
756
 
    
757
 
    /* Cleanup things */
758
 
    if (sb)
759
 
        avahi_s_service_browser_free(sb);
760
 
    
761
 
    if (server)
762
 
        avahi_server_free(server);
763
 
 
764
 
    if (simple_poll)
765
 
        avahi_simple_poll_free(simple_poll);
766
 
 
767
 
    return returncode;
 
1207
  }
 
1208
  
 
1209
  /* Check if creating the Avahi server object succeeded */
 
1210
  if(mc.server == NULL){
 
1211
    fprintf(stderr, "Failed to create Avahi server: %s\n",
 
1212
            avahi_strerror(error));
 
1213
    exitcode = EXIT_FAILURE;
 
1214
    goto end;
 
1215
  }
 
1216
  
 
1217
  /* Create the Avahi service browser */
 
1218
  sb = avahi_s_service_browser_new(mc.server, if_index,
 
1219
                                   AVAHI_PROTO_INET6, "_mandos._tcp",
 
1220
                                   NULL, 0, browse_callback, NULL);
 
1221
  if(sb == NULL){
 
1222
    fprintf(stderr, "Failed to create service browser: %s\n",
 
1223
            avahi_strerror(avahi_server_errno(mc.server)));
 
1224
    exitcode = EXIT_FAILURE;
 
1225
    goto end;
 
1226
  }
 
1227
 
 
1228
  sigemptyset(&sigterm_action.sa_mask);
 
1229
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
 
1230
  if(ret == -1){
 
1231
    perror("sigaddset");
 
1232
    exitcode = EXIT_FAILURE;
 
1233
    goto end;
 
1234
  }
 
1235
  ret = sigaction(SIGTERM, &sigterm_action, &old_sigterm_action);
 
1236
  if(ret == -1){
 
1237
    perror("sigaction");
 
1238
    exitcode = EXIT_FAILURE;
 
1239
    goto end;
 
1240
  }  
 
1241
  
 
1242
  /* Run the main loop */
 
1243
  
 
1244
  if(debug){
 
1245
    fprintf(stderr, "Starting Avahi loop search\n");
 
1246
  }
 
1247
  
 
1248
  avahi_simple_poll_loop(mc.simple_poll);
 
1249
  
 
1250
 end:
 
1251
  
 
1252
  if(debug){
 
1253
    fprintf(stderr, "%s exiting\n", argv[0]);
 
1254
  }
 
1255
  
 
1256
  /* Cleanup things */
 
1257
  if(sb != NULL)
 
1258
    avahi_s_service_browser_free(sb);
 
1259
  
 
1260
  if(mc.server != NULL)
 
1261
    avahi_server_free(mc.server);
 
1262
  
 
1263
  if(mc.simple_poll != NULL)
 
1264
    avahi_simple_poll_free(mc.simple_poll);
 
1265
  
 
1266
  if(gnutls_initialized){
 
1267
    gnutls_certificate_free_credentials(mc.cred);
 
1268
    gnutls_global_deinit();
 
1269
    gnutls_dh_params_deinit(mc.dh_params);
 
1270
  }
 
1271
  
 
1272
  if(gpgme_initialized){
 
1273
    gpgme_release(mc.ctx);
 
1274
  }
 
1275
  
 
1276
  /* Removes the temp directory used by GPGME */
 
1277
  if(tempdir_created){
 
1278
    DIR *d;
 
1279
    struct dirent *direntry;
 
1280
    d = opendir(tempdir);
 
1281
    if(d == NULL){
 
1282
      if(errno != ENOENT){
 
1283
        perror("opendir");
 
1284
      }
 
1285
    } else {
 
1286
      while(true){
 
1287
        direntry = readdir(d);
 
1288
        if(direntry == NULL){
 
1289
          break;
 
1290
        }
 
1291
        /* Skip "." and ".." */
 
1292
        if(direntry->d_name[0] == '.'
 
1293
           and (direntry->d_name[1] == '\0'
 
1294
                or (direntry->d_name[1] == '.'
 
1295
                    and direntry->d_name[2] == '\0'))){
 
1296
          continue;
 
1297
        }
 
1298
        char *fullname = NULL;
 
1299
        ret = asprintf(&fullname, "%s/%s", tempdir,
 
1300
                       direntry->d_name);
 
1301
        if(ret < 0){
 
1302
          perror("asprintf");
 
1303
          continue;
 
1304
        }
 
1305
        ret = remove(fullname);
 
1306
        if(ret == -1){
 
1307
          fprintf(stderr, "remove(\"%s\"): %s\n", fullname,
 
1308
                  strerror(errno));
 
1309
        }
 
1310
        free(fullname);
 
1311
      }
 
1312
      closedir(d);
 
1313
    }
 
1314
    ret = rmdir(tempdir);
 
1315
    if(ret == -1 and errno != ENOENT){
 
1316
      perror("rmdir");
 
1317
    }
 
1318
  }
 
1319
  
 
1320
  return exitcode;
768
1321
}