/mandos/trunk

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

« back to all changes in this revision

Viewing changes to plugins.d/password-request.c

  • Committer: Teddy Hogeborn
  • Date: 2008-08-29 05:53:59 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080829055359-wkdasnyxtylmnxus
* mandos.xml (EXAMPLE): Replaced all occurences of command name with
                        "&COMMANDNAME;".

* plugins.d/password-prompt.c (main): Improved some documentation
                                      strings.  Do perror() of
                                      tcgetattr() fails.  Add debug
                                      output if interrupted by signal.
                                      Loop over write() instead of
                                      using fwrite() when outputting
                                      password.  Add debug output if
                                      getline() returns 0, unless it
                                      was caused by a signal.  Add
                                      exit status code to debug
                                      output.

* plugins.d/password-prompt.xml: Changed all single quotes to double
                                 quotes for consistency.  Removed
                                 <?xml-stylesheet>.
  (ENTITY TIMESTAMP): New.  Automatically updated by Emacs time-stamp
                      by using Emacs local variables.
  (/refentry/refentryinfo/title): Changed to "Mandos Manual".
  (/refentry/refentryinfo/productname): Changed to "Mandos".
  (/refentry/refentryinfo/date): New; set to "&TIMESTAMP;".
  (/refentry/refentryinfo/copyright): Split copyright holders.
  (/refentry/refnamediv/refpurpose): Improved wording.
  (SYNOPSIS): Fix to use correct markup.  Add short options.
  (DESCRIPTION, OPTIONS): Improved wording.
  (OPTIONS): Improved wording.  Use more correct markup.  Document
             short options.
  (EXIT STATUS): Add text.
  (ENVIRONMENT): Document use of "cryptsource" and "crypttarget".
  (FILES): REMOVED.
  (BUGS): Add text.
  (EXAMPLE): Added some examples.
  (SECURITY): Added text.
  (SEE ALSO): Remove reference to mandos(8).  Add reference to
              crypttab(5).

Show diffs side-by-side

added added

removed removed

Lines of Context:
47
47
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
48
48
                                   sockaddr_in6, PF_INET6,
49
49
                                   SOCK_STREAM, INET6_ADDRSTRLEN,
50
 
                                   uid_t, gid_t, open(), opendir(), DIR */
51
 
#include <sys/stat.h>           /* open() */
 
50
                                   uid_t, gid_t */
 
51
#include <inttypes.h>           /* PRIu16 */
52
52
#include <sys/socket.h>         /* socket(), struct sockaddr_in6,
53
53
                                   struct in6_addr, inet_pton(),
54
54
                                   connect() */
55
 
#include <fcntl.h>              /* open() */
56
 
#include <dirent.h>             /* opendir(), struct dirent, readdir() */
57
 
#include <inttypes.h>           /* PRIu16 */
58
55
#include <assert.h>             /* assert() */
59
56
#include <errno.h>              /* perror(), errno */
60
57
#include <time.h>               /* time() */
61
58
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
62
59
                                   SIOCSIFFLAGS, if_indextoname(),
63
60
                                   if_nametoindex(), IF_NAMESIZE */
64
 
#include <netinet/in.h>
65
61
#include <unistd.h>             /* close(), SEEK_SET, off_t, write(),
66
62
                                   getuid(), getgid(), setuid(),
67
63
                                   setgid() */
 
64
#include <netinet/in.h>
68
65
#include <arpa/inet.h>          /* inet_pton(), htons */
69
66
#include <iso646.h>             /* not, and */
70
67
#include <argp.h>               /* struct argp_option, error_t, struct
101
98
 
102
99
#define BUFFER_SIZE 256
103
100
 
104
 
/*
105
 
  #define PATHDIR "/conf/conf.d/mandos"
106
 
*/
107
 
 
108
 
#define PATHDIR "/conf/conf.d/mandos"
109
 
#define SECKEY "seckey.txt"
110
 
#define PUBKEY "pupkey.txt"
111
 
 
112
101
bool debug = false;
 
102
static const char *keydir = "/conf/conf.d/mandos";
113
103
static const char mandos_protocol_version[] = "1";
114
104
const char *argp_program_version = "password-request 1.0";
115
105
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
122
112
  unsigned int dh_bits;
123
113
  gnutls_dh_params_t dh_params;
124
114
  const char *priority;
125
 
  gpgme_ctx_t ctx;
126
115
} mandos_context;
127
116
 
128
117
/*
143
132
}
144
133
 
145
134
/* 
146
 
 * Initialize GPGME.
 
135
 * Decrypt OpenPGP data using keyrings in HOMEDIR.
 
136
 * Returns -1 on error
147
137
 */
148
 
static bool init_gpgme(mandos_context *mc, const char *seckey,
149
 
                       const char *pubkey, const char *tempdir){
150
 
  int ret;
 
138
static ssize_t pgp_packet_decrypt (const char *cryptotext,
 
139
                                   size_t crypto_size,
 
140
                                   char **plaintext,
 
141
                                   const char *homedir){
 
142
  gpgme_data_t dh_crypto, dh_plain;
 
143
  gpgme_ctx_t ctx;
151
144
  gpgme_error_t rc;
 
145
  ssize_t ret;
 
146
  size_t plaintext_capacity = 0;
 
147
  ssize_t plaintext_length = 0;
152
148
  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 = 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 = TEMP_FAILURE_RETRY(close(fd));
183
 
    if(ret == -1){
184
 
      perror("close");
185
 
    }
186
 
    gpgme_data_release(pgp_data);
187
 
    return true;
188
 
  }
189
149
  
190
150
  if (debug){
191
 
    fprintf(stderr, "Initialize gpgme\n");
 
151
    fprintf(stderr, "Trying to decrypt OpenPGP data\n");
192
152
  }
193
 
 
 
153
  
194
154
  /* Init GPGME */
195
155
  gpgme_check_version(NULL);
196
156
  rc = gpgme_engine_check_version(GPGME_PROTOCOL_OpenPGP);
197
157
  if (rc != GPG_ERR_NO_ERROR){
198
158
    fprintf(stderr, "bad gpgme_engine_check_version: %s: %s\n",
199
159
            gpgme_strsource(rc), gpgme_strerror(rc));
200
 
    return false;
 
160
    return -1;
201
161
  }
202
 
 
203
 
    /* Set GPGME home directory for the OpenPGP engine only */
 
162
  
 
163
  /* Set GPGME home directory for the OpenPGP engine only */
204
164
  rc = gpgme_get_engine_info (&engine_info);
205
165
  if (rc != GPG_ERR_NO_ERROR){
206
166
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
207
167
            gpgme_strsource(rc), gpgme_strerror(rc));
208
 
    return false;
 
168
    return -1;
209
169
  }
210
170
  while(engine_info != NULL){
211
171
    if(engine_info->protocol == GPGME_PROTOCOL_OpenPGP){
212
172
      gpgme_set_engine_info(GPGME_PROTOCOL_OpenPGP,
213
 
                            engine_info->file_name, tempdir);
 
173
                            engine_info->file_name, homedir);
214
174
      break;
215
175
    }
216
176
    engine_info = engine_info->next;
217
177
  }
218
178
  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");
 
179
    fprintf(stderr, "Could not set GPGME home dir to %s\n", homedir);
 
180
    return -1;
254
181
  }
255
182
  
256
183
  /* Create new GPGME data buffer from memory cryptotext */
271
198
    return -1;
272
199
  }
273
200
  
 
201
  /* Create new GPGME "context" */
 
202
  rc = gpgme_new(&ctx);
 
203
  if (rc != GPG_ERR_NO_ERROR){
 
204
    fprintf(stderr, "bad gpgme_new: %s: %s\n",
 
205
            gpgme_strsource(rc), gpgme_strerror(rc));
 
206
    plaintext_length = -1;
 
207
    goto decrypt_end;
 
208
  }
 
209
  
274
210
  /* Decrypt data from the cryptotext data buffer to the plaintext
275
211
     data buffer */
276
 
  rc = gpgme_op_decrypt(mc->ctx, dh_crypto, dh_plain);
 
212
  rc = gpgme_op_decrypt(ctx, dh_crypto, dh_plain);
277
213
  if (rc != GPG_ERR_NO_ERROR){
278
214
    fprintf(stderr, "bad gpgme_op_decrypt: %s: %s\n",
279
215
            gpgme_strsource(rc), gpgme_strerror(rc));
280
216
    plaintext_length = -1;
281
217
    if (debug){
282
218
      gpgme_decrypt_result_t result;
283
 
      result = gpgme_op_decrypt_result(mc->ctx);
 
219
      result = gpgme_op_decrypt_result(ctx);
284
220
      if (result == NULL){
285
221
        fprintf(stderr, "gpgme_op_decrypt_result failed\n");
286
222
      } else {
345
281
    }
346
282
    plaintext_length += ret;
347
283
  }
348
 
  
 
284
 
349
285
  if(debug){
350
286
    fprintf(stderr, "Decrypted password is: ");
351
287
    for(ssize_t i = 0; i < plaintext_length; i++){
412
348
  }
413
349
  
414
350
  if(debug){
415
 
    fprintf(stderr, "Attempting to use OpenPGP public key %s and"
416
 
            " secret key %s as GnuTLS credentials\n", pubkeyfilename,
 
351
    fprintf(stderr, "Attempting to use OpenPGP certificate %s"
 
352
            " and keyfile %s as GnuTLS credentials\n", pubkeyfilename,
417
353
            seckeyfilename);
418
354
  }
419
355
  
424
360
    fprintf(stderr,
425
361
            "Error[%d] while reading the OpenPGP key pair ('%s',"
426
362
            " '%s')\n", ret, pubkeyfilename, seckeyfilename);
427
 
    fprintf(stderr, "The GnuTLS error is: %s\n",
 
363
    fprintf(stdout, "The GnuTLS error is: %s\n",
428
364
            safer_gnutls_strerror(ret));
429
365
    goto globalfail;
430
366
  }
444
380
  }
445
381
  
446
382
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
447
 
  
 
383
 
448
384
  return 0;
449
 
  
 
385
 
450
386
 globalfail:
451
 
  
 
387
 
452
388
  gnutls_certificate_free_credentials(mc->cred);
453
389
  gnutls_global_deinit();
454
390
  return -1;
 
391
 
455
392
}
456
393
 
457
394
static int init_gnutls_session(mandos_context *mc,
529
466
    perror("socket");
530
467
    return -1;
531
468
  }
532
 
  
 
469
 
533
470
  if(debug){
534
471
    if(if_indextoname((unsigned int)if_index, interface) == NULL){
535
472
      perror("if_indextoname");
574
511
    perror("connect");
575
512
    return -1;
576
513
  }
577
 
  
 
514
 
578
515
  const char *out = mandos_protocol_version;
579
516
  written = 0;
580
517
  while (true){
598
535
      }
599
536
    }
600
537
  }
601
 
  
 
538
 
602
539
  if(debug){
603
540
    fprintf(stderr, "Establishing TLS session with %s\n", ip);
604
541
  }
605
542
  
606
543
  gnutls_transport_set_ptr (session, (gnutls_transport_ptr_t) tcp_sd);
607
 
  
 
544
 
608
545
  do{
609
546
    ret = gnutls_handshake (session);
610
547
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
624
561
    fprintf(stderr, "Retrieving pgp encrypted password from %s\n",
625
562
            ip);
626
563
  }
627
 
  
 
564
 
628
565
  while(true){
629
566
    buffer_capacity = adjustbuffer(&buffer, buffer_length,
630
567
                                   buffer_capacity);
674
611
  gnutls_bye (session, GNUTLS_SHUT_RDWR);
675
612
  
676
613
  if (buffer_length > 0){
677
 
    decrypted_buffer_size = pgp_packet_decrypt(mc, buffer,
 
614
    decrypted_buffer_size = pgp_packet_decrypt(buffer,
678
615
                                               buffer_length,
679
 
                                               &decrypted_buffer);
 
616
                                               &decrypted_buffer,
 
617
                                               keydir);
680
618
    if (decrypted_buffer_size >= 0){
681
619
      written = 0;
682
620
      while(written < (size_t) decrypted_buffer_size){
705
643
  
706
644
 mandos_end:
707
645
  free(buffer);
708
 
  ret = TEMP_FAILURE_RETRY(close(tcp_sd));
709
 
  if(ret == -1){
710
 
    perror("close");
711
 
  }
 
646
  close(tcp_sd);
712
647
  gnutls_deinit (session);
713
648
  return retval;
714
649
}
810
745
  }
811
746
}
812
747
 
 
748
/* Combines file name and path and returns the malloced new
 
749
   string. some sane checks could/should be added */
 
750
static char *combinepath(const char *first, const char *second){
 
751
  char *tmp;
 
752
  int ret = asprintf(&tmp, "%s/%s", first, second);
 
753
  if(ret < 0){
 
754
    return NULL;
 
755
  }
 
756
  return tmp;
 
757
}
 
758
 
 
759
 
813
760
int main(int argc, char *argv[]){
814
761
    AvahiSServiceBrowser *sb = NULL;
815
762
    int error;
821
768
    uid_t uid;
822
769
    gid_t gid;
823
770
    char *connect_to = NULL;
824
 
    char tempdir[] = "/tmp/mandosXXXXXX";
825
771
    AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
826
 
    const char *seckey = PATHDIR "/" SECKEY;
827
 
    const char *pubkey = PATHDIR "/" PUBKEY;
828
 
    
 
772
    char *pubkeyfilename = NULL;
 
773
    char *seckeyfilename = NULL;
 
774
    const char *pubkeyname = "pubkey.txt";
 
775
    const char *seckeyname = "seckey.txt";
829
776
    mandos_context mc = { .simple_poll = NULL, .server = NULL,
830
 
                          .dh_bits = 1024, .priority = "SECURE256"
831
 
                          ":!CTYPE-X.509:+CTYPE-OPENPGP" };
 
777
                          .dh_bits = 1024, .priority = "SECURE256"};
832
778
    bool gnutls_initalized = false;
833
 
    bool pgpme_initalized = false;
834
779
    
835
780
    {
836
781
      struct argp_option options[] = {
837
782
        { .name = "debug", .key = 128,
838
783
          .doc = "Debug mode", .group = 3 },
839
784
        { .name = "connect", .key = 'c',
840
 
          .arg = "ADDRESS:PORT",
841
 
          .doc = "Connect directly to a specific Mandos server",
 
785
          .arg = "IP",
 
786
          .doc = "Connect directly to a sepcified mandos server",
842
787
          .group = 1 },
843
788
        { .name = "interface", .key = 'i',
844
 
          .arg = "NAME",
845
 
          .doc = "Interface that will be used to search for Mandos"
846
 
          " servers",
 
789
          .arg = "INTERFACE",
 
790
          .doc = "Interface that Avahi will conntect through",
 
791
          .group = 1 },
 
792
        { .name = "keydir", .key = 'd',
 
793
          .arg = "KEYDIR",
 
794
          .doc = "Directory where the openpgp keyring is",
847
795
          .group = 1 },
848
796
        { .name = "seckey", .key = 's',
849
 
          .arg = "FILE",
850
 
          .doc = "OpenPGP secret key file base name",
 
797
          .arg = "SECKEY",
 
798
          .doc = "Secret openpgp key for gnutls authentication",
851
799
          .group = 1 },
852
800
        { .name = "pubkey", .key = 'p',
853
 
          .arg = "FILE",
854
 
          .doc = "OpenPGP public key file base name",
 
801
          .arg = "PUBKEY",
 
802
          .doc = "Public openpgp key for gnutls authentication",
855
803
          .group = 2 },
856
804
        { .name = "dh-bits", .key = 129,
857
805
          .arg = "BITS",
858
 
          .doc = "Bit length of the prime number used in the"
859
 
          " Diffie-Hellman key exchange",
 
806
          .doc = "dh-bits to use in gnutls communication",
860
807
          .group = 2 },
861
808
        { .name = "priority", .key = 130,
862
 
          .arg = "STRING",
863
 
          .doc = "GnuTLS priority string for the TLS handshake",
864
 
          .group = 1 },
 
809
          .arg = "PRIORITY",
 
810
          .doc = "GNUTLS priority", .group = 1 },
865
811
        { .name = NULL }
866
812
      };
 
813
 
867
814
      
868
815
      error_t parse_opt (int key, char *arg,
869
816
                         struct argp_state *state) {
870
817
        /* Get the INPUT argument from `argp_parse', which we know is
871
818
           a pointer to our plugin list pointer. */
872
819
        switch (key) {
873
 
        case 128:               /* --debug */
 
820
        case 128:
874
821
          debug = true;
875
822
          break;
876
 
        case 'c':               /* --connect */
 
823
        case 'c':
877
824
          connect_to = arg;
878
825
          break;
879
 
        case 'i':               /* --interface */
 
826
        case 'i':
880
827
          interface = arg;
881
828
          break;
882
 
        case 's':               /* --seckey */
883
 
          seckey = arg;
884
 
          break;
885
 
        case 'p':               /* --pubkey */
886
 
          pubkey = arg;
887
 
          break;
888
 
        case 129:               /* --dh-bits */
 
829
        case 'd':
 
830
          keydir = arg;
 
831
          break;
 
832
        case 's':
 
833
          seckeyname = arg;
 
834
          break;
 
835
        case 'p':
 
836
          pubkeyname = arg;
 
837
          break;
 
838
        case 129:
889
839
          errno = 0;
890
840
          mc.dh_bits = (unsigned int) strtol(arg, NULL, 10);
891
841
          if (errno){
893
843
            exit(EXIT_FAILURE);
894
844
          }
895
845
          break;
896
 
        case 130:               /* --priority */
 
846
        case 130:
897
847
          mc.priority = arg;
898
848
          break;
899
849
        case ARGP_KEY_ARG:
905
855
        }
906
856
        return 0;
907
857
      }
908
 
      
 
858
 
909
859
      struct argp argp = { .options = options, .parser = parse_opt,
910
860
                           .args_doc = "",
911
861
                           .doc = "Mandos client -- Get and decrypt"
912
 
                           " passwords from a Mandos server" };
 
862
                           " passwords from mandos server" };
913
863
      ret = argp_parse (&argp, argc, argv, 0, 0, NULL);
914
864
      if (ret == ARGP_ERR_UNKNOWN){
915
865
        fprintf(stderr, "Unknown error while parsing arguments\n");
917
867
        goto end;
918
868
      }
919
869
    }
 
870
      
 
871
    pubkeyfilename = combinepath(keydir, pubkeyname);
 
872
    if (pubkeyfilename == NULL){
 
873
      perror("combinepath");
 
874
      exitcode = EXIT_FAILURE;
 
875
      goto end;
 
876
    }
920
877
    
921
 
    ret = init_gnutls_global(&mc, pubkey, seckey);
 
878
    seckeyfilename = combinepath(keydir, seckeyname);
 
879
    if (seckeyfilename == NULL){
 
880
      perror("combinepath");
 
881
      exitcode = EXIT_FAILURE;
 
882
      goto end;
 
883
    }
 
884
 
 
885
    ret = init_gnutls_global(&mc, pubkeyfilename, seckeyfilename);
922
886
    if (ret == -1){
923
887
      fprintf(stderr, "init_gnutls_global failed\n");
924
888
      exitcode = EXIT_FAILURE;
926
890
    } else {
927
891
      gnutls_initalized = true;
928
892
    }
929
 
 
930
 
    if(mkdtemp(tempdir) == NULL){
931
 
      perror("mkdtemp");
932
 
      tempdir[0] = '\0';
933
 
      goto end;
934
 
    }
935
 
    
936
 
    if(not init_gpgme(&mc, pubkey, seckey, tempdir)){
937
 
      fprintf(stderr, "pgpme_initalized failed\n");
938
 
      exitcode = EXIT_FAILURE;
939
 
      goto end;
940
 
    } else {
941
 
      pgpme_initalized = true;
942
 
    }
943
893
    
944
894
    /* If the interface is down, bring it up */
945
895
    {
965
915
          goto end;
966
916
        }
967
917
      }
968
 
      ret = TEMP_FAILURE_RETRY(close(sd));
969
 
      if(ret == -1){
970
 
        perror("close");
971
 
      }
 
918
      close(sd);
972
919
    }
973
920
    
974
921
    uid = getuid();
1032
979
        exitcode = EXIT_FAILURE;
1033
980
        goto end;
1034
981
    }
1035
 
    
 
982
 
1036
983
    {
1037
984
      AvahiServerConfig config;
1038
985
      /* Do not publish any local Zeroconf records */
1041
988
      config.publish_addresses = 0;
1042
989
      config.publish_workstation = 0;
1043
990
      config.publish_domain = 0;
1044
 
      
 
991
 
1045
992
      /* Allocate a new server */
1046
993
      mc.server = avahi_server_new(avahi_simple_poll_get
1047
994
                                   (mc.simple_poll), &config, NULL,
1048
995
                                   NULL, &error);
1049
 
      
 
996
    
1050
997
      /* Free the Avahi configuration data */
1051
998
      avahi_server_config_free(&config);
1052
999
    }
1072
1019
    }
1073
1020
    
1074
1021
    /* Run the main loop */
1075
 
    
 
1022
 
1076
1023
    if (debug){
1077
1024
      fprintf(stderr, "Starting Avahi loop search\n");
1078
1025
    }
1080
1027
    avahi_simple_poll_loop(mc.simple_poll);
1081
1028
    
1082
1029
 end:
1083
 
    
 
1030
 
1084
1031
    if (debug){
1085
1032
      fprintf(stderr, "%s exiting\n", argv[0]);
1086
1033
    }
1091
1038
    
1092
1039
    if (mc.server != NULL)
1093
1040
        avahi_server_free(mc.server);
1094
 
    
 
1041
 
1095
1042
    if (mc.simple_poll != NULL)
1096
1043
        avahi_simple_poll_free(mc.simple_poll);
1097
 
    
 
1044
    free(pubkeyfilename);
 
1045
    free(seckeyfilename);
 
1046
 
1098
1047
    if (gnutls_initalized){
1099
1048
      gnutls_certificate_free_credentials(mc.cred);
1100
1049
      gnutls_global_deinit ();
1101
1050
    }
1102
 
 
1103
 
    if(pgpme_initalized){
1104
 
      gpgme_release(mc.ctx);
1105
 
    }
1106
 
 
1107
 
    /* Removes the temp directory used by GPGME */
1108
 
    if(tempdir[0] != '\0'){
1109
 
      DIR *d;
1110
 
      struct dirent *direntry;
1111
 
      d = opendir(tempdir);
1112
 
      if(d == NULL){
1113
 
        perror("opendir");
1114
 
      } else {
1115
 
        while(true){
1116
 
          direntry = readdir(d);
1117
 
          if(direntry == NULL){
1118
 
            break;
1119
 
          }
1120
 
          if (direntry->d_type == DT_REG){
1121
 
            char *fullname = NULL;
1122
 
            ret = asprintf(&fullname, "%s/%s", tempdir,
1123
 
                           direntry->d_name);
1124
 
            if(ret < 0){
1125
 
              perror("asprintf");
1126
 
              continue;
1127
 
            }
1128
 
            ret = unlink(fullname);
1129
 
            if(ret == -1){
1130
 
              fprintf(stderr, "unlink(\"%s\"): %s",
1131
 
                      fullname, strerror(errno));
1132
 
            }
1133
 
            free(fullname);
1134
 
          }
1135
 
        }
1136
 
      }
1137
 
      ret = rmdir(tempdir);
1138
 
      if(ret == -1){
1139
 
        perror("rmdir");
1140
 
      }
1141
 
    }
1142
 
          
 
1051
    
1143
1052
    return exitcode;
1144
1053
}