/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/mandosclient.c

  • Committer: Björn Påhlsson
  • Date: 2008-08-02 21:06:29 UTC
  • mto: (237.7.1 mandos) (24.1.154 mandos)
  • mto: This revision was merged to the branch mainline in revision 38.
  • Revision ID: belorn@braxen-20080802210629-p9jc5515yufcg4ge
not working midwork...

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