/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 Hogeborn
  • Date: 2016-03-17 20:40:55 UTC
  • Revision ID: teddy@recompile.se-20160317204055-bhsh5xsidq7w5cxu
Client: Fix plymouth agent; broken since 1.7.2.

Fix an very old memory bug in the plymouth agent (which has been
present since its apperance in version 1.2), but which was only
recently detected at run time due to the new -fsanitize=address
compile- time flag, which has been used since version 1.7.2.  This
detection of a memory access violation causes the program to abort,
making the Plymouth graphical boot system unable to accept interactive
input of passwords when using the Mandos client.

* plugins.d/plymouth.c (exec_and_wait): Fix memory allocation bug when
  allocating new_argv.  Also tolerate a zero-length argv.

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-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
 
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
23
21
 * WITHOUT ANY WARRANTY; without even the implied warranty of
24
22
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25
23
 * General Public License for more details.
26
24
 * 
27
25
 * You should have received a copy of the GNU General Public License
28
 
 * along with Mandos.  If not, see <http://www.gnu.org/licenses/>.
 
26
 * along with this program.  If not, see
 
27
 * <http://www.gnu.org/licenses/>.
29
28
 * 
30
29
 * Contact the authors at <mandos@recompile.se>.
31
30
 */
48
47
                                   strtof(), abort() */
49
48
#include <stdbool.h>            /* bool, false, true */
50
49
#include <string.h>             /* strcmp(), strlen(), strerror(),
51
 
                                   asprintf(), strncpy(), strsignal()
52
 
                                */
 
50
                                   asprintf(), strncpy() */
53
51
#include <sys/ioctl.h>          /* ioctl */
54
52
#include <sys/types.h>          /* socket(), inet_pton(), sockaddr,
55
53
                                   sockaddr_in6, PF_INET6,
123
121
                                   gnutls_*
124
122
                                   init_gnutls_session(),
125
123
                                   GNUTLS_* */
126
 
#if GNUTLS_VERSION_NUMBER < 0x030600
127
124
#include <gnutls/openpgp.h>
128
125
                         /* gnutls_certificate_set_openpgp_key_file(),
129
126
                            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
135
127
 
136
128
/* GPGME */
137
129
#include <gpgme.h>              /* All GPGME types, constants and
145
137
#define PATHDIR "/conf/conf.d/mandos"
146
138
#define SECKEY "seckey.txt"
147
139
#define PUBKEY "pubkey.txt"
148
 
#define TLS_PRIVKEY "tls-privkey.pem"
149
 
#define TLS_PUBKEY "tls-pubkey.pem"
150
140
#define HOOKDIR "/lib/mandos/network-hooks.d"
151
141
 
152
142
bool debug = false;
280
270
  return true;
281
271
}
282
272
 
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
 
 
335
273
/* 
336
274
 * Initialize GPGME.
337
275
 */
357
295
      return false;
358
296
    }
359
297
    
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
 
 
409
298
    rc = gpgme_data_new_from_fd(&pgp_data, fd);
410
299
    if(rc != GPG_ERR_NO_ERROR){
411
300
      fprintf_plus(stderr, "bad gpgme_data_new_from_fd: %s: %s\n",
419
308
                   gpgme_strsource(rc), gpgme_strerror(rc));
420
309
      return false;
421
310
    }
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
 
    }
497
311
    
498
312
    ret = close(fd);
499
313
    if(ret == -1){
540
354
  /* Create new GPGME "context" */
541
355
  rc = gpgme_new(&(mc->ctx));
542
356
  if(rc != GPG_ERR_NO_ERROR){
543
 
    fprintf_plus(stderr, "bad gpgme_new: %s: %s\n",
544
 
                 gpgme_strsource(rc), gpgme_strerror(rc));
 
357
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
 
358
                 "bad gpgme_new: %s: %s\n", gpgme_strsource(rc),
 
359
                 gpgme_strerror(rc));
545
360
    return false;
546
361
  }
547
362
  
583
398
  /* Create new empty GPGME data buffer for the plaintext */
584
399
  rc = gpgme_data_new(&dh_plain);
585
400
  if(rc != GPG_ERR_NO_ERROR){
586
 
    fprintf_plus(stderr, "bad gpgme_data_new: %s: %s\n",
 
401
    fprintf_plus(stderr, "Mandos plugin mandos-client: "
 
402
                 "bad gpgme_data_new: %s: %s\n",
587
403
                 gpgme_strsource(rc), gpgme_strerror(rc));
588
404
    gpgme_data_release(dh_crypto);
589
405
    return -1;
602
418
      if(result == NULL){
603
419
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
604
420
      } else {
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");
 
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);
611
425
        if(result->file_name != NULL){
612
426
          fprintf_plus(stderr, "File name: %s\n", result->file_name);
613
427
        }
614
 
 
615
 
        for(gpgme_recipient_t r = result->recipients; r != NULL;
616
 
            r = r->next){
 
428
        gpgme_recipient_t recipient;
 
429
        recipient = result->recipients;
 
430
        while(recipient != NULL){
617
431
          fprintf_plus(stderr, "Public key algorithm: %s\n",
618
 
                       gpgme_pubkey_algo_name(r->pubkey_algo));
619
 
          fprintf_plus(stderr, "Key ID: %s\n", r->keyid);
 
432
                       gpgme_pubkey_algo_name
 
433
                       (recipient->pubkey_algo));
 
434
          fprintf_plus(stderr, "Key ID: %s\n", recipient->keyid);
620
435
          fprintf_plus(stderr, "Secret key available: %s\n",
621
 
                       r->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
 
436
                       recipient->status == GPG_ERR_NO_SECKEY
 
437
                       ? "No" : "Yes");
 
438
          recipient = recipient->next;
622
439
        }
623
440
      }
624
441
    }
706
523
                              const char *dhparamsfilename,
707
524
                              mandos_context *mc){
708
525
  int ret;
 
526
  unsigned int uret;
709
527
  
710
528
  if(debug){
711
529
    fprintf_plus(stderr, "Initializing GnuTLS\n");
728
546
  }
729
547
  
730
548
  if(debug){
731
 
    fprintf_plus(stderr, "Attempting to use public key %s and"
732
 
                 " private key %s as GnuTLS credentials\n",
 
549
    fprintf_plus(stderr, "Attempting to use OpenPGP public key %s and"
 
550
                 " secret key %s as GnuTLS credentials\n",
733
551
                 pubkeyfilename,
734
552
                 seckeyfilename);
735
553
  }
736
554
  
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
750
555
  ret = gnutls_certificate_set_openpgp_key_file
751
556
    (mc->cred, pubkeyfilename, seckeyfilename,
752
557
     GNUTLS_OPENPGP_FMT_BASE64);
753
 
#else
754
 
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
755
 
#endif
756
558
  if(ret != GNUTLS_E_SUCCESS){
757
559
    fprintf_plus(stderr,
758
 
                 "Error[%d] while reading the key pair ('%s',"
 
560
                 "Error[%d] while reading the OpenPGP key pair ('%s',"
759
561
                 " '%s')\n", ret, pubkeyfilename, seckeyfilename);
760
562
    fprintf_plus(stderr, "The GnuTLS error is: %s\n",
761
563
                 safer_gnutls_strerror(ret));
809
611
        }
810
612
        params.size += (unsigned int)bytes_read;
811
613
      }
812
 
      ret = close(dhpfile);
813
 
      if(ret == -1){
814
 
        perror_plus("close");
815
 
      }
816
614
      if(params.data == NULL){
817
615
        dhparamsfilename = NULL;
818
616
      }
827
625
                     safer_gnutls_strerror(ret));
828
626
        dhparamsfilename = NULL;
829
627
      }
830
 
      free(params.data);
831
628
    } while(false);
832
629
  }
833
630
  if(dhparamsfilename == NULL){
834
631
    if(mc->dh_bits == 0){
835
 
#if GNUTLS_VERSION_NUMBER < 0x030600
836
632
      /* Find out the optimal number of DH bits */
837
633
      /* Try to read the private key file */
838
634
      gnutls_datum_t buffer = { .data = NULL, .size = 0 };
918
714
          }
919
715
        }
920
716
      }
921
 
      unsigned int uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
 
717
      uret = gnutls_sec_param_to_pk_bits(GNUTLS_PK_DH, sec_param);
922
718
      if(uret != 0){
923
719
        mc->dh_bits = uret;
924
720
        if(debug){
936
732
                     safer_gnutls_strerror(ret));
937
733
        goto globalfail;
938
734
      }
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);
 
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;
953
745
    }
954
746
  }
 
747
  gnutls_certificate_set_dh_params(mc->cred, mc->dh_params);
955
748
  
956
749
  return 0;
957
750
  
968
761
  int ret;
969
762
  /* GnuTLS session creation */
970
763
  do {
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
 
                                ));
 
764
    ret = gnutls_init(session, GNUTLS_SERVER);
979
765
    if(quit_now){
980
766
      return -1;
981
767
    }
1029
815
static void empty_log(__attribute__((unused)) AvahiLogLevel level,
1030
816
                      __attribute__((unused)) const char *txt){}
1031
817
 
 
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
 
1032
870
/* Helper function to add_local_route() and delete_local_route() */
1033
871
__attribute__((nonnull, warn_unused_result))
1034
872
static bool add_delete_local_route(const bool add,
1073
911
      ret = setgid(0);
1074
912
      if(ret == -1){
1075
913
        perror_plus("setgid");
1076
 
        close(devnull);
1077
914
        _exit(EX_NOPERM);
1078
915
      }
1079
916
      /* Reset supplementary groups */
1081
918
      ret = setgroups(0, NULL);
1082
919
      if(ret == -1){
1083
920
        perror_plus("setgroups");
1084
 
        close(devnull);
1085
921
        _exit(EX_NOPERM);
1086
922
      }
1087
923
    }
1088
924
    ret = dup2(devnull, STDIN_FILENO);
1089
925
    if(ret == -1){
1090
926
      perror_plus("dup2(devnull, STDIN_FILENO)");
1091
 
      close(devnull);
1092
927
      _exit(EX_OSERR);
1093
928
    }
1094
929
    ret = close(devnull);
1095
930
    if(ret == -1){
1096
931
      perror_plus("close");
 
932
      _exit(EX_OSERR);
1097
933
    }
1098
934
    ret = dup2(STDERR_FILENO, STDOUT_FILENO);
1099
935
    if(ret == -1){
1134
970
  }
1135
971
  if(pid == -1){
1136
972
    perror_plus("fork");
1137
 
    close(devnull);
1138
973
    return false;
1139
974
  }
1140
 
  ret = close(devnull);
1141
 
  if(ret == -1){
1142
 
    perror_plus("close");
1143
 
  }
1144
975
  int status;
1145
976
  pid_t pret = -1;
1146
977
  errno = 0;
1246
1077
    bool match = false;
1247
1078
    {
1248
1079
      char *interface = NULL;
1249
 
      while((interface = argz_next(mc->interfaces,
1250
 
                                   mc->interfaces_size,
1251
 
                                   interface))){
 
1080
      while((interface=argz_next(mc->interfaces, mc->interfaces_size,
 
1081
                                 interface))){
1252
1082
        if(if_nametoindex(interface) == (unsigned int)if_index){
1253
1083
          match = true;
1254
1084
          break;
1407
1237
           with an explicit route added with the server's address.
1408
1238
           
1409
1239
           Avahi bug reference:
1410
 
           https://lists.freedesktop.org/archives/avahi/2010-February/001833.html
 
1240
           http://lists.freedesktop.org/archives/avahi/2010-February/001833.html
1411
1241
           https://bugs.debian.org/587961
1412
1242
        */
1413
1243
        if(debug){
1593
1423
                                               &decrypted_buffer, mc);
1594
1424
    if(decrypted_buffer_size >= 0){
1595
1425
      
1596
 
      clearerr(stdout);
1597
1426
      written = 0;
1598
1427
      while(written < (size_t) decrypted_buffer_size){
1599
1428
        if(quit_now){
1615
1444
        }
1616
1445
        written += (size_t)ret;
1617
1446
      }
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
 
      }
1628
1447
      retval = 0;
1629
1448
    }
1630
1449
  }
1661
1480
  return retval;
1662
1481
}
1663
1482
 
 
1483
__attribute__((nonnull))
1664
1484
static void resolve_callback(AvahiSServiceResolver *r,
1665
1485
                             AvahiIfIndex interface,
1666
1486
                             AvahiProtocol proto,
1821
1641
      perror_plus("ioctl SIOCGIFFLAGS");
1822
1642
      errno = old_errno;
1823
1643
    }
1824
 
    if((close(s) == -1) and debug){
1825
 
      old_errno = errno;
1826
 
      perror_plus("close");
1827
 
      errno = old_errno;
1828
 
    }
1829
1644
    return false;
1830
1645
  }
1831
 
  if((close(s) == -1) and debug){
1832
 
    old_errno = errno;
1833
 
    perror_plus("close");
1834
 
    errno = old_errno;
1835
 
  }
1836
1646
  return true;
1837
1647
}
1838
1648
 
2099
1909
      return;
2100
1910
    }
2101
1911
  }
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
 
  }
2107
1912
  int numhooks = scandirat(hookdir_fd, ".", &direntries,
2108
1913
                           runnable_hook, alphasort);
2109
1914
  if(numhooks == -1){
2110
1915
    perror_plus("scandir");
2111
 
    close(devnull);
2112
1916
    return;
2113
1917
  }
2114
1918
  struct dirent *direntry;
2115
1919
  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
  }
2116
1925
  for(int i = 0; i < numhooks; i++){
2117
1926
    direntry = direntries[i];
2118
1927
    if(debug){
2374
2183
  
2375
2184
  /* Sleep checking until interface is running.
2376
2185
     Check every 0.25s, up to total time of delay */
2377
 
  for(int i = 0; i < delay * 4; i++){
 
2186
  for(int i=0; i < delay * 4; i++){
2378
2187
    if(interface_is_running(interface)){
2379
2188
      break;
2380
2189
    }
2467
2276
 
2468
2277
int main(int argc, char *argv[]){
2469
2278
  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
2475
2279
                        .priority = "SECURE256:!CTYPE-X.509"
2476
2280
                        ":+CTYPE-OPENPGP:!RSA:+SIGN-DSA-SHA256",
2477
 
#else
2478
 
#error "Needs GnuTLS 3.6.6 or later, or before 3.6.0"
2479
 
#endif
2480
2281
                        .current_server = NULL, .interfaces = NULL,
2481
2282
                        .interfaces_size = 0 };
2482
2283
  AvahiSServiceBrowser *sb = NULL;
2493
2294
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
2494
2295
  const char *seckey = PATHDIR "/" SECKEY;
2495
2296
  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
2500
2297
  const char *dh_params_file = NULL;
2501
2298
  char *interfaces_hooks = NULL;
2502
2299
  
2550
2347
      { .name = "pubkey", .key = 'p',
2551
2348
        .arg = "FILE",
2552
2349
        .doc = "OpenPGP public key file base name",
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 },
 
2350
        .group = 2 },
2570
2351
      { .name = "dh-bits", .key = 129,
2571
2352
        .arg = "BITS",
2572
2353
        .doc = "Bit length of the prime number used in the"
2628
2409
      case 'p':                 /* --pubkey */
2629
2410
        pubkey = arg;
2630
2411
        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;
2641
2412
      case 129:                 /* --dh-bits */
2642
2413
        errno = 0;
2643
2414
        tmpmax = strtoimax(arg, &tmp, 10);
2678
2449
        argp_state_help(state, state->out_stream,
2679
2450
                        (ARGP_HELP_STD_HELP | ARGP_HELP_EXIT_ERR)
2680
2451
                        & ~(unsigned int)ARGP_HELP_EXIT_OK);
2681
 
        __builtin_unreachable();
2682
2452
      case -3:                  /* --usage */
2683
2453
        argp_state_help(state, state->out_stream,
2684
2454
                        ARGP_HELP_USAGE | ARGP_HELP_EXIT_ERR);
2685
 
        __builtin_unreachable();
2686
2455
      case 'V':                 /* --version */
2687
2456
        fprintf_plus(state->out_stream, "%s\n", argp_program_version);
2688
2457
        exit(argp_err_exit_status);
2716
2485
  
2717
2486
  {
2718
2487
    /* Work around Debian bug #633582:
2719
 
       <https://bugs.debian.org/633582> */
 
2488
       <http://bugs.debian.org/633582> */
2720
2489
    
2721
2490
    /* Re-raise privileges */
2722
2491
    ret = raise_privileges();
2999
2768
    goto end;
3000
2769
  }
3001
2770
  
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
3005
2771
  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
3009
2772
  if(ret == -1){
3010
2773
    fprintf_plus(stderr, "init_gnutls_global failed\n");
3011
2774
    exitcode = EX_UNAVAILABLE;
3183
2946
 end:
3184
2947
  
3185
2948
  if(debug){
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
 
    }
 
2949
    fprintf_plus(stderr, "%s exiting\n", argv[0]);
3193
2950
  }
3194
2951
  
3195
2952
  /* Cleanup things */
3247
3004
      /* Take down the network interfaces which were brought up */
3248
3005
      {
3249
3006
        char *interface = NULL;
3250
 
        while((interface = argz_next(interfaces_to_take_down,
3251
 
                                     interfaces_to_take_down_size,
3252
 
                                     interface))){
 
3007
        while((interface=argz_next(interfaces_to_take_down,
 
3008
                                   interfaces_to_take_down_size,
 
3009
                                   interface))){
3253
3010
          ret = take_down_interface(interface);
3254
3011
          if(ret != 0){
3255
3012
            errno = ret;
3284
3041
                                                | O_PATH));
3285
3042
    if(dir_fd == -1){
3286
3043
      perror_plus("open");
3287
 
      return;
3288
3044
    }
3289
3045
    int numentries = scandirat(dir_fd, ".", &direntries,
3290
3046
                               notdotentries, alphasort);
3307
3063
            clean_dir_at(dir_fd, direntries[i]->d_name, level+1);
3308
3064
            dret = 0;
3309
3065
          }
3310
 
          if((dret == -1) and (errno != ENOENT)){
 
3066
          if(dret == -1){
3311
3067
            fprintf_plus(stderr, "unlink(\"%s/%s\"): %s\n", dirname,
3312
3068
                         direntries[i]->d_name, strerror(errno));
3313
3069
          }
3317
3073
      
3318
3074
      /* need to clean even if 0 because man page doesn't specify */
3319
3075
      free(direntries);
 
3076
      if(numentries == -1){
 
3077
        perror_plus("scandirat");
 
3078
      }
3320
3079
      dret = unlinkat(base, dirname, AT_REMOVEDIR);
3321
3080
      if(dret == -1 and errno != ENOENT){
3322
3081
        perror_plus("rmdir");