/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

Convert some programs to use the exit codes from <sysexits.h>.  Change
all programs using the "argp" parsing functions to use them correctly;
checking return value, using argp_error() to report parse errors etc.

* plugin-runner.c: Use <sysexits.h> exit codes.  Always use fallback,
                   even on option errors, except for "--help", etc.
  (getplugin): Make sure "errno" is set correctly on return.
  (main): Declare our own "--help", "--usage", and "--version"
          options which do not cause the fallback to be invoked.
          In all other options, use fallback on any error.
  (parse_opt, parse_opt_config_file): Reset errno at start and return
                                      errno.  No need to check "arg"
                                      for NULL.  New "--help",
                                      "--usage", and "--version"
                                      options.
  (parse_opt): Accept empty string as global option.  Do not print
               errors which will be detected and reported later.  Do
               "argp_error()" on parse error or empty plugin names.
* plugins.d/mandos-client.c: Use <sysexits.h> exit codes.  Do not
                             return successful exit code on "--help",
                             etc. since this would give the wrong
                             message to "plugin-runner".
  (main): Declare our own "--help", "--usage", and "--version"
          options which do not return a successful exit code.
  (parse_opt): Reset errno at start and return errno.  Do
               "argp_error()" on parse errors.  New "--help",
               "--usage", and "--version" options.
* plugins.d/password-prompt.c: Use exit codes from <sysexits.h>.  Do
                               not return successful exit code on
                               "--help", etc. since this would give
                               the wrong message to "plugin-runner".
  (main): Declare our own "--help", "--usage", and "--version" options
          which do not return a successful exit code.  Do
          close(STDOUT_FILENO) after writing to check its return code.
  (parse_opt): Reset errno at start and return errno.

Show diffs side-by-side

added added

removed removed

Lines of Context:
43
43
                                   stdout, ferror(), remove() */
44
44
#include <stdint.h>             /* uint16_t, uint32_t */
45
45
#include <stddef.h>             /* NULL, size_t, ssize_t */
46
 
#include <stdlib.h>             /* free(), EXIT_SUCCESS, srand(),
47
 
                                   strtof(), abort() */
 
46
#include <stdlib.h>             /* free(), EXIT_SUCCESS, EXIT_FAILURE,
 
47
                                   srand(), strtof(), abort() */
48
48
#include <stdbool.h>            /* bool, false, true */
49
49
#include <string.h>             /* memset(), strcmp(), strlen(),
50
50
                                   strerror(), asprintf(), strcpy() */
82
82
#include <signal.h>             /* sigemptyset(), sigaddset(),
83
83
                                   sigaction(), SIGTERM, sig_atomic_t,
84
84
                                   raise() */
85
 
#include <sysexits.h>           /* EX_OSERR, EX_USAGE, EX_UNAVAILABLE,
86
 
                                   EX_NOHOST, EX_IOERR, EX_PROTOCOL */
 
85
#include <sysexits.h>           /* EX_OSERR, EX_USAGE */
87
86
 
88
87
#ifdef __linux__
89
88
#include <sys/klog.h>           /* klogctl() */
554
553
  gnutls_session_t session;
555
554
  int pf;                       /* Protocol family */
556
555
  
557
 
  errno = 0;
558
 
  
559
556
  if(quit_now){
560
 
    errno = EINTR;
561
557
    return -1;
562
558
  }
563
559
  
570
566
    break;
571
567
  default:
572
568
    fprintf(stderr, "Bad address family: %d\n", af);
573
 
    errno = EINVAL;
574
569
    return -1;
575
570
  }
576
571
  
586
581
  
587
582
  tcp_sd = socket(pf, SOCK_STREAM, 0);
588
583
  if(tcp_sd < 0){
589
 
    int e = errno;
590
584
    perror("socket");
591
 
    errno = e;
592
585
    goto mandos_end;
593
586
  }
594
587
  
595
588
  if(quit_now){
596
 
    errno = EINTR;
597
589
    goto mandos_end;
598
590
  }
599
591
  
606
598
    ret = inet_pton(af, ip, &to.in.sin_addr);
607
599
  }
608
600
  if(ret < 0 ){
609
 
    int e = errno;
610
601
    perror("inet_pton");
611
 
    errno = e;
612
602
    goto mandos_end;
613
603
  }
614
604
  if(ret == 0){
615
 
    int e = errno;
616
605
    fprintf(stderr, "Bad address: %s\n", ip);
617
 
    errno = e;
618
606
    goto mandos_end;
619
607
  }
620
608
  if(af == AF_INET6){
628
616
      if(if_index == AVAHI_IF_UNSPEC){
629
617
        fprintf(stderr, "An IPv6 link-local address is incomplete"
630
618
                " without a network interface\n");
631
 
        errno = EINVAL;
632
619
        goto mandos_end;
633
620
      }
634
621
      /* Set the network interface number as scope */
641
628
  }
642
629
  
643
630
  if(quit_now){
644
 
    errno = EINTR;
645
631
    goto mandos_end;
646
632
  }
647
633
  
678
664
  }
679
665
  
680
666
  if(quit_now){
681
 
    errno = EINTR;
682
667
    goto mandos_end;
683
668
  }
684
669
  
688
673
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
689
674
  }
690
675
  if(ret < 0){
691
 
    int e = errno;
692
676
    perror("connect");
693
 
    errno = e;
694
677
    goto mandos_end;
695
678
  }
696
679
  
697
680
  if(quit_now){
698
 
    errno = EINTR;
699
681
    goto mandos_end;
700
682
  }
701
683
  
706
688
    ret = (int)TEMP_FAILURE_RETRY(write(tcp_sd, out + written,
707
689
                                   out_size - written));
708
690
    if(ret == -1){
709
 
      int e = errno;
710
691
      perror("write");
711
 
      errno = e;
712
692
      goto mandos_end;
713
693
    }
714
694
    written += (size_t)ret;
724
704
    }
725
705
  
726
706
    if(quit_now){
727
 
      errno = EINTR;
728
707
      goto mandos_end;
729
708
    }
730
709
  }
734
713
  }
735
714
  
736
715
  if(quit_now){
737
 
    errno = EINTR;
738
716
    goto mandos_end;
739
717
  }
740
718
  
741
719
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
742
720
  
743
721
  if(quit_now){
744
 
    errno = EINTR;
745
722
    goto mandos_end;
746
723
  }
747
724
  
748
725
  do {
749
726
    ret = gnutls_handshake(session);
750
727
    if(quit_now){
751
 
      errno = EINTR;
752
728
      goto mandos_end;
753
729
    }
754
730
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
758
734
      fprintf(stderr, "*** GnuTLS Handshake failed ***\n");
759
735
      gnutls_perror(ret);
760
736
    }
761
 
    errno = EPROTO;
762
737
    goto mandos_end;
763
738
  }
764
739
  
772
747
  while(true){
773
748
    
774
749
    if(quit_now){
775
 
      errno = EINTR;
776
750
      goto mandos_end;
777
751
    }
778
752
    
779
753
    buffer_capacity = incbuffer(&buffer, buffer_length,
780
754
                                   buffer_capacity);
781
755
    if(buffer_capacity == 0){
782
 
      int e = errno;
783
756
      perror("incbuffer");
784
 
      errno = e;
785
757
      goto mandos_end;
786
758
    }
787
759
    
788
760
    if(quit_now){
789
 
      errno = EINTR;
790
761
      goto mandos_end;
791
762
    }
792
763
    
805
776
          ret = gnutls_handshake(session);
806
777
          
807
778
          if(quit_now){
808
 
            errno = EINTR;
809
779
            goto mandos_end;
810
780
          }
811
781
        } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
812
782
        if(ret < 0){
813
783
          fprintf(stderr, "*** GnuTLS Re-handshake failed ***\n");
814
784
          gnutls_perror(ret);
815
 
          errno = EPROTO;
816
785
          goto mandos_end;
817
786
        }
818
787
        break;
820
789
        fprintf(stderr, "Unknown error while reading data from"
821
790
                " encrypted session with Mandos server\n");
822
791
        gnutls_bye(session, GNUTLS_SHUT_RDWR);
823
 
        errno = EIO;
824
792
        goto mandos_end;
825
793
      }
826
794
    } else {
833
801
  }
834
802
  
835
803
  if(quit_now){
836
 
    errno = EINTR;
837
804
    goto mandos_end;
838
805
  }
839
806
  
840
807
  do {
841
808
    ret = gnutls_bye(session, GNUTLS_SHUT_RDWR);
842
809
    if(quit_now){
843
 
      errno = EINTR;
844
810
      goto mandos_end;
845
811
    }
846
812
  } while(ret == GNUTLS_E_AGAIN or ret == GNUTLS_E_INTERRUPTED);
855
821
      written = 0;
856
822
      while(written < (size_t) decrypted_buffer_size){
857
823
        if(quit_now){
858
 
          errno = EINTR;
859
824
          goto mandos_end;
860
825
        }
861
826
        
863
828
                          (size_t)decrypted_buffer_size - written,
864
829
                          stdout);
865
830
        if(ret == 0 and ferror(stdout)){
866
 
          int e = errno;
867
831
          if(debug){
868
832
            fprintf(stderr, "Error writing encrypted data: %s\n",
869
833
                    strerror(errno));
870
834
          }
871
 
          errno = e;
872
835
          goto mandos_end;
873
836
        }
874
837
        written += (size_t)ret;
880
843
  /* Shutdown procedure */
881
844
  
882
845
 mandos_end:
883
 
  {
884
 
    int e = errno;
885
 
    free(decrypted_buffer);
886
 
    free(buffer);
887
 
    if(tcp_sd >= 0){
888
 
      ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
889
 
    }
890
 
    if(ret == -1){
891
 
      if(e == 0){
892
 
        e = errno;
893
 
      }
894
 
      perror("close");
895
 
    }
896
 
    gnutls_deinit(session);
897
 
    if(quit_now){
898
 
      e = EINTR;
899
 
      retval = -1;
900
 
    }
901
 
    errno = e;
 
846
  free(decrypted_buffer);
 
847
  free(buffer);
 
848
  if(tcp_sd >= 0){
 
849
    ret = (int)TEMP_FAILURE_RETRY(close(tcp_sd));
 
850
  }
 
851
  if(ret == -1){
 
852
    perror("close");
 
853
  }
 
854
  gnutls_deinit(session);
 
855
  if(quit_now){
 
856
    retval = -1;
902
857
  }
903
858
  return retval;
904
859
}
1204
1159
  mc.simple_poll = avahi_simple_poll_new();
1205
1160
  if(mc.simple_poll == NULL){
1206
1161
    fprintf(stderr, "Avahi: Failed to create simple poll object.\n");
1207
 
    exitcode = EX_UNAVAILABLE;
 
1162
    exitcode = EXIT_FAILURE;
1208
1163
    goto end;
1209
1164
  }
1210
1165
  
1212
1167
  ret = sigaddset(&sigterm_action.sa_mask, SIGINT);
1213
1168
  if(ret == -1){
1214
1169
    perror("sigaddset");
1215
 
    exitcode = EX_OSERR;
 
1170
    exitcode = EXIT_FAILURE;
1216
1171
    goto end;
1217
1172
  }
1218
1173
  ret = sigaddset(&sigterm_action.sa_mask, SIGHUP);
1219
1174
  if(ret == -1){
1220
1175
    perror("sigaddset");
1221
 
    exitcode = EX_OSERR;
 
1176
    exitcode = EXIT_FAILURE;
1222
1177
    goto end;
1223
1178
  }
1224
1179
  ret = sigaddset(&sigterm_action.sa_mask, SIGTERM);
1225
1180
  if(ret == -1){
1226
1181
    perror("sigaddset");
1227
 
    exitcode = EX_OSERR;
 
1182
    exitcode = EXIT_FAILURE;
1228
1183
    goto end;
1229
1184
  }
1230
1185
  /* Need to check if the handler is SIG_IGN before handling:
1234
1189
  ret = sigaction(SIGINT, NULL, &old_sigterm_action);
1235
1190
  if(ret == -1){
1236
1191
    perror("sigaction");
1237
 
    return EX_OSERR;
 
1192
    return EXIT_FAILURE;
1238
1193
  }
1239
1194
  if(old_sigterm_action.sa_handler != SIG_IGN){
1240
1195
    ret = sigaction(SIGINT, &sigterm_action, NULL);
1241
1196
    if(ret == -1){
1242
1197
      perror("sigaction");
1243
 
      exitcode = EX_OSERR;
 
1198
      exitcode = EXIT_FAILURE;
1244
1199
      goto end;
1245
1200
    }
1246
1201
  }
1247
1202
  ret = sigaction(SIGHUP, NULL, &old_sigterm_action);
1248
1203
  if(ret == -1){
1249
1204
    perror("sigaction");
1250
 
    return EX_OSERR;
 
1205
    return EXIT_FAILURE;
1251
1206
  }
1252
1207
  if(old_sigterm_action.sa_handler != SIG_IGN){
1253
1208
    ret = sigaction(SIGHUP, &sigterm_action, NULL);
1254
1209
    if(ret == -1){
1255
1210
      perror("sigaction");
1256
 
      exitcode = EX_OSERR;
 
1211
      exitcode = EXIT_FAILURE;
1257
1212
      goto end;
1258
1213
    }
1259
1214
  }
1260
1215
  ret = sigaction(SIGTERM, NULL, &old_sigterm_action);
1261
1216
  if(ret == -1){
1262
1217
    perror("sigaction");
1263
 
    return EX_OSERR;
 
1218
    return EXIT_FAILURE;
1264
1219
  }
1265
1220
  if(old_sigterm_action.sa_handler != SIG_IGN){
1266
1221
    ret = sigaction(SIGTERM, &sigterm_action, NULL);
1267
1222
    if(ret == -1){
1268
1223
      perror("sigaction");
1269
 
      exitcode = EX_OSERR;
 
1224
      exitcode = EXIT_FAILURE;
1270
1225
      goto end;
1271
1226
    }
1272
1227
  }
1276
1231
    if_index = (AvahiIfIndex) if_nametoindex(interface);
1277
1232
    if(if_index == 0){
1278
1233
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
1279
 
      exitcode = EX_UNAVAILABLE;
 
1234
      exitcode = EXIT_FAILURE;
1280
1235
      goto end;
1281
1236
    }
1282
1237
    
1305
1260
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1306
1261
    if(sd < 0){
1307
1262
      perror("socket");
1308
 
      exitcode = EX_OSERR;
 
1263
      exitcode = EXIT_FAILURE;
1309
1264
#ifdef __linux__
1310
1265
      if(restore_loglevel){
1311
1266
        ret = klogctl(7, NULL, 0);
1334
1289
        }
1335
1290
      }
1336
1291
#endif  /* __linux__ */
1337
 
      exitcode = EX_OSERR;
 
1292
      exitcode = EXIT_FAILURE;
1338
1293
      /* Lower privileges */
1339
1294
      errno = 0;
1340
1295
      ret = seteuid(uid);
1350
1305
      if(ret == -1){
1351
1306
        take_down_interface = false;
1352
1307
        perror("ioctl SIOCSIFFLAGS");
1353
 
        exitcode = EX_OSERR;
 
1308
        exitcode = EXIT_FAILURE;
1354
1309
#ifdef __linux__
1355
1310
        if(restore_loglevel){
1356
1311
          ret = klogctl(7, NULL, 0);
1422
1377
  ret = init_gnutls_global(pubkey, seckey);
1423
1378
  if(ret == -1){
1424
1379
    fprintf(stderr, "init_gnutls_global failed\n");
1425
 
    exitcode = EX_UNAVAILABLE;
 
1380
    exitcode = EXIT_FAILURE;
1426
1381
    goto end;
1427
1382
  } else {
1428
1383
    gnutls_initialized = true;
1445
1400
  
1446
1401
  if(not init_gpgme(pubkey, seckey, tempdir)){
1447
1402
    fprintf(stderr, "init_gpgme failed\n");
1448
 
    exitcode = EX_UNAVAILABLE;
 
1403
    exitcode = EXIT_FAILURE;
1449
1404
    goto end;
1450
1405
  } else {
1451
1406
    gpgme_initialized = true;
1461
1416
    char *address = strrchr(connect_to, ':');
1462
1417
    if(address == NULL){
1463
1418
      fprintf(stderr, "No colon in address\n");
1464
 
      exitcode = EX_USAGE;
 
1419
      exitcode = EXIT_FAILURE;
1465
1420
      goto end;
1466
1421
    }
1467
1422
    
1475
1430
    if(errno != 0 or tmp == address+1 or *tmp != '\0'
1476
1431
       or tmpmax != (uint16_t)tmpmax){
1477
1432
      fprintf(stderr, "Bad port number\n");
1478
 
      exitcode = EX_USAGE;
 
1433
      exitcode = EXIT_FAILURE;
1479
1434
      goto end;
1480
1435
    }
1481
1436
  
1500
1455
    
1501
1456
    ret = start_mandos_communication(address, port, if_index, af);
1502
1457
    if(ret < 0){
1503
 
      switch(errno){
1504
 
      case ENETUNREACH:
1505
 
      case EHOSTDOWN:
1506
 
      case EHOSTUNREACH:
1507
 
        exitcode = EX_NOHOST;
1508
 
        break;
1509
 
      case EINVAL:
1510
 
        exitcode = EX_USAGE;
1511
 
        break;
1512
 
      case EIO:
1513
 
        exitcode = EX_IOERR;
1514
 
        break;
1515
 
      case EPROTO:
1516
 
        exitcode = EX_PROTOCOL;
1517
 
        break;
1518
 
      default:
1519
 
        exitcode = EX_OSERR;
1520
 
        break;
1521
 
      }
 
1458
      exitcode = EXIT_FAILURE;
1522
1459
    } else {
1523
1460
      exitcode = EXIT_SUCCESS;
1524
1461
    }
1551
1488
  if(mc.server == NULL){
1552
1489
    fprintf(stderr, "Failed to create Avahi server: %s\n",
1553
1490
            avahi_strerror(error));
1554
 
    exitcode = EX_UNAVAILABLE;
 
1491
    exitcode = EXIT_FAILURE;
1555
1492
    goto end;
1556
1493
  }
1557
1494
  
1566
1503
  if(sb == NULL){
1567
1504
    fprintf(stderr, "Failed to create service browser: %s\n",
1568
1505
            avahi_strerror(avahi_server_errno(mc.server)));
1569
 
    exitcode = EX_UNAVAILABLE;
 
1506
    exitcode = EXIT_FAILURE;
1570
1507
    goto end;
1571
1508
  }
1572
1509