/mandos/trunk

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

« back to all changes in this revision

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

  • Committer: teddy at recompile
  • Date: 2020-04-05 21:30:59 UTC
  • Revision ID: teddy@recompile.se-20200405213059-fb2a61ckqynrmatk
Fix file descriptor leak in mandos-client

When the local network has Mandos servers announcing themselves using
real, globally reachable, IPv6 addresses (i.e. not link-local
addresses), but there is no router on the local network providing IPv6
RA (Router Advertisement) packets, the client cannot reach the server
by normal means, since the client only has a link-local IPv6 address,
and has no usable route to reach the server's global IPv6 address.
(This is not a common situation, and usually only happens when the
router itself reboots and runs a Mandos client, since it cannot then
give RA packets to itself.)  The client code has a solution for
this, which consists of adding a temporary local route to reach the
address of the server during communication, and removing this
temporary route afterwards.

This solution with a temporary route works, but has a file descriptor
leak; it leaks one file descriptor for each addition and for each
removal of a route.  If one server requiring an added route is present
on the network, but no servers gives a password, making the client
retry after the default ten seconds, and we furthermore assume a
default 1024 open files limit, the client runs out of file descriptors
after about 90 minutes, after which time the client process will be
useless and fail to retrieve any passwords, necessitating manual
password entry via the keyboard.

Fix this by eliminating the file descriptor leak in the client.

* plugins.d/mandos-client.c (add_delete_local_route): Do
  close(devnull) also in parent process, also if fork() fails, and on
  any failure in child process.

Show diffs side-by-side

added added

removed removed

Lines of Context:
9
9
 * "browse_callback", and parts of "main".
10
10
 * 
11
11
 * Everything else is
12
 
 * Copyright © 2008-2017 Teddy Hogeborn
13
 
 * Copyright © 2008-2017 Björn Påhlsson
 
12
 * Copyright © 2008-2019 Teddy Hogeborn
 
13
 * Copyright © 2008-2019 Björn Påhlsson
14
14
 * 
15
15
 * This file is part of Mandos.
16
16
 * 
123
123
                                   gnutls_*
124
124
                                   init_gnutls_session(),
125
125
                                   GNUTLS_* */
 
126
#if GNUTLS_VERSION_NUMBER < 0x030600
126
127
#include <gnutls/openpgp.h>
127
128
                         /* gnutls_certificate_set_openpgp_key_file(),
128
129
                            GNUTLS_OPENPGP_FMT_BASE64 */
 
130
#elif GNUTLS_VERSION_NUMBER >= 0x030606
 
131
#include <gnutls/x509.h>        /* gnutls_pkcs_encrypt_flags_t,
 
132
                                 GNUTLS_PKCS_PLAIN,
 
133
                                 GNUTLS_PKCS_NULL_PASSWORD */
 
134
#endif
129
135
 
130
136
/* GPGME */
131
137
#include <gpgme.h>              /* All GPGME types, constants and
139
145
#define PATHDIR "/conf/conf.d/mandos"
140
146
#define SECKEY "seckey.txt"
141
147
#define PUBKEY "pubkey.txt"
 
148
#define TLS_PRIVKEY "tls-privkey.pem"
 
149
#define TLS_PUBKEY "tls-pubkey.pem"
142
150
#define HOOKDIR "/lib/mandos/network-hooks.d"
143
151
 
144
152
bool debug = false;
272
280
  return true;
273
281
}
274
282
 
 
283
/* Set effective uid to 0, return errno */
 
284
__attribute__((warn_unused_result))
 
285
int raise_privileges(void){
 
286
  int old_errno = errno;
 
287
  int ret = 0;
 
288
  if(seteuid(0) == -1){
 
289
    ret = errno;
 
290
  }
 
291
  errno = old_errno;
 
292
  return ret;
 
293
}
 
294
 
 
295
/* Set effective and real user ID to 0.  Return errno. */
 
296
__attribute__((warn_unused_result))
 
297
int raise_privileges_permanently(void){
 
298
  int old_errno = errno;
 
299
  int ret = raise_privileges();
 
300
  if(ret != 0){
 
301
    errno = old_errno;
 
302
    return ret;
 
303
  }
 
304
  if(setuid(0) == -1){
 
305
    ret = errno;
 
306
  }
 
307
  errno = old_errno;
 
308
  return ret;
 
309
}
 
310
 
 
311
/* Set effective user ID to unprivileged saved user ID */
 
312
__attribute__((warn_unused_result))
 
313
int lower_privileges(void){
 
314
  int old_errno = errno;
 
315
  int ret = 0;
 
316
  if(seteuid(uid) == -1){
 
317
    ret = errno;
 
318
  }
 
319
  errno = old_errno;
 
320
  return ret;
 
321
}
 
322
 
 
323
/* Lower privileges permanently */
 
324
__attribute__((warn_unused_result))
 
325
int lower_privileges_permanently(void){
 
326
  int old_errno = errno;
 
327
  int ret = 0;
 
328
  if(setuid(uid) == -1){
 
329
    ret = errno;
 
330
  }
 
331
  errno = old_errno;
 
332
  return ret;
 
333
}
 
334
 
275
335
/* 
276
336
 * Initialize GPGME.
277
337
 */
297
357
      return false;
298
358
    }
299
359
    
 
360
    /* Workaround for systems without a real-time clock; see also
 
361
       Debian bug #894495: <https://bugs.debian.org/894495> */
 
362
    do {
 
363
      {
 
364
        time_t currtime = time(NULL);
 
365
        if(currtime != (time_t)-1){
 
366
          struct tm tm;
 
367
          if(gmtime_r(&currtime, &tm) == NULL) {
 
368
            perror_plus("gmtime_r");
 
369
            break;
 
370
          }
 
371
          if(tm.tm_year != 70 or tm.tm_mon != 0){
 
372
            break;
 
373
          }
 
374
          if(debug){
 
375
            fprintf_plus(stderr, "System clock is January 1970");
 
376
          }
 
377
        } else {
 
378
          if(debug){
 
379
            fprintf_plus(stderr, "System clock is invalid");
 
380
          }
 
381
        }
 
382
      }
 
383
      struct stat keystat;
 
384
      ret = fstat(fd, &keystat);
 
385
      if(ret != 0){
 
386
        perror_plus("fstat");
 
387
        break;
 
388
      }
 
389
      ret = raise_privileges();
 
390
      if(ret != 0){
 
391
        errno = ret;
 
392
        perror_plus("Failed to raise privileges");
 
393
        break;
 
394
      }
 
395
      if(debug){
 
396
        fprintf_plus(stderr,
 
397
                     "Setting system clock to key file mtime");
 
398
      }
 
399
      time_t keytime = keystat.st_mtim.tv_sec;
 
400
      if(stime(&keytime) != 0){
 
401
        perror_plus("stime");
 
402
      }
 
403
      ret = lower_privileges();
 
404
      if(ret != 0){
 
405
        errno = ret;
 
406
        perror_plus("Failed to lower privileges");
 
407
      }
 
408
    } while(false);
 
409
 
300
410
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
301
411
    if(rc != GPG_ERR_NO_ERROR){
302
412
      fprintf_plus(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
310
420
                   gpgme_strsource(rc), gpgme_strerror(rc));
311
421
      return false;
312
422
    }
 
423
    {
 
424
      gpgme_import_result_t import_result
 
425
        = gpgme_op_import_result(mc->ctx);
 
426
      if((import_result->imported < 1
 
427
          or import_result->not_imported > 0)
 
428
         and import_result->unchanged == 0){
 
429
        fprintf_plus(stderr, "bad gpgme_op_import_results:\n");
 
430
        fprintf_plus(stderr,
 
431
                     "The total number of considered keys: %d\n",
 
432
                     import_result->considered);
 
433
        fprintf_plus(stderr,
 
434
                     "The number of keys without user ID: %d\n",
 
435
                     import_result->no_user_id);
 
436
        fprintf_plus(stderr,
 
437
                     "The total number of imported keys: %d\n",
 
438
                     import_result->imported);
 
439
        fprintf_plus(stderr, "The number of imported RSA keys: %d\n",
 
440
                     import_result->imported_rsa);
 
441
        fprintf_plus(stderr, "The number of unchanged keys: %d\n",
 
442
                     import_result->unchanged);
 
443
        fprintf_plus(stderr, "The number of new user IDs: %d\n",
 
444
                     import_result->new_user_ids);
 
445
        fprintf_plus(stderr, "The number of new sub keys: %d\n",
 
446
                     import_result->new_sub_keys);
 
447
        fprintf_plus(stderr, "The number of new signatures: %d\n",
 
448
                     import_result->new_signatures);
 
449
        fprintf_plus(stderr, "The number of new revocations: %d\n",
 
450
                     import_result->new_revocations);
 
451
        fprintf_plus(stderr,
 
452
                     "The total number of secret keys read: %d\n",
 
453
                     import_result->secret_read);
 
454
        fprintf_plus(stderr,
 
455
                     "The number of imported secret keys: %d\n",
 
456
                     import_result->secret_imported);
 
457
        fprintf_plus(stderr,
 
458
                     "The number of unchanged secret keys: %d\n",
 
459
                     import_result->secret_unchanged);
 
460
        fprintf_plus(stderr, "The number of keys not imported: %d\n",
 
461
                     import_result->not_imported);
 
462
        for(gpgme_import_status_t import_status
 
463
              = import_result->imports;
 
464
            import_status != NULL;
 
465
            import_status = import_status->next){
 
466
          fprintf_plus(stderr, "Import status for key: %s\n",
 
467
                       import_status->fpr);
 
468
          if(import_status->result != GPG_ERR_NO_ERROR){
 
469
            fprintf_plus(stderr, "Import result: %s: %s\n",
 
470
                         gpgme_strsource(import_status->result),
 
471
                         gpgme_strerror(import_status->result));
 
472
          }
 
473
          fprintf_plus(stderr, "Key status:\n");
 
474
          fprintf_plus(stderr,
 
475
                       import_status->status & GPGME_IMPORT_NEW
 
476
                       ? "The key was new.\n"
 
477
                       : "The key was not new.\n");
 
478
          fprintf_plus(stderr,
 
479
                       import_status->status & GPGME_IMPORT_UID
 
480
                       ? "The key contained new user IDs.\n"
 
481
                       : "The key did not contain new user IDs.\n");
 
482
          fprintf_plus(stderr,
 
483
                       import_status->status & GPGME_IMPORT_SIG
 
484
                       ? "The key contained new signatures.\n"
 
485
                       : "The key did not contain new signatures.\n");
 
486
          fprintf_plus(stderr,
 
487
                       import_status->status & GPGME_IMPORT_SUBKEY
 
488
                       ? "The key contained new sub keys.\n"
 
489
                       : "The key did not contain new sub keys.\n");
 
490
          fprintf_plus(stderr,
 
491
                       import_status->status & GPGME_IMPORT_SECRET
 
492
                       ? "The key contained a secret key.\n"
 
493
                       : "The key did not contain a secret key.\n");
 
494
        }
 
495
        return false;
 
496
      }
 
497
    }
313
498
    
314
499
    ret = close(fd);
315
500
    if(ret == -1){
356
541
  /* Create new GPGME "context" */
357
542
  rc = gpgme_new(&(mc->ctx));
358
543
  if(rc != GPG_ERR_NO_ERROR){
359
 
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
360
 
                 "bad gpgme_new: %s: %s\n", gpgme_strsource(rc),
361
 
                 gpgme_strerror(rc));
 
544
    fprintf_plus(stderr, "bad gpgme_new: %s: %s\n",
 
545
                 gpgme_strsource(rc), gpgme_strerror(rc));
362
546
    return false;
363
547
  }
364
548
  
400
584
  /* Create new empty GPGME data buffer for the plaintext */
401
585
  rc = gpgme_data_new(&dh_plain);
402
586
  if(rc != GPG_ERR_NO_ERROR){
403
 
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
404
 
                 "bad gpgme_data_new: %s: %s\n",
 
587
    fprintf_plus(stderr, "bad gpgme_data_new: %s: %s\n",
405
588
                 gpgme_strsource(rc), gpgme_strerror(rc));
406
589
    gpgme_data_release(dh_crypto);
407
590
    return -1;
420
603
      if(result == NULL){
421
604
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
422
605
      } else {
423
 
        fprintf_plus(stderr, "Unsupported algorithm: %s\n",
424
 
                     result->unsupported_algorithm);
425
 
        fprintf_plus(stderr, "Wrong key usage: %u\n",
426
 
                     result->wrong_key_usage);
 
606
        if(result->unsupported_algorithm != NULL) {
 
607
          fprintf_plus(stderr, "Unsupported algorithm: %s\n",
 
608
                       result->unsupported_algorithm);
 
609
        }
 
610
        fprintf_plus(stderr, "Wrong key usage: %s\n",
 
611
                     result->wrong_key_usage ? "Yes" : "No");
427
612
        if(result->file_name != NULL){
428
613
          fprintf_plus(stderr, "File name: %s\n", result->file_name);
429
614
        }
430
 
        gpgme_recipient_t recipient;
431
 
        recipient = result->recipients;
432
 
        while(recipient != NULL){
 
615
 
 
616
        for(gpgme_recipient_t r = result->recipients; r != NULL;
 
617
            r = r->next){
433
618
          fprintf_plus(stderr, "Public key algorithm: %s\n",
434
 
                       gpgme_pubkey_algo_name
435
 
                       (recipient->pubkey_algo));
436
 
          fprintf_plus(stderr, "Key ID: %s\n", recipient->keyid);
 
619
                       gpgme_pubkey_algo_name(r->pubkey_algo));
 
620
          fprintf_plus(stderr, "Key ID: %s\n", r->keyid);
437
621
          fprintf_plus(stderr, "Secret key available: %s\n",
438
 
                       recipient->status == GPG_ERR_NO_SECKEY
439
 
                       ? "No" : "Yes");
440
 
          recipient = recipient->next;
 
622
                       r->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
441
623
        }
442
624
      }
443
625
    }
525
707
                              const char *dhparamsfilename,
526
708
                              mandos_context *mc){
527
709
  int ret;
528
 
  unsigned int uret;
529
710
  
530
711
  if(debug){
531
712
    fprintf_plus(stderr, "Initializing GnuTLS\n");
548
729
  }
549
730
  
550
731
  if(debug){
551
 
    fprintf_plus(stderr, "Attempting to use OpenPGP public key %s and"
552
 
                 " secret key %s as GnuTLS credentials\n",
 
732
    fprintf_plus(stderr, "Attempting to use public key %s and"
 
733
                 " private key %s as GnuTLS credentials\n",
553
734
                 pubkeyfilename,
554
735
                 seckeyfilename);
555
736
  }
556
737
  
 
738
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
739
  ret = gnutls_certificate_set_rawpk_key_file
 
740
    (mc->cred, pubkeyfilename, seckeyfilename,
 
741
     GNUTLS_X509_FMT_PEM,       /* format */
 
742
     NULL,                      /* pass */
 
743
     /* key_usage */
 
744
     GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 
745
     NULL,                      /* names */
 
746
     0,                         /* names_length */
 
747
     /* privkey_flags */
 
748
     GNUTLS_PKCS_PLAIN | GNUTLS_PKCS_NULL_PASSWORD,
 
749
     0);                        /* pkcs11_flags */
 
750
#elif GNUTLS_VERSION_NUMBER < 0x030600
557
751
  ret = gnutls_certificate_set_openpgp_key_file
558
752
    (mc->cred, pubkeyfilename, seckeyfilename,
559
753
     GNUTLS_OPENPGP_FMT_BASE64);
 
754
#else
 
755
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
 
756
#endif
560
757
  if(ret != GNUTLS_E_SUCCESS){
561
758
    fprintf_plus(stderr,
562
 
                 "Error[%d] while reading the OpenPGP key pair ('%s',"
 
759
                 "Error[%d] while reading the key pair ('%s',"
563
760
                 " '%s')\n", ret, pubkeyfilename, seckeyfilename);
564
761
    fprintf_plus(stderr, "The GnuTLS error is: %s\n",
565
762
                 safer_gnutls_strerror(ret));
613
810
        }
614
811
        params.size += (unsigned int)bytes_read;
615
812
      }
 
813
      ret = close(dhpfile);
 
814
      if(ret == -1){
 
815
        perror_plus("close");
 
816
      }
616
817
      if(params.data == NULL){
617
818
        dhparamsfilename = NULL;
618
819
      }
632
833
  }
633
834
  if(dhparamsfilename == NULL){
634
835
    if(mc->dh_bits == 0){
 
836
#if GNUTLS_VERSION_NUMBER < 0x030600
635
837
      /* Find out the optimal number of DH bits */
636
838
      /* Try to read the private key file */
637
839
      gnutls_datum_t buffer = { .data = NULL, .size = 0 };
717
919
          }
718
920
        }
719
921
      }
720
 
      uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
 
922
      unsigned int uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
721
923
      if(uret != 0){
722
924
        mc->dh_bits = uret;
723
925
        if(debug){
735
937
                     safer_gnutls_strerror(ret));
736
938
        goto globalfail;
737
939
      }
738
 
    } else if(debug){
739
 
      fprintf_plus(stderr, "DH bits explicitly set to %u\n",
740
 
                   mc->dh_bits);
741
 
    }
742
 
    ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
743
 
    if(ret != GNUTLS_E_SUCCESS){
744
 
      fprintf_plus(stderr, "Error in GnuTLS prime generation (%u"
745
 
                   " bits): %s\n", mc->dh_bits,
746
 
                   safer_gnutls_strerror(ret));
747
 
      goto globalfail;
 
940
#endif
 
941
    } else {                    /* dh_bits != 0 */
 
942
      if(debug){
 
943
        fprintf_plus(stderr, "DH bits explicitly set to %u\n",
 
944
                     mc->dh_bits);
 
945
      }
 
946
      ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
 
947
      if(ret != GNUTLS_E_SUCCESS){
 
948
        fprintf_plus(stderr, "Error in GnuTLS prime generation (%u"
 
949
                     " bits): %s\n", mc->dh_bits,
 
950
                     safer_gnutls_strerror(ret));
 
951
        goto globalfail;
 
952
      }
 
953
      gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
748
954
    }
749
955
  }
750
 
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
751
956
  
752
957
  return 0;
753
958
  
764
969
  int ret;
765
970
  /* GnuTLS session creation */
766
971
  do {
767
 
    ret = gnutls_init(session, GNUTLS_SERVER);
 
972
    ret = gnutls_init(session, (GNUTLS_SERVER
 
973
#if GNUTLS_VERSION_NUMBER >= 0x030506
 
974
                                | GNUTLS_NO_TICKETS
 
975
#endif
 
976
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
977
                                | GNUTLS_ENABLE_RAWPK
 
978
#endif
 
979
                                ));
768
980
    if(quit_now){
769
981
      return -1;
770
982
    }
818
1030
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
819
1031
                      __attribute__((unused)) const char *txt){}
820
1032
 
821
 
/* Set effective uid to 0, return errno */
822
 
__attribute__((warn_unused_result))
823
 
int raise_privileges(void){
824
 
  int old_errno = errno;
825
 
  int ret = 0;
826
 
  if(seteuid(0) == -1){
827
 
    ret = errno;
828
 
  }
829
 
  errno = old_errno;
830
 
  return ret;
831
 
}
832
 
 
833
 
/* Set effective and real user ID to 0.  Return errno. */
834
 
__attribute__((warn_unused_result))
835
 
int raise_privileges_permanently(void){
836
 
  int old_errno = errno;
837
 
  int ret = raise_privileges();
838
 
  if(ret != 0){
839
 
    errno = old_errno;
840
 
    return ret;
841
 
  }
842
 
  if(setuid(0) == -1){
843
 
    ret = errno;
844
 
  }
845
 
  errno = old_errno;
846
 
  return ret;
847
 
}
848
 
 
849
 
/* Set effective user ID to unprivileged saved user ID */
850
 
__attribute__((warn_unused_result))
851
 
int lower_privileges(void){
852
 
  int old_errno = errno;
853
 
  int ret = 0;
854
 
  if(seteuid(uid) == -1){
855
 
    ret = errno;
856
 
  }
857
 
  errno = old_errno;
858
 
  return ret;
859
 
}
860
 
 
861
 
/* Lower privileges permanently */
862
 
__attribute__((warn_unused_result))
863
 
int lower_privileges_permanently(void){
864
 
  int old_errno = errno;
865
 
  int ret = 0;
866
 
  if(setuid(uid) == -1){
867
 
    ret = errno;
868
 
  }
869
 
  errno = old_errno;
870
 
  return ret;
871
 
}
872
 
 
873
1033
/* Helper function to add_local_route() and delete_local_route() */
874
1034
__attribute__((nonnull, warn_unused_result))
875
1035
static bool add_delete_local_route(const bool add,
914
1074
      ret = setgid(0);
915
1075
      if(ret == -1){
916
1076
        perror_plus("setgid");
 
1077
        close(devnull);
917
1078
        _exit(EX_NOPERM);
918
1079
      }
919
1080
      /* Reset supplementary groups */
921
1082
      ret = setgroups(0, NULL);
922
1083
      if(ret == -1){
923
1084
        perror_plus("setgroups");
 
1085
        close(devnull);
924
1086
        _exit(EX_NOPERM);
925
1087
      }
926
1088
    }
927
1089
    ret = dup2(devnull, STDIN_FILENO);
928
1090
    if(ret == -1){
929
1091
      perror_plus("dup2(devnull, STDIN_FILENO)");
 
1092
      close(devnull);
930
1093
      _exit(EX_OSERR);
931
1094
    }
932
1095
    ret = close(devnull);
933
1096
    if(ret == -1){
934
1097
      perror_plus("close");
935
 
      _exit(EX_OSERR);
936
1098
    }
937
1099
    ret = dup2(STDERR_FILENO, STDOUT_FILENO);
938
1100
    if(ret == -1){
973
1135
  }
974
1136
  if(pid == -1){
975
1137
    perror_plus("fork");
 
1138
    close(devnull);
976
1139
    return false;
977
1140
  }
 
1141
  ret = close(devnull);
 
1142
  if(ret == -1){
 
1143
    perror_plus("close");
 
1144
  }
978
1145
  int status;
979
1146
  pid_t pret = -1;
980
1147
  errno = 0;
1655
1822
      perror_plus("ioctl SIOCGIFFLAGS");
1656
1823
      errno = old_errno;
1657
1824
    }
 
1825
    if((close(s) == -1) and debug){
 
1826
      old_errno = errno;
 
1827
      perror_plus("close");
 
1828
      errno = old_errno;
 
1829
    }
1658
1830
    return false;
1659
1831
  }
 
1832
  if((close(s) == -1) and debug){
 
1833
    old_errno = errno;
 
1834
    perror_plus("close");
 
1835
    errno = old_errno;
 
1836
  }
1660
1837
  return true;
1661
1838
}
1662
1839
 
1923
2100
      return;
1924
2101
    }
1925
2102
  }
 
2103
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
 
2104
  if(devnull == -1){
 
2105
    perror_plus("open(\"/dev/null\", O_RDONLY)");
 
2106
    return;
 
2107
  }
1926
2108
  int numhooks = scandirat(hookdir_fd, ".", &direntries,
1927
2109
                           runnable_hook, alphasort);
1928
2110
  if(numhooks == -1){
1929
2111
    perror_plus("scandir");
 
2112
    close(devnull);
1930
2113
    return;
1931
2114
  }
1932
2115
  struct dirent *direntry;
1933
2116
  int ret;
1934
 
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
1935
 
  if(devnull == -1){
1936
 
    perror_plus("open(\"/dev/null\", O_RDONLY)");
1937
 
    return;
1938
 
  }
1939
2117
  for(int i = 0; i < numhooks; i++){
1940
2118
    direntry = direntries[i];
1941
2119
    if(debug){
2290
2468
 
2291
2469
int main(int argc, char *argv[]){
2292
2470
  mandos_context mc = { .server = NULL, .dh_bits = 0,
 
2471
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2472
                        .priority = "SECURE128:!CTYPE-X.509"
 
2473
                        ":+CTYPE-RAWPK:!RSA:!VERS-ALL:+VERS-TLS1.3"
 
2474
                        ":%PROFILE_ULTRA",
 
2475
#elif GNUTLS_VERSION_NUMBER < 0x030600
2293
2476
                        .priority = "SECURE256:!CTYPE-X.509"
2294
2477
                        ":+CTYPE-OPENPGP:!RSA:+SIGN-DSA-SHA256",
 
2478
#else
 
2479
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
 
2480
#endif
2295
2481
                        .current_server = NULL, .interfaces = NULL,
2296
2482
                        .interfaces_size = 0 };
2297
2483
  AvahiSServiceBrowser *sb = NULL;
2308
2494
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
2309
2495
  const char *seckey = PATHDIR "/" SECKEY;
2310
2496
  const char *pubkey = PATHDIR "/" PUBKEY;
 
2497
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2498
  const char *tls_privkey = PATHDIR "/" TLS_PRIVKEY;
 
2499
  const char *tls_pubkey = PATHDIR "/" TLS_PUBKEY;
 
2500
#endif
2311
2501
  const char *dh_params_file = NULL;
2312
2502
  char *interfaces_hooks = NULL;
2313
2503
  
2361
2551
      { .name = "pubkey", .key = 'p',
2362
2552
        .arg = "FILE",
2363
2553
        .doc = "OpenPGP public key file base name",
2364
 
        .group = 2 },
 
2554
        .group = 1 },
 
2555
      { .name = "tls-privkey", .key = 't',
 
2556
        .arg = "FILE",
 
2557
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2558
        .doc = "TLS private key file base name",
 
2559
#else
 
2560
        .doc = "Dummy; ignored (requires GnuTLS 3.6.6)",
 
2561
#endif
 
2562
        .group = 1 },
 
2563
      { .name = "tls-pubkey", .key = 'T',
 
2564
        .arg = "FILE",
 
2565
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2566
        .doc = "TLS public key file base name",
 
2567
#else
 
2568
        .doc = "Dummy; ignored (requires GnuTLS 3.6.6)",
 
2569
#endif
 
2570
        .group = 1 },
2365
2571
      { .name = "dh-bits", .key = 129,
2366
2572
        .arg = "BITS",
2367
2573
        .doc = "Bit length of the prime number used in the"
2423
2629
      case 'p':                 /* --pubkey */
2424
2630
        pubkey = arg;
2425
2631
        break;
 
2632
      case 't':                 /* --tls-privkey */
 
2633
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2634
        tls_privkey = arg;
 
2635
#endif
 
2636
        break;
 
2637
      case 'T':                 /* --tls-pubkey */
 
2638
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2639
        tls_pubkey = arg;
 
2640
#endif
 
2641
        break;
2426
2642
      case 129:                 /* --dh-bits */
2427
2643
        errno = 0;
2428
2644
        tmpmax = strtoimax(arg, &tmp, 10);
2463
2679
        argp_state_help(state, state->out_stream,
2464
2680
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
2465
2681
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
 
2682
        __builtin_unreachable();
2466
2683
      case -3:                  /* --usage */
2467
2684
        argp_state_help(state, state->out_stream,
2468
2685
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
 
2686
        __builtin_unreachable();
2469
2687
      case 'V':                 /* --version */
2470
2688
        fprintf_plus(state->out_stream, "%s\n", argp_program_version);
2471
2689
        exit(argp_err_exit_status);
2782
3000
    goto end;
2783
3001
  }
2784
3002
  
 
3003
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
3004
  ret = init_gnutls_global(tls_pubkey, tls_privkey, dh_params_file, &mc);
 
3005
#elif GNUTLS_VERSION_NUMBER < 0x030600
2785
3006
  ret = init_gnutls_global(pubkey, seckey, dh_params_file, &mc);
 
3007
#else
 
3008
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
 
3009
#endif
2786
3010
  if(ret == -1){
2787
3011
    fprintf_plus(stderr, "init_gnutls_global failed\n");
2788
3012
    exitcode = EX_UNAVAILABLE;
3061
3285
                                                | O_PATH));
3062
3286
    if(dir_fd == -1){
3063
3287
      perror_plus("open");
 
3288
      return;
3064
3289
    }
3065
3290
    int numentries = scandirat(dir_fd, ".", &direntries,
3066
3291
                               notdotentries, alphasort);
3083
3308
            clean_dir_at(dir_fd, direntries[i]->d_name, level+1);
3084
3309
            dret = 0;
3085
3310
          }
3086
 
          if(dret == -1){
 
3311
          if((dret == -1) and (errno != ENOENT)){
3087
3312
            fprintf_plus(stderr, "unlink(\"%s/%s\"): %s\n", dirname,
3088
3313
                         direntries[i]->d_name, strerror(errno));
3089
3314
          }
3093
3318
      
3094
3319
      /* need to clean even if 0 because man page doesn't specify */
3095
3320
      free(direntries);
3096
 
      if(numentries == -1){
3097
 
        perror_plus("scandirat");
3098
 
      }
3099
3321
      dret = unlinkat(base, dirname, AT_REMOVEDIR);
3100
3322
      if(dret == -1 and errno != ENOENT){
3101
3323
        perror_plus("rmdir");