/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-12-03 20:30:45 UTC
  • Revision ID: teddy@recompile.se-20201203203045-iqd6nq9y5nwalh1x
Minor fix of a test function

In dracut-module/password-agent, the test function
test_send_password_to_socket_EMSGSIZE() (which tests that the
send_password_to_socket() task function aborts properly when getting
EMSGSIZE when writing to the password socket), part of the test code
is supposed to find a message size which definitely does trigger
EMSGSIZE when send()ing to a socket.  Without a "break" in the proper
place, however, the size given is always exactly 1024 bytes too large.

This is very probably not a problem, since a too large message will
still be too large if it is increased by 1024 bytes, and send(2) in
practice checks the size before reading the buffer.  The biggest issue
would be if some version of send(2) would try to look at the last 1024
bytes of the message buffer before checking the message size; this
would then lead to a buffer over-read when running this test function.
(But even then there would be no security implications since the tests
are not run in the normal operation of the program.)

* dracut-module/password-agent.c
  (test_send_password_to_socket_EMSGSIZE): Break out early when ssret
  < 0 and errno == EMSGSIZE; don't allow loop to increase message_size
  again.

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-2020 Teddy Hogeborn
 
13
 * Copyright © 2008-2020 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
 */
47
48
                                   strtof(), abort() */
48
49
#include <stdbool.h>            /* bool, false, true */
49
50
#include <string.h>             /* strcmp(), strlen(), strerror(),
50
 
                                   asprintf(), strncpy() */
 
51
                                   asprintf(), strncpy(), strsignal()
 
52
                                */
51
53
#include <sys/ioctl.h>          /* ioctl */
52
54
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
53
55
                                   sockaddr_in6, PF_INET6,
121
123
                                   gnutls_*
122
124
                                   init_gnutls_session(),
123
125
                                   GNUTLS_* */
 
126
#if GNUTLS_VERSION_NUMBER < 0x030600
124
127
#include <gnutls/openpgp.h>
125
128
                         /* gnutls_certificate_set_openpgp_key_file(),
126
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
127
135
 
128
136
/* GPGME */
129
137
#include <gpgme.h>              /* All GPGME types, constants and
137
145
#define PATHDIR "/conf/conf.d/mandos"
138
146
#define SECKEY "seckey.txt"
139
147
#define PUBKEY "pubkey.txt"
 
148
#define TLS_PRIVKEY "tls-privkey.pem"
 
149
#define TLS_PUBKEY "tls-pubkey.pem"
140
150
#define HOOKDIR "/lib/mandos/network-hooks.d"
141
151
 
142
152
bool debug = false;
270
280
  return true;
271
281
}
272
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
 
273
335
/* 
274
336
 * Initialize GPGME.
275
337
 */
295
357
      return false;
296
358
    }
297
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
      if(clock_settime(CLOCK_REALTIME, &keystat.st_mtim) != 0){
 
400
        perror_plus("clock_settime");
 
401
      }
 
402
      ret = lower_privileges();
 
403
      if(ret != 0){
 
404
        errno = ret;
 
405
        perror_plus("Failed to lower privileges");
 
406
      }
 
407
    } while(false);
 
408
 
298
409
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
299
410
    if(rc != GPG_ERR_NO_ERROR){
300
411
      fprintf_plus(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
308
419
                   gpgme_strsource(rc), gpgme_strerror(rc));
309
420
      return false;
310
421
    }
 
422
    {
 
423
      gpgme_import_result_t import_result
 
424
        = gpgme_op_import_result(mc->ctx);
 
425
      if((import_result->imported < 1
 
426
          or import_result->not_imported > 0)
 
427
         and import_result->unchanged == 0){
 
428
        fprintf_plus(stderr, "bad gpgme_op_import_results:\n");
 
429
        fprintf_plus(stderr,
 
430
                     "The total number of considered keys: %d\n",
 
431
                     import_result->considered);
 
432
        fprintf_plus(stderr,
 
433
                     "The number of keys without user ID: %d\n",
 
434
                     import_result->no_user_id);
 
435
        fprintf_plus(stderr,
 
436
                     "The total number of imported keys: %d\n",
 
437
                     import_result->imported);
 
438
        fprintf_plus(stderr, "The number of imported RSA keys: %d\n",
 
439
                     import_result->imported_rsa);
 
440
        fprintf_plus(stderr, "The number of unchanged keys: %d\n",
 
441
                     import_result->unchanged);
 
442
        fprintf_plus(stderr, "The number of new user IDs: %d\n",
 
443
                     import_result->new_user_ids);
 
444
        fprintf_plus(stderr, "The number of new sub keys: %d\n",
 
445
                     import_result->new_sub_keys);
 
446
        fprintf_plus(stderr, "The number of new signatures: %d\n",
 
447
                     import_result->new_signatures);
 
448
        fprintf_plus(stderr, "The number of new revocations: %d\n",
 
449
                     import_result->new_revocations);
 
450
        fprintf_plus(stderr,
 
451
                     "The total number of secret keys read: %d\n",
 
452
                     import_result->secret_read);
 
453
        fprintf_plus(stderr,
 
454
                     "The number of imported secret keys: %d\n",
 
455
                     import_result->secret_imported);
 
456
        fprintf_plus(stderr,
 
457
                     "The number of unchanged secret keys: %d\n",
 
458
                     import_result->secret_unchanged);
 
459
        fprintf_plus(stderr, "The number of keys not imported: %d\n",
 
460
                     import_result->not_imported);
 
461
        for(gpgme_import_status_t import_status
 
462
              = import_result->imports;
 
463
            import_status != NULL;
 
464
            import_status = import_status->next){
 
465
          fprintf_plus(stderr, "Import status for key: %s\n",
 
466
                       import_status->fpr);
 
467
          if(import_status->result != GPG_ERR_NO_ERROR){
 
468
            fprintf_plus(stderr, "Import result: %s: %s\n",
 
469
                         gpgme_strsource(import_status->result),
 
470
                         gpgme_strerror(import_status->result));
 
471
          }
 
472
          fprintf_plus(stderr, "Key status:\n");
 
473
          fprintf_plus(stderr,
 
474
                       import_status->status & GPGME_IMPORT_NEW
 
475
                       ? "The key was new.\n"
 
476
                       : "The key was not new.\n");
 
477
          fprintf_plus(stderr,
 
478
                       import_status->status & GPGME_IMPORT_UID
 
479
                       ? "The key contained new user IDs.\n"
 
480
                       : "The key did not contain new user IDs.\n");
 
481
          fprintf_plus(stderr,
 
482
                       import_status->status & GPGME_IMPORT_SIG
 
483
                       ? "The key contained new signatures.\n"
 
484
                       : "The key did not contain new signatures.\n");
 
485
          fprintf_plus(stderr,
 
486
                       import_status->status & GPGME_IMPORT_SUBKEY
 
487
                       ? "The key contained new sub keys.\n"
 
488
                       : "The key did not contain new sub keys.\n");
 
489
          fprintf_plus(stderr,
 
490
                       import_status->status & GPGME_IMPORT_SECRET
 
491
                       ? "The key contained a secret key.\n"
 
492
                       : "The key did not contain a secret key.\n");
 
493
        }
 
494
        return false;
 
495
      }
 
496
    }
311
497
    
312
498
    ret = close(fd);
313
499
    if(ret == -1){
354
540
  /* Create new GPGME "context" */
355
541
  rc = gpgme_new(&(mc->ctx));
356
542
  if(rc != GPG_ERR_NO_ERROR){
357
 
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
358
 
                 "bad gpgme_new: %s: %s\n", gpgme_strsource(rc),
359
 
                 gpgme_strerror(rc));
 
543
    fprintf_plus(stderr, "bad gpgme_new: %s: %s\n",
 
544
                 gpgme_strsource(rc), gpgme_strerror(rc));
360
545
    return false;
361
546
  }
362
547
  
398
583
  /* Create new empty GPGME data buffer for the plaintext */
399
584
  rc = gpgme_data_new(&dh_plain);
400
585
  if(rc != GPG_ERR_NO_ERROR){
401
 
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
402
 
                 "bad gpgme_data_new: %s: %s\n",
 
586
    fprintf_plus(stderr, "bad gpgme_data_new: %s: %s\n",
403
587
                 gpgme_strsource(rc), gpgme_strerror(rc));
404
588
    gpgme_data_release(dh_crypto);
405
589
    return -1;
418
602
      if(result == NULL){
419
603
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
420
604
      } else {
421
 
        fprintf_plus(stderr, "Unsupported algorithm: %s\n",
422
 
                     result->unsupported_algorithm);
423
 
        fprintf_plus(stderr, "Wrong key usage: %u\n",
424
 
                     result->wrong_key_usage);
 
605
        if(result->unsupported_algorithm != NULL) {
 
606
          fprintf_plus(stderr, "Unsupported algorithm: %s\n",
 
607
                       result->unsupported_algorithm);
 
608
        }
 
609
        fprintf_plus(stderr, "Wrong key usage: %s\n",
 
610
                     result->wrong_key_usage ? "Yes" : "No");
425
611
        if(result->file_name != NULL){
426
612
          fprintf_plus(stderr, "File name: %s\n", result->file_name);
427
613
        }
428
 
        gpgme_recipient_t recipient;
429
 
        recipient = result->recipients;
430
 
        while(recipient != NULL){
 
614
 
 
615
        for(gpgme_recipient_t r = result->recipients; r != NULL;
 
616
            r = r->next){
431
617
          fprintf_plus(stderr, "Public key algorithm: %s\n",
432
 
                       gpgme_pubkey_algo_name
433
 
                       (recipient->pubkey_algo));
434
 
          fprintf_plus(stderr, "Key ID: %s\n", recipient->keyid);
 
618
                       gpgme_pubkey_algo_name(r->pubkey_algo));
 
619
          fprintf_plus(stderr, "Key ID: %s\n", r->keyid);
435
620
          fprintf_plus(stderr, "Secret key available: %s\n",
436
 
                       recipient->status == GPG_ERR_NO_SECKEY
437
 
                       ? "No" : "Yes");
438
 
          recipient = recipient->next;
 
621
                       r->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
439
622
        }
440
623
      }
441
624
    }
523
706
                              const char *dhparamsfilename,
524
707
                              mandos_context *mc){
525
708
  int ret;
526
 
  unsigned int uret;
527
709
  
528
710
  if(debug){
529
711
    fprintf_plus(stderr, "Initializing GnuTLS\n");
546
728
  }
547
729
  
548
730
  if(debug){
549
 
    fprintf_plus(stderr, "Attempting to use OpenPGP public key %s and"
550
 
                 " secret key %s as GnuTLS credentials\n",
 
731
    fprintf_plus(stderr, "Attempting to use public key %s and"
 
732
                 " private key %s as GnuTLS credentials\n",
551
733
                 pubkeyfilename,
552
734
                 seckeyfilename);
553
735
  }
554
736
  
 
737
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
738
  ret = gnutls_certificate_set_rawpk_key_file
 
739
    (mc->cred, pubkeyfilename, seckeyfilename,
 
740
     GNUTLS_X509_FMT_PEM,       /* format */
 
741
     NULL,                      /* pass */
 
742
     /* key_usage */
 
743
     GNUTLS_KEY_DIGITAL_SIGNATURE | GNUTLS_KEY_KEY_ENCIPHERMENT,
 
744
     NULL,                      /* names */
 
745
     0,                         /* names_length */
 
746
     /* privkey_flags */
 
747
     GNUTLS_PKCS_PLAIN | GNUTLS_PKCS_NULL_PASSWORD,
 
748
     0);                        /* pkcs11_flags */
 
749
#elif GNUTLS_VERSION_NUMBER < 0x030600
555
750
  ret = gnutls_certificate_set_openpgp_key_file
556
751
    (mc->cred, pubkeyfilename, seckeyfilename,
557
752
     GNUTLS_OPENPGP_FMT_BASE64);
 
753
#else
 
754
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
 
755
#endif
558
756
  if(ret != GNUTLS_E_SUCCESS){
559
757
    fprintf_plus(stderr,
560
 
                 "Error[%d] while reading the OpenPGP key pair ('%s',"
 
758
                 "Error[%d] while reading the key pair ('%s',"
561
759
                 " '%s')\n", ret, pubkeyfilename, seckeyfilename);
562
760
    fprintf_plus(stderr, "The GnuTLS error is: %s\n",
563
761
                 safer_gnutls_strerror(ret));
611
809
        }
612
810
        params.size += (unsigned int)bytes_read;
613
811
      }
 
812
      ret = close(dhpfile);
 
813
      if(ret == -1){
 
814
        perror_plus("close");
 
815
      }
614
816
      if(params.data == NULL){
615
817
        dhparamsfilename = NULL;
616
818
      }
625
827
                     safer_gnutls_strerror(ret));
626
828
        dhparamsfilename = NULL;
627
829
      }
 
830
      free(params.data);
628
831
    } while(false);
629
832
  }
630
833
  if(dhparamsfilename == NULL){
631
834
    if(mc->dh_bits == 0){
 
835
#if GNUTLS_VERSION_NUMBER < 0x030600
632
836
      /* Find out the optimal number of DH bits */
633
837
      /* Try to read the private key file */
634
838
      gnutls_datum_t buffer = { .data = NULL, .size = 0 };
714
918
          }
715
919
        }
716
920
      }
717
 
      uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
 
921
      unsigned int uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
718
922
      if(uret != 0){
719
923
        mc->dh_bits = uret;
720
924
        if(debug){
732
936
                     safer_gnutls_strerror(ret));
733
937
        goto globalfail;
734
938
      }
735
 
    } else if(debug){
736
 
      fprintf_plus(stderr, "DH bits explicitly set to %u\n",
737
 
                   mc->dh_bits);
738
 
    }
739
 
    ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
740
 
    if(ret != GNUTLS_E_SUCCESS){
741
 
      fprintf_plus(stderr, "Error in GnuTLS prime generation (%u"
742
 
                   " bits): %s\n", mc->dh_bits,
743
 
                   safer_gnutls_strerror(ret));
744
 
      goto globalfail;
 
939
#endif
 
940
    } else {                    /* dh_bits != 0 */
 
941
      if(debug){
 
942
        fprintf_plus(stderr, "DH bits explicitly set to %u\n",
 
943
                     mc->dh_bits);
 
944
      }
 
945
      ret = gnutls_dh_params_generate2(mc->dh_params, mc->dh_bits);
 
946
      if(ret != GNUTLS_E_SUCCESS){
 
947
        fprintf_plus(stderr, "Error in GnuTLS prime generation (%u"
 
948
                     " bits): %s\n", mc->dh_bits,
 
949
                     safer_gnutls_strerror(ret));
 
950
        goto globalfail;
 
951
      }
 
952
      gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
745
953
    }
746
954
  }
747
 
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
748
955
  
749
956
  return 0;
750
957
  
761
968
  int ret;
762
969
  /* GnuTLS session creation */
763
970
  do {
764
 
    ret = gnutls_init(session, GNUTLS_SERVER);
 
971
    ret = gnutls_init(session, (GNUTLS_SERVER
 
972
#if GNUTLS_VERSION_NUMBER >= 0x030506
 
973
                                | GNUTLS_NO_TICKETS
 
974
#endif
 
975
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
976
                                | GNUTLS_ENABLE_RAWPK
 
977
#endif
 
978
                                ));
765
979
    if(quit_now){
766
980
      return -1;
767
981
    }
815
1029
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
816
1030
                      __attribute__((unused)) const char *txt){}
817
1031
 
818
 
/* Set effective uid to 0, return errno */
819
 
__attribute__((warn_unused_result))
820
 
int raise_privileges(void){
821
 
  int old_errno = errno;
822
 
  int ret = 0;
823
 
  if(seteuid(0) == -1){
824
 
    ret = errno;
825
 
  }
826
 
  errno = old_errno;
827
 
  return ret;
828
 
}
829
 
 
830
 
/* Set effective and real user ID to 0.  Return errno. */
831
 
__attribute__((warn_unused_result))
832
 
int raise_privileges_permanently(void){
833
 
  int old_errno = errno;
834
 
  int ret = raise_privileges();
835
 
  if(ret != 0){
836
 
    errno = old_errno;
837
 
    return ret;
838
 
  }
839
 
  if(setuid(0) == -1){
840
 
    ret = errno;
841
 
  }
842
 
  errno = old_errno;
843
 
  return ret;
844
 
}
845
 
 
846
 
/* Set effective user ID to unprivileged saved user ID */
847
 
__attribute__((warn_unused_result))
848
 
int lower_privileges(void){
849
 
  int old_errno = errno;
850
 
  int ret = 0;
851
 
  if(seteuid(uid) == -1){
852
 
    ret = errno;
853
 
  }
854
 
  errno = old_errno;
855
 
  return ret;
856
 
}
857
 
 
858
 
/* Lower privileges permanently */
859
 
__attribute__((warn_unused_result))
860
 
int lower_privileges_permanently(void){
861
 
  int old_errno = errno;
862
 
  int ret = 0;
863
 
  if(setuid(uid) == -1){
864
 
    ret = errno;
865
 
  }
866
 
  errno = old_errno;
867
 
  return ret;
868
 
}
869
 
 
870
1032
/* Helper function to add_local_route() and delete_local_route() */
871
1033
__attribute__((nonnull, warn_unused_result))
872
1034
static bool add_delete_local_route(const bool add,
911
1073
      ret = setgid(0);
912
1074
      if(ret == -1){
913
1075
        perror_plus("setgid");
 
1076
        close(devnull);
914
1077
        _exit(EX_NOPERM);
915
1078
      }
916
1079
      /* Reset supplementary groups */
918
1081
      ret = setgroups(0, NULL);
919
1082
      if(ret == -1){
920
1083
        perror_plus("setgroups");
 
1084
        close(devnull);
921
1085
        _exit(EX_NOPERM);
922
1086
      }
923
1087
    }
924
1088
    ret = dup2(devnull, STDIN_FILENO);
925
1089
    if(ret == -1){
926
1090
      perror_plus("dup2(devnull, STDIN_FILENO)");
 
1091
      close(devnull);
927
1092
      _exit(EX_OSERR);
928
1093
    }
929
1094
    ret = close(devnull);
930
1095
    if(ret == -1){
931
1096
      perror_plus("close");
932
 
      _exit(EX_OSERR);
933
1097
    }
934
1098
    ret = dup2(STDERR_FILENO, STDOUT_FILENO);
935
1099
    if(ret == -1){
970
1134
  }
971
1135
  if(pid == -1){
972
1136
    perror_plus("fork");
 
1137
    close(devnull);
973
1138
    return false;
974
1139
  }
 
1140
  ret = close(devnull);
 
1141
  if(ret == -1){
 
1142
    perror_plus("close");
 
1143
  }
975
1144
  int status;
976
1145
  pid_t pret = -1;
977
1146
  errno = 0;
1077
1246
    bool match = false;
1078
1247
    {
1079
1248
      char *interface = NULL;
1080
 
      while((interface=argz_next(mc->interfaces, mc->interfaces_size,
1081
 
                                 interface))){
 
1249
      while((interface = argz_next(mc->interfaces,
 
1250
                                   mc->interfaces_size,
 
1251
                                   interface))){
1082
1252
        if(if_nametoindex(interface) == (unsigned int)if_index){
1083
1253
          match = true;
1084
1254
          break;
1237
1407
           with an explicit route added with the server's address.
1238
1408
           
1239
1409
           Avahi bug reference:
1240
 
           http://lists.freedesktop.org/archives/avahi/2010-February/001833.html
 
1410
           https://lists.freedesktop.org/archives/avahi/2010-February/001833.html
1241
1411
           https://bugs.debian.org/587961
1242
1412
        */
1243
1413
        if(debug){
1423
1593
                                               &decrypted_buffer, mc);
1424
1594
    if(decrypted_buffer_size >= 0){
1425
1595
      
 
1596
      clearerr(stdout);
1426
1597
      written = 0;
1427
1598
      while(written < (size_t) decrypted_buffer_size){
1428
1599
        if(quit_now){
1444
1615
        }
1445
1616
        written += (size_t)ret;
1446
1617
      }
 
1618
      ret = fflush(stdout);
 
1619
      if(ret != 0){
 
1620
        int e = errno;
 
1621
        if(debug){
 
1622
          fprintf_plus(stderr, "Error writing encrypted data: %s\n",
 
1623
                       strerror(errno));
 
1624
        }
 
1625
        errno = e;
 
1626
        goto mandos_end;
 
1627
      }
1447
1628
      retval = 0;
1448
1629
    }
1449
1630
  }
1480
1661
  return retval;
1481
1662
}
1482
1663
 
1483
 
__attribute__((nonnull))
1484
1664
static void resolve_callback(AvahiSServiceResolver *r,
1485
1665
                             AvahiIfIndex interface,
1486
1666
                             AvahiProtocol proto,
1641
1821
      perror_plus("ioctl SIOCGIFFLAGS");
1642
1822
      errno = old_errno;
1643
1823
    }
 
1824
    if((close(s) == -1) and debug){
 
1825
      old_errno = errno;
 
1826
      perror_plus("close");
 
1827
      errno = old_errno;
 
1828
    }
1644
1829
    return false;
1645
1830
  }
 
1831
  if((close(s) == -1) and debug){
 
1832
    old_errno = errno;
 
1833
    perror_plus("close");
 
1834
    errno = old_errno;
 
1835
  }
1646
1836
  return true;
1647
1837
}
1648
1838
 
1909
2099
      return;
1910
2100
    }
1911
2101
  }
 
2102
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
 
2103
  if(devnull == -1){
 
2104
    perror_plus("open(\"/dev/null\", O_RDONLY)");
 
2105
    return;
 
2106
  }
1912
2107
  int numhooks = scandirat(hookdir_fd, ".", &direntries,
1913
2108
                           runnable_hook, alphasort);
1914
2109
  if(numhooks == -1){
1915
2110
    perror_plus("scandir");
 
2111
    close(devnull);
1916
2112
    return;
1917
2113
  }
1918
2114
  struct dirent *direntry;
1919
2115
  int ret;
1920
 
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
1921
 
  if(devnull == -1){
1922
 
    perror_plus("open(\"/dev/null\", O_RDONLY)");
1923
 
    return;
1924
 
  }
1925
2116
  for(int i = 0; i < numhooks; i++){
1926
2117
    direntry = direntries[i];
1927
2118
    if(debug){
2183
2374
  
2184
2375
  /* Sleep checking until interface is running.
2185
2376
     Check every 0.25s, up to total time of delay */
2186
 
  for(int i=0; i < delay * 4; i++){
 
2377
  for(int i = 0; i < delay * 4; i++){
2187
2378
    if(interface_is_running(interface)){
2188
2379
      break;
2189
2380
    }
2276
2467
 
2277
2468
int main(int argc, char *argv[]){
2278
2469
  mandos_context mc = { .server = NULL, .dh_bits = 0,
 
2470
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2471
                        .priority = "SECURE128:!CTYPE-X.509"
 
2472
                        ":+CTYPE-RAWPK:!RSA:!VERS-ALL:+VERS-TLS1.3"
 
2473
                        ":%PROFILE_ULTRA",
 
2474
#elif GNUTLS_VERSION_NUMBER < 0x030600
2279
2475
                        .priority = "SECURE256:!CTYPE-X.509"
2280
2476
                        ":+CTYPE-OPENPGP:!RSA:+SIGN-DSA-SHA256",
 
2477
#else
 
2478
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
 
2479
#endif
2281
2480
                        .current_server = NULL, .interfaces = NULL,
2282
2481
                        .interfaces_size = 0 };
2283
2482
  AvahiSServiceBrowser *sb = NULL;
2294
2493
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
2295
2494
  const char *seckey = PATHDIR "/" SECKEY;
2296
2495
  const char *pubkey = PATHDIR "/" PUBKEY;
 
2496
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2497
  const char *tls_privkey = PATHDIR "/" TLS_PRIVKEY;
 
2498
  const char *tls_pubkey = PATHDIR "/" TLS_PUBKEY;
 
2499
#endif
2297
2500
  const char *dh_params_file = NULL;
2298
2501
  char *interfaces_hooks = NULL;
2299
2502
  
2347
2550
      { .name = "pubkey", .key = 'p',
2348
2551
        .arg = "FILE",
2349
2552
        .doc = "OpenPGP public key file base name",
2350
 
        .group = 2 },
 
2553
        .group = 1 },
 
2554
      { .name = "tls-privkey", .key = 't',
 
2555
        .arg = "FILE",
 
2556
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2557
        .doc = "TLS private key file base name",
 
2558
#else
 
2559
        .doc = "Dummy; ignored (requires GnuTLS 3.6.6)",
 
2560
#endif
 
2561
        .group = 1 },
 
2562
      { .name = "tls-pubkey", .key = 'T',
 
2563
        .arg = "FILE",
 
2564
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2565
        .doc = "TLS public key file base name",
 
2566
#else
 
2567
        .doc = "Dummy; ignored (requires GnuTLS 3.6.6)",
 
2568
#endif
 
2569
        .group = 1 },
2351
2570
      { .name = "dh-bits", .key = 129,
2352
2571
        .arg = "BITS",
2353
2572
        .doc = "Bit length of the prime number used in the"
2409
2628
      case 'p':                 /* --pubkey */
2410
2629
        pubkey = arg;
2411
2630
        break;
 
2631
      case 't':                 /* --tls-privkey */
 
2632
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2633
        tls_privkey = arg;
 
2634
#endif
 
2635
        break;
 
2636
      case 'T':                 /* --tls-pubkey */
 
2637
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
2638
        tls_pubkey = arg;
 
2639
#endif
 
2640
        break;
2412
2641
      case 129:                 /* --dh-bits */
2413
2642
        errno = 0;
2414
2643
        tmpmax = strtoimax(arg, &tmp, 10);
2449
2678
        argp_state_help(state, state->out_stream,
2450
2679
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
2451
2680
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
 
2681
        __builtin_unreachable();
2452
2682
      case -3:                  /* --usage */
2453
2683
        argp_state_help(state, state->out_stream,
2454
2684
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
 
2685
        __builtin_unreachable();
2455
2686
      case 'V':                 /* --version */
2456
2687
        fprintf_plus(state->out_stream, "%s\n", argp_program_version);
2457
2688
        exit(argp_err_exit_status);
2485
2716
  
2486
2717
  {
2487
2718
    /* Work around Debian bug #633582:
2488
 
       <http://bugs.debian.org/633582> */
 
2719
       <https://bugs.debian.org/633582> */
2489
2720
    
2490
2721
    /* Re-raise privileges */
2491
2722
    ret = raise_privileges();
2768
2999
    goto end;
2769
3000
  }
2770
3001
  
 
3002
#if GNUTLS_VERSION_NUMBER >= 0x030606
 
3003
  ret = init_gnutls_global(tls_pubkey, tls_privkey, dh_params_file, &mc);
 
3004
#elif GNUTLS_VERSION_NUMBER < 0x030600
2771
3005
  ret = init_gnutls_global(pubkey, seckey, dh_params_file, &mc);
 
3006
#else
 
3007
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
 
3008
#endif
2772
3009
  if(ret == -1){
2773
3010
    fprintf_plus(stderr, "init_gnutls_global failed\n");
2774
3011
    exitcode = EX_UNAVAILABLE;
2946
3183
 end:
2947
3184
  
2948
3185
  if(debug){
2949
 
    fprintf_plus(stderr, "%s exiting\n", argv[0]);
 
3186
    if(signal_received){
 
3187
      fprintf_plus(stderr, "%s exiting due to signal %d: %s\n",
 
3188
                   argv[0], signal_received,
 
3189
                   strsignal(signal_received));
 
3190
    } else {
 
3191
      fprintf_plus(stderr, "%s exiting\n", argv[0]);
 
3192
    }
2950
3193
  }
2951
3194
  
2952
3195
  /* Cleanup things */
3004
3247
      /* Take down the network interfaces which were brought up */
3005
3248
      {
3006
3249
        char *interface = NULL;
3007
 
        while((interface=argz_next(interfaces_to_take_down,
3008
 
                                   interfaces_to_take_down_size,
3009
 
                                   interface))){
 
3250
        while((interface = argz_next(interfaces_to_take_down,
 
3251
                                     interfaces_to_take_down_size,
 
3252
                                     interface))){
3010
3253
          ret = take_down_interface(interface);
3011
3254
          if(ret != 0){
3012
3255
            errno = ret;
3041
3284
                                                | O_PATH));
3042
3285
    if(dir_fd == -1){
3043
3286
      perror_plus("open");
 
3287
      return;
3044
3288
    }
3045
3289
    int numentries = scandirat(dir_fd, ".", &direntries,
3046
3290
                               notdotentries, alphasort);
3063
3307
            clean_dir_at(dir_fd, direntries[i]->d_name, level+1);
3064
3308
            dret = 0;
3065
3309
          }
3066
 
          if(dret == -1){
 
3310
          if((dret == -1) and (errno != ENOENT)){
3067
3311
            fprintf_plus(stderr, "unlink(\"%s/%s\"): %s\n", dirname,
3068
3312
                         direntries[i]->d_name, strerror(errno));
3069
3313
          }
3073
3317
      
3074
3318
      /* need to clean even if 0 because man page doesn't specify */
3075
3319
      free(direntries);
3076
 
      if(numentries == -1){
3077
 
        perror_plus("scandirat");
3078
 
      }
3079
3320
      dret = unlinkat(base, dirname, AT_REMOVEDIR);
3080
3321
      if(dret == -1 and errno != ENOENT){
3081
3322
        perror_plus("rmdir");