/mandos/release

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

« back to all changes in this revision

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

  • Committer: Teddy Hogeborn
  • Date: 2019-07-29 16:35:53 UTC
  • mto: This revision was merged to the branch mainline in revision 384.
  • Revision ID: teddy@recompile.se-20190729163553-1i442i2cbx64c537
Make tests and man page examples match

Make the tests test_manual_page_example[1-5] match exactly what is
written in the manual page, and add comments to manual page as
reminders to keep tests and manual page examples in sync.

* mandos-ctl (Test_commands_from_options.test_manual_page_example_1):
  Remove "--verbose" option, since the manual does not have it as the
  first example, and change assertion to match.
* mandos-ctl.xml (EXAMPLE): Add comments to all examples documenting
  which test function they correspond to.  Also remove unnecessary
  quotes from option arguments in fourth example, and clarify language
  slightly in fifth example.

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-2016 Teddy Hogeborn
13
 
 * Copyright © 2008-2016 Björn Påhlsson
14
 
 * 
15
 
 * This program is free software: you can redistribute it and/or
16
 
 * modify it under the terms of the GNU General Public License as
17
 
 * published by the Free Software Foundation, either version 3 of the
18
 
 * License, or (at your option) any later version.
19
 
 * 
20
 
 * This program is distributed in the hope that it will be useful, but
 
12
 * Copyright © 2008-2019 Teddy Hogeborn
 
13
 * Copyright © 2008-2019 Björn Påhlsson
 
14
 * 
 
15
 * This file is part of Mandos.
 
16
 * 
 
17
 * Mandos is free software: you can redistribute it and/or modify it
 
18
 * under the terms of the GNU General Public License as published by
 
19
 * the Free Software Foundation, either version 3 of the License, or
 
20
 * (at your option) any later version.
 
21
 * 
 
22
 * Mandos is distributed in the hope that it will be useful, but
21
23
 * WITHOUT ANY WARRANTY; without even the implied warranty of
22
24
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23
25
 * General Public License for more details.
24
26
 * 
25
27
 * You should have received a copy of the GNU General Public License
26
 
 * along with this program.  If not, see
27
 
 * <http://www.gnu.org/licenses/>.
 
28
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
28
29
 * 
29
30
 * Contact the authors at <mandos@recompile.se>.
30
31
 */
122
123
                                   gnutls_*
123
124
                                   init_gnutls_session(),
124
125
                                   GNUTLS_* */
 
126
#if GNUTLS_VERSION_NUMBER < 0x030600
125
127
#include <gnutls/openpgp.h>
126
128
                         /* gnutls_certificate_set_openpgp_key_file(),
127
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
128
135
 
129
136
/* GPGME */
130
137
#include <gpgme.h>              /* All GPGME types, constants and
138
145
#define PATHDIR "/conf/conf.d/mandos"
139
146
#define SECKEY "seckey.txt"
140
147
#define PUBKEY "pubkey.txt"
 
148
#define TLS_PRIVKEY "tls-privkey.pem"
 
149
#define TLS_PUBKEY "tls-pubkey.pem"
141
150
#define HOOKDIR "/lib/mandos/network-hooks.d"
142
151
 
143
152
bool debug = false;
271
280
  return true;
272
281
}
273
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
 
274
335
/* 
275
336
 * Initialize GPGME.
276
337
 */
296
357
      return false;
297
358
    }
298
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
 
299
410
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
300
411
    if(rc != GPG_ERR_NO_ERROR){
301
412
      fprintf_plus(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
309
420
                   gpgme_strsource(rc), gpgme_strerror(rc));
310
421
      return false;
311
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
    }
312
498
    
313
499
    ret = close(fd);
314
500
    if(ret == -1){
355
541
  /* Create new GPGME "context" */
356
542
  rc = gpgme_new(&(mc->ctx));
357
543
  if(rc != GPG_ERR_NO_ERROR){
358
 
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
359
 
                 "bad gpgme_new: %s: %s\n", gpgme_strsource(rc),
360
 
                 gpgme_strerror(rc));
 
544
    fprintf_plus(stderr, "bad gpgme_new: %s: %s\n",
 
545
                 gpgme_strsource(rc), gpgme_strerror(rc));
361
546
    return false;
362
547
  }
363
548
  
399
584
  /* Create new empty GPGME data buffer for the plaintext */
400
585
  rc = gpgme_data_new(&dh_plain);
401
586
  if(rc != GPG_ERR_NO_ERROR){
402
 
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
403
 
                 "bad gpgme_data_new: %s: %s\n",
 
587
    fprintf_plus(stderr, "bad gpgme_data_new: %s: %s\n",
404
588
                 gpgme_strsource(rc), gpgme_strerror(rc));
405
589
    gpgme_data_release(dh_crypto);
406
590
    return -1;
419
603
      if(result == NULL){
420
604
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
421
605
      } else {
422
 
        fprintf_plus(stderr, "Unsupported algorithm: %s\n",
423
 
                     result->unsupported_algorithm);
424
 
        fprintf_plus(stderr, "Wrong key usage: %u\n",
425
 
                     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");
426
612
        if(result->file_name != NULL){
427
613
          fprintf_plus(stderr, "File name: %s\n", result->file_name);
428
614
        }
429
 
        gpgme_recipient_t recipient;
430
 
        recipient = result->recipients;
431
 
        while(recipient != NULL){
 
615
 
 
616
        for(gpgme_recipient_t r = result->recipients; r != NULL;
 
617
            r = r->next){
432
618
          fprintf_plus(stderr, "Public key algorithm: %s\n",
433
 
                       gpgme_pubkey_algo_name
434
 
                       (recipient->pubkey_algo));
435
 
          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);
436
621
          fprintf_plus(stderr, "Secret key available: %s\n",
437
 
                       recipient->status == GPG_ERR_NO_SECKEY
438
 
                       ? "No" : "Yes");
439
 
          recipient = recipient->next;
 
622
                       r->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
440
623
        }
441
624
      }
442
625
    }
524
707
                              const char *dhparamsfilename,
525
708
                              mandos_context *mc){
526
709
  int ret;
527
 
  unsigned int uret;
528
710
  
529
711
  if(debug){
530
712
    fprintf_plus(stderr, "Initializing GnuTLS\n");
547
729
  }
548
730
  
549
731
  if(debug){
550
 
    fprintf_plus(stderr, "Attempting to use OpenPGP public key %s and"
551
 
                 " 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",
552
734
                 pubkeyfilename,
553
735
                 seckeyfilename);
554
736
  }
555
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
556
751
  ret = gnutls_certificate_set_openpgp_key_file
557
752
    (mc->cred, pubkeyfilename, seckeyfilename,
558
753
     GNUTLS_OPENPGP_FMT_BASE64);
 
754
#else
 
755
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
 
756
#endif
559
757
  if(ret != GNUTLS_E_SUCCESS){
560
758
    fprintf_plus(stderr,
561
 
                 "Error[%d] while reading the OpenPGP key pair ('%s',"
 
759
                 "Error[%d] while reading the key pair ('%s',"
562
760
                 " '%s')\n", ret, pubkeyfilename, seckeyfilename);
563
761
    fprintf_plus(stderr, "The GnuTLS error is: %s\n",
564
762
                 safer_gnutls_strerror(ret));
612
810
        }
613
811
        params.size += (unsigned int)bytes_read;
614
812
      }
 
813
      ret = close(dhpfile);
 
814
      if(ret == -1){
 
815
        perror_plus("close");
 
816
      }
615
817
      if(params.data == NULL){
616
818
        dhparamsfilename = NULL;
617
819
      }
626
828
                     safer_gnutls_strerror(ret));
627
829
        dhparamsfilename = NULL;
628
830
      }
 
831
      free(params.data);
629
832
    } while(false);
630
833
  }
631
834
  if(dhparamsfilename == NULL){
632
835
    if(mc->dh_bits == 0){
 
836
#if GNUTLS_VERSION_NUMBER < 0x030600
633
837
      /* Find out the optimal number of DH bits */
634
838
      /* Try to read the private key file */
635
839
      gnutls_datum_t buffer = { .data = NULL, .size = 0 };
715
919
          }
716
920
        }
717
921
      }
718
 
      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);
719
923
      if(uret != 0){
720
924
        mc->dh_bits = uret;
721
925
        if(debug){
733
937
                     safer_gnutls_strerror(ret));
734
938
        goto globalfail;
735
939
      }
736
 
    } else if(debug){
737
 
      fprintf_plus(stderr, "DH bits explicitly set to %u\n",
738
 
                   mc->dh_bits);
739
 
    }
740
 
    ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
741
 
    if(ret != GNUTLS_E_SUCCESS){
742
 
      fprintf_plus(stderr, "Error in GnuTLS prime generation (%u"
743
 
                   " bits): %s\n", mc->dh_bits,
744
 
                   safer_gnutls_strerror(ret));
745
 
      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);
746
954
    }
747
955
  }
748
 
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
749
956
  
750
957
  return 0;
751
958
  
762
969
  int ret;
763
970
  /* GnuTLS session creation */
764
971
  do {
765
 
    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
                                ));
766
980
    if(quit_now){
767
981
      return -1;
768
982
    }
816
1030
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
817
1031
                      __attribute__((unused)) const char *txt){}
818
1032
 
819
 
/* Set effective uid to 0, return errno */
820
 
__attribute__((warn_unused_result))
821
 
int raise_privileges(void){
822
 
  int old_errno = errno;
823
 
  int ret = 0;
824
 
  if(seteuid(0) == -1){
825
 
    ret = errno;
826
 
  }
827
 
  errno = old_errno;
828
 
  return ret;
829
 
}
830
 
 
831
 
/* Set effective and real user ID to 0.  Return errno. */
832
 
__attribute__((warn_unused_result))
833
 
int raise_privileges_permanently(void){
834
 
  int old_errno = errno;
835
 
  int ret = raise_privileges();
836
 
  if(ret != 0){
837
 
    errno = old_errno;
838
 
    return ret;
839
 
  }
840
 
  if(setuid(0) == -1){
841
 
    ret = errno;
842
 
  }
843
 
  errno = old_errno;
844
 
  return ret;
845
 
}
846
 
 
847
 
/* Set effective user ID to unprivileged saved user ID */
848
 
__attribute__((warn_unused_result))
849
 
int lower_privileges(void){
850
 
  int old_errno = errno;
851
 
  int ret = 0;
852
 
  if(seteuid(uid) == -1){
853
 
    ret = errno;
854
 
  }
855
 
  errno = old_errno;
856
 
  return ret;
857
 
}
858
 
 
859
 
/* Lower privileges permanently */
860
 
__attribute__((warn_unused_result))
861
 
int lower_privileges_permanently(void){
862
 
  int old_errno = errno;
863
 
  int ret = 0;
864
 
  if(setuid(uid) == -1){
865
 
    ret = errno;
866
 
  }
867
 
  errno = old_errno;
868
 
  return ret;
869
 
}
870
 
 
871
1033
/* Helper function to add_local_route() and delete_local_route() */
872
1034
__attribute__((nonnull, warn_unused_result))
873
1035
static bool add_delete_local_route(const bool add,
1078
1240
    bool match = false;
1079
1241
    {
1080
1242
      char *interface = NULL;
1081
 
      while((interface=argz_next(mc->interfaces, mc->interfaces_size,
1082
 
                                 interface))){
 
1243
      while((interface = argz_next(mc->interfaces,
 
1244
                                   mc->interfaces_size,
 
1245
                                   interface))){
1083
1246
        if(if_nametoindex(interface) == (unsigned int)if_index){
1084
1247
          match = true;
1085
1248
          break;
1492
1655
  return retval;
1493
1656
}
1494
1657
 
1495
 
__attribute__((nonnull))
1496
1658
static void resolve_callback(AvahiSServiceResolver *r,
1497
1659
                             AvahiIfIndex interface,
1498
1660
                             AvahiProtocol proto,
1653
1815
      perror_plus("ioctl SIOCGIFFLAGS");
1654
1816
      errno = old_errno;
1655
1817
    }
 
1818
    if((close(s) == -1) and debug){
 
1819
      old_errno = errno;
 
1820
      perror_plus("close");
 
1821
      errno = old_errno;
 
1822
    }
1656
1823
    return false;
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 true;
1659
1831
}
1660
1832
 
1921
2093
      return;
1922
2094
    }
1923
2095
  }
 
2096
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
 
2097
  if(devnull == -1){
 
2098
    perror_plus("open(\"/dev/null\", O_RDONLY)");
 
2099
    return;
 
2100
  }
1924
2101
  int numhooks = scandirat(hookdir_fd, ".", &direntries,
1925
2102
                           runnable_hook, alphasort);
1926
2103
  if(numhooks == -1){
1927
2104
    perror_plus("scandir");
 
2105
    close(devnull);
1928
2106
    return;
1929
2107
  }
1930
2108
  struct dirent *direntry;
1931
2109
  int ret;
1932
 
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
1933
 
  if(devnull == -1){
1934
 
    perror_plus("open(\"/dev/null\", O_RDONLY)");
1935
 
    return;
1936
 
  }
1937
2110
  for(int i = 0; i < numhooks; i++){
1938
2111
    direntry = direntries[i];
1939
2112
    if(debug){
2195
2368
  
2196
2369
  /* Sleep checking until interface is running.
2197
2370
     Check every 0.25s, up to total time of delay */
2198
 
  for(int i=0; i < delay * 4; i++){
 
2371
  for(int i = 0; i < delay * 4; i++){
2199
2372
    if(interface_is_running(interface)){
2200
2373
      break;
2201
2374
    }
2288
2461
 
2289
2462
int main(int argc, char *argv[]){
2290
2463
  mandos_context mc = { .server = NULL, .dh_bits = 0,
 
2464
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2465
                        .priority = "SECURE128:!CTYPE-X.509"
 
2466
                        ":+CTYPE-RAWPK:!RSA:!VERS-ALL:+VERS-TLS1.3"
 
2467
                        ":%PROFILE_ULTRA",
 
2468
#elif GNUTLS_VERSION_NUMBER < 0x030600
2291
2469
                        .priority = "SECURE256:!CTYPE-X.509"
2292
2470
                        ":+CTYPE-OPENPGP:!RSA:+SIGN-DSA-SHA256",
 
2471
#else
 
2472
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
 
2473
#endif
2293
2474
                        .current_server = NULL, .interfaces = NULL,
2294
2475
                        .interfaces_size = 0 };
2295
2476
  AvahiSServiceBrowser *sb = NULL;
2306
2487
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
2307
2488
  const char *seckey = PATHDIR "/" SECKEY;
2308
2489
  const char *pubkey = PATHDIR "/" PUBKEY;
 
2490
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2491
  const char *tls_privkey = PATHDIR "/" TLS_PRIVKEY;
 
2492
  const char *tls_pubkey = PATHDIR "/" TLS_PUBKEY;
 
2493
#endif
2309
2494
  const char *dh_params_file = NULL;
2310
2495
  char *interfaces_hooks = NULL;
2311
2496
  
2359
2544
      { .name = "pubkey", .key = 'p',
2360
2545
        .arg = "FILE",
2361
2546
        .doc = "OpenPGP public key file base name",
2362
 
        .group = 2 },
 
2547
        .group = 1 },
 
2548
      { .name = "tls-privkey", .key = 't',
 
2549
        .arg = "FILE",
 
2550
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2551
        .doc = "TLS private key file base name",
 
2552
#else
 
2553
        .doc = "Dummy; ignored (requires GnuTLS 3.6.6)",
 
2554
#endif
 
2555
        .group = 1 },
 
2556
      { .name = "tls-pubkey", .key = 'T',
 
2557
        .arg = "FILE",
 
2558
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2559
        .doc = "TLS public key file base name",
 
2560
#else
 
2561
        .doc = "Dummy; ignored (requires GnuTLS 3.6.6)",
 
2562
#endif
 
2563
        .group = 1 },
2363
2564
      { .name = "dh-bits", .key = 129,
2364
2565
        .arg = "BITS",
2365
2566
        .doc = "Bit length of the prime number used in the"
2421
2622
      case 'p':                 /* --pubkey */
2422
2623
        pubkey = arg;
2423
2624
        break;
 
2625
      case 't':                 /* --tls-privkey */
 
2626
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2627
        tls_privkey = arg;
 
2628
#endif
 
2629
        break;
 
2630
      case 'T':                 /* --tls-pubkey */
 
2631
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2632
        tls_pubkey = arg;
 
2633
#endif
 
2634
        break;
2424
2635
      case 129:                 /* --dh-bits */
2425
2636
        errno = 0;
2426
2637
        tmpmax = strtoimax(arg, &tmp, 10);
2461
2672
        argp_state_help(state, state->out_stream,
2462
2673
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
2463
2674
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
 
2675
        __builtin_unreachable();
2464
2676
      case -3:                  /* --usage */
2465
2677
        argp_state_help(state, state->out_stream,
2466
2678
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
 
2679
        __builtin_unreachable();
2467
2680
      case 'V':                 /* --version */
2468
2681
        fprintf_plus(state->out_stream, "%s\n", argp_program_version);
2469
2682
        exit(argp_err_exit_status);
2780
2993
    goto end;
2781
2994
  }
2782
2995
  
 
2996
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2997
  ret = init_gnutls_global(tls_pubkey, tls_privkey, dh_params_file, &mc);
 
2998
#elif GNUTLS_VERSION_NUMBER < 0x030600
2783
2999
  ret = init_gnutls_global(pubkey, seckey, dh_params_file, &mc);
 
3000
#else
 
3001
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
 
3002
#endif
2784
3003
  if(ret == -1){
2785
3004
    fprintf_plus(stderr, "init_gnutls_global failed\n");
2786
3005
    exitcode = EX_UNAVAILABLE;
3022
3241
      /* Take down the network interfaces which were brought up */
3023
3242
      {
3024
3243
        char *interface = NULL;
3025
 
        while((interface=argz_next(interfaces_to_take_down,
3026
 
                                   interfaces_to_take_down_size,
3027
 
                                   interface))){
 
3244
        while((interface = argz_next(interfaces_to_take_down,
 
3245
                                     interfaces_to_take_down_size,
 
3246
                                     interface))){
3028
3247
          ret = take_down_interface(interface);
3029
3248
          if(ret != 0){
3030
3249
            errno = ret;
3059
3278
                                                | O_PATH));
3060
3279
    if(dir_fd == -1){
3061
3280
      perror_plus("open");
 
3281
      return;
3062
3282
    }
3063
3283
    int numentries = scandirat(dir_fd, ".", &direntries,
3064
3284
                               notdotentries, alphasort);
3081
3301
            clean_dir_at(dir_fd, direntries[i]->d_name, level+1);
3082
3302
            dret = 0;
3083
3303
          }
3084
 
          if(dret == -1){
 
3304
          if((dret == -1) and (errno != ENOENT)){
3085
3305
            fprintf_plus(stderr, "unlink(\"%s/%s\"): %s\n", dirname,
3086
3306
                         direntries[i]->d_name, strerror(errno));
3087
3307
          }
3091
3311
      
3092
3312
      /* need to clean even if 0 because man page doesn't specify */
3093
3313
      free(direntries);
3094
 
      if(numentries == -1){
3095
 
        perror_plus("scandirat");
3096
 
      }
3097
3314
      dret = unlinkat(base, dirname, AT_REMOVEDIR);
3098
3315
      if(dret == -1 and errno != ENOENT){
3099
3316
        perror_plus("rmdir");