/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-2018 Teddy Hogeborn
13
 
 * Copyright © 2008-2018 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,
310
308
                   gpgme_strsource(rc), gpgme_strerror(rc));
311
309
      return false;
312
310
    }
313
 
    {
314
 
      gpgme_import_result_t import_result
315
 
        = gpgme_op_import_result(mc->ctx);
316
 
      if((import_result->imported < 1
317
 
          or import_result->not_imported > 0)
318
 
         and import_result->unchanged == 0){
319
 
        fprintf_plus(stderr, "bad gpgme_op_import_results:\n");
320
 
        fprintf_plus(stderr,
321
 
                     "The total number of considered keys: %d\n",
322
 
                     import_result->considered);
323
 
        fprintf_plus(stderr,
324
 
                     "The number of keys without user ID: %d\n",
325
 
                     import_result->no_user_id);
326
 
        fprintf_plus(stderr,
327
 
                     "The total number of imported keys: %d\n",
328
 
                     import_result->imported);
329
 
        fprintf_plus(stderr, "The number of imported RSA keys: %d\n",
330
 
                     import_result->imported_rsa);
331
 
        fprintf_plus(stderr, "The number of unchanged keys: %d\n",
332
 
                     import_result->unchanged);
333
 
        fprintf_plus(stderr, "The number of new user IDs: %d\n",
334
 
                     import_result->new_user_ids);
335
 
        fprintf_plus(stderr, "The number of new sub keys: %d\n",
336
 
                     import_result->new_sub_keys);
337
 
        fprintf_plus(stderr, "The number of new signatures: %d\n",
338
 
                     import_result->new_signatures);
339
 
        fprintf_plus(stderr, "The number of new revocations: %d\n",
340
 
                     import_result->new_revocations);
341
 
        fprintf_plus(stderr,
342
 
                     "The total number of secret keys read: %d\n",
343
 
                     import_result->secret_read);
344
 
        fprintf_plus(stderr,
345
 
                     "The number of imported secret keys: %d\n",
346
 
                     import_result->secret_imported);
347
 
        fprintf_plus(stderr,
348
 
                     "The number of unchanged secret keys: %d\n",
349
 
                     import_result->secret_unchanged);
350
 
        fprintf_plus(stderr, "The number of keys not imported: %d\n",
351
 
                     import_result->not_imported);
352
 
        for(gpgme_import_status_t import_status
353
 
              = import_result->imports;
354
 
            import_status != NULL;
355
 
            import_status = import_status->next){
356
 
          fprintf_plus(stderr, "Import status for key: %s\n",
357
 
                       import_status->fpr);
358
 
          if(import_status->result != GPG_ERR_NO_ERROR){
359
 
            fprintf_plus(stderr, "Import result: %s: %s\n",
360
 
                         gpgme_strsource(import_status->result),
361
 
                         gpgme_strerror(import_status->result));
362
 
          }
363
 
          fprintf_plus(stderr, "Key status:\n");
364
 
          fprintf_plus(stderr,
365
 
                       import_status->status & GPGME_IMPORT_NEW
366
 
                       ? "The key was new.\n"
367
 
                       : "The key was not new.\n");
368
 
          fprintf_plus(stderr,
369
 
                       import_status->status & GPGME_IMPORT_UID
370
 
                       ? "The key contained new user IDs.\n"
371
 
                       : "The key did not contain new user IDs.\n");
372
 
          fprintf_plus(stderr,
373
 
                       import_status->status & GPGME_IMPORT_SIG
374
 
                       ? "The key contained new signatures.\n"
375
 
                       : "The key did not contain new signatures.\n");
376
 
          fprintf_plus(stderr,
377
 
                       import_status->status & GPGME_IMPORT_SUBKEY
378
 
                       ? "The key contained new sub keys.\n"
379
 
                       : "The key did not contain new sub keys.\n");
380
 
          fprintf_plus(stderr,
381
 
                       import_status->status & GPGME_IMPORT_SECRET
382
 
                       ? "The key contained a secret key.\n"
383
 
                       : "The key did not contain a secret key.\n");
384
 
        }
385
 
        return false;
386
 
      }
387
 
    }
388
311
    
389
312
    ret = close(fd);
390
313
    if(ret == -1){
431
354
  /* Create new GPGME "context" */
432
355
  rc = gpgme_new(&(mc->ctx));
433
356
  if(rc != GPG_ERR_NO_ERROR){
434
 
    fprintf_plus(stderr, "bad gpgme_new: %s: %s\n",
435
 
                 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));
436
360
    return false;
437
361
  }
438
362
  
474
398
  /* Create new empty GPGME data buffer for the plaintext */
475
399
  rc = gpgme_data_new(&dh_plain);
476
400
  if(rc != GPG_ERR_NO_ERROR){
477
 
    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",
478
403
                 gpgme_strsource(rc), gpgme_strerror(rc));
479
404
    gpgme_data_release(dh_crypto);
480
405
    return -1;
493
418
      if(result == NULL){
494
419
        fprintf_plus(stderr, "gpgme_op_decrypt_result failed\n");
495
420
      } else {
496
 
        if(result->unsupported_algorithm != NULL) {
497
 
          fprintf_plus(stderr, "Unsupported algorithm: %s\n",
498
 
                       result->unsupported_algorithm);
499
 
        }
500
 
        fprintf_plus(stderr, "Wrong key usage: %s\n",
501
 
                     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);
502
425
        if(result->file_name != NULL){
503
426
          fprintf_plus(stderr, "File name: %s\n", result->file_name);
504
427
        }
505
 
 
506
 
        for(gpgme_recipient_t r = result->recipients; r != NULL;
507
 
            r = r->next){
 
428
        gpgme_recipient_t recipient;
 
429
        recipient = result->recipients;
 
430
        while(recipient != NULL){
508
431
          fprintf_plus(stderr, "Public key algorithm: %s\n",
509
 
                       gpgme_pubkey_algo_name(r->pubkey_algo));
510
 
          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);
511
435
          fprintf_plus(stderr, "Secret key available: %s\n",
512
 
                       r->status == GPG_ERR_NO_SECKEY ? "No" : "Yes");
 
436
                       recipient->status == GPG_ERR_NO_SECKEY
 
437
                       ? "No" : "Yes");
 
438
          recipient = recipient->next;
513
439
        }
514
440
      }
515
441
    }
685
611
        }
686
612
        params.size += (unsigned int)bytes_read;
687
613
      }
688
 
      ret = close(dhpfile);
689
 
      if(ret == -1){
690
 
        perror_plus("close");
691
 
      }
692
614
      if(params.data == NULL){
693
615
        dhparamsfilename = NULL;
694
616
      }
703
625
                     safer_gnutls_strerror(ret));
704
626
        dhparamsfilename = NULL;
705
627
      }
706
 
      free(params.data);
707
628
    } while(false);
708
629
  }
709
630
  if(dhparamsfilename == NULL){
1156
1077
    bool match = false;
1157
1078
    {
1158
1079
      char *interface = NULL;
1159
 
      while((interface = argz_next(mc->interfaces,
1160
 
                                   mc->interfaces_size,
1161
 
                                   interface))){
 
1080
      while((interface=argz_next(mc->interfaces, mc->interfaces_size,
 
1081
                                 interface))){
1162
1082
        if(if_nametoindex(interface) == (unsigned int)if_index){
1163
1083
          match = true;
1164
1084
          break;
1317
1237
           with an explicit route added with the server's address.
1318
1238
           
1319
1239
           Avahi bug reference:
1320
 
           https://lists.freedesktop.org/archives/avahi/2010-February/001833.html
 
1240
           http://lists.freedesktop.org/archives/avahi/2010-February/001833.html
1321
1241
           https://bugs.debian.org/587961
1322
1242
        */
1323
1243
        if(debug){
1503
1423
                                               &decrypted_buffer, mc);
1504
1424
    if(decrypted_buffer_size >= 0){
1505
1425
      
1506
 
      clearerr(stdout);
1507
1426
      written = 0;
1508
1427
      while(written < (size_t) decrypted_buffer_size){
1509
1428
        if(quit_now){
1525
1444
        }
1526
1445
        written += (size_t)ret;
1527
1446
      }
1528
 
      ret = fflush(stdout);
1529
 
      if(ret != 0){
1530
 
        int e = errno;
1531
 
        if(debug){
1532
 
          fprintf_plus(stderr, "Error writing encrypted data: %s\n",
1533
 
                       strerror(errno));
1534
 
        }
1535
 
        errno = e;
1536
 
        goto mandos_end;
1537
 
      }
1538
1447
      retval = 0;
1539
1448
    }
1540
1449
  }
1571
1480
  return retval;
1572
1481
}
1573
1482
 
 
1483
__attribute__((nonnull))
1574
1484
static void resolve_callback(AvahiSServiceResolver *r,
1575
1485
                             AvahiIfIndex interface,
1576
1486
                             AvahiProtocol proto,
1731
1641
      perror_plus("ioctl SIOCGIFFLAGS");
1732
1642
      errno = old_errno;
1733
1643
    }
1734
 
    if((close(s) == -1) and debug){
1735
 
      old_errno = errno;
1736
 
      perror_plus("close");
1737
 
      errno = old_errno;
1738
 
    }
1739
1644
    return false;
1740
1645
  }
1741
 
  if((close(s) == -1) and debug){
1742
 
    old_errno = errno;
1743
 
    perror_plus("close");
1744
 
    errno = old_errno;
1745
 
  }
1746
1646
  return true;
1747
1647
}
1748
1648
 
2009
1909
      return;
2010
1910
    }
2011
1911
  }
2012
 
  int devnull = (int)TEMP_FAILURE_RETRY(open("/dev/null", O_RDONLY));
2013
 
  if(devnull == -1){
2014
 
    perror_plus("open(\"/dev/null\", O_RDONLY)");
2015
 
    return;
2016
 
  }
2017
1912
  int numhooks = scandirat(hookdir_fd, ".", &direntries,
2018
1913
                           runnable_hook, alphasort);
2019
1914
  if(numhooks == -1){
2020
1915
    perror_plus("scandir");
2021
 
    close(devnull);
2022
1916
    return;
2023
1917
  }
2024
1918
  struct dirent *direntry;
2025
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
  }
2026
1925
  for(int i = 0; i < numhooks; i++){
2027
1926
    direntry = direntries[i];
2028
1927
    if(debug){
2284
2183
  
2285
2184
  /* Sleep checking until interface is running.
2286
2185
     Check every 0.25s, up to total time of delay */
2287
 
  for(int i = 0; i < delay * 4; i++){
 
2186
  for(int i=0; i < delay * 4; i++){
2288
2187
    if(interface_is_running(interface)){
2289
2188
      break;
2290
2189
    }
2586
2485
  
2587
2486
  {
2588
2487
    /* Work around Debian bug #633582:
2589
 
       <https://bugs.debian.org/633582> */
 
2488
       <http://bugs.debian.org/633582> */
2590
2489
    
2591
2490
    /* Re-raise privileges */
2592
2491
    ret = raise_privileges();
3047
2946
 end:
3048
2947
  
3049
2948
  if(debug){
3050
 
    if(signal_received){
3051
 
      fprintf_plus(stderr, "%s exiting due to signal %d: %s\n",
3052
 
                   argv[0], signal_received,
3053
 
                   strsignal(signal_received));
3054
 
    } else {
3055
 
      fprintf_plus(stderr, "%s exiting\n", argv[0]);
3056
 
    }
 
2949
    fprintf_plus(stderr, "%s exiting\n", argv[0]);
3057
2950
  }
3058
2951
  
3059
2952
  /* Cleanup things */
3111
3004
      /* Take down the network interfaces which were brought up */
3112
3005
      {
3113
3006
        char *interface = NULL;
3114
 
        while((interface = argz_next(interfaces_to_take_down,
3115
 
                                     interfaces_to_take_down_size,
3116
 
                                     interface))){
 
3007
        while((interface=argz_next(interfaces_to_take_down,
 
3008
                                   interfaces_to_take_down_size,
 
3009
                                   interface))){
3117
3010
          ret = take_down_interface(interface);
3118
3011
          if(ret != 0){
3119
3012
            errno = ret;
3148
3041
                                                | O_PATH));
3149
3042
    if(dir_fd == -1){
3150
3043
      perror_plus("open");
3151
 
      return;
3152
3044
    }
3153
3045
    int numentries = scandirat(dir_fd, ".", &direntries,
3154
3046
                               notdotentries, alphasort);
3171
3063
            clean_dir_at(dir_fd, direntries[i]->d_name, level+1);
3172
3064
            dret = 0;
3173
3065
          }
3174
 
          if((dret == -1) and (errno != ENOENT)){
 
3066
          if(dret == -1){
3175
3067
            fprintf_plus(stderr, "unlink(\"%s/%s\"): %s\n", dirname,
3176
3068
                         direntries[i]->d_name, strerror(errno));
3177
3069
          }
3181
3073
      
3182
3074
      /* need to clean even if 0 because man page doesn't specify */
3183
3075
      free(direntries);
 
3076
      if(numentries == -1){
 
3077
        perror_plus("scandirat");
 
3078
      }
3184
3079
      dret = unlinkat(base, dirname, AT_REMOVEDIR);
3185
3080
      if(dret == -1 and errno != ENOENT){
3186
3081
        perror_plus("rmdir");