/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: Björn Påhlsson
  • Date: 2011-06-19 20:25:38 UTC
  • mto: This revision was merged to the branch mainline in revision 485.
  • Revision ID: belorn@fukt.bsnet.se-20110619202538-0js072v8fso12u07
prepended mandos plugin to error messages in each plugin. Added a better way in TODO.

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,2009 Teddy Hogeborn
13
 
 * Copyright © 2008,2009 Björn Påhlsson
 
12
 * Copyright © 2008-2011 Teddy Hogeborn
 
13
 * Copyright © 2008-2011 Björn Påhlsson
14
14
 * 
15
15
 * This program is free software: you can redistribute it and/or
16
16
 * modify it under the terms of the GNU General Public License as
63
63
                                   strtoimax() */
64
64
#include <assert.h>             /* assert() */
65
65
#include <errno.h>              /* perror(), errno */
66
 
#include <time.h>               /* nanosleep(), time() */
 
66
#include <time.h>               /* nanosleep(), time(), sleep() */
67
67
#include <net/if.h>             /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP,
68
68
                                   SIOCSIFFLAGS, if_indextoname(),
69
69
                                   if_nametoindex(), IF_NAMESIZE */
127
127
static const char mandos_protocol_version[] = "1";
128
128
const char *argp_program_version = "mandos-client " VERSION;
129
129
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
 
130
static const char sys_class_net[] = "/sys/class/net";
 
131
char *connect_to = NULL;
130
132
 
131
133
/* Used for passing in values through the Avahi callback functions */
132
134
typedef struct {
688
690
    ret = connect(tcp_sd, &to.in, sizeof(to)); /* IPv4 */
689
691
  }
690
692
  if(ret < 0){
691
 
    int e = errno;
692
 
    perror("connect");
693
 
    errno = e;
 
693
    if ((errno != ECONNREFUSED and errno != ENETUNREACH) or debug){
 
694
      int e = errno;
 
695
      perror("connect");
 
696
      errno = e;
 
697
    }
694
698
    goto mandos_end;
695
699
  }
696
700
  
737
741
    errno = EINTR;
738
742
    goto mandos_end;
739
743
  }
740
 
  
 
744
 
 
745
  /* Spurious warnings from -Wint-to-pointer-cast */
741
746
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
742
747
  
743
748
  if(quit_now){
1020
1025
  errno = old_errno;
1021
1026
}
1022
1027
 
 
1028
/* 
 
1029
 * This function determines if a directory entry in /sys/class/net
 
1030
 * corresponds to an acceptable network device.
 
1031
 * (This function is passed to scandir(3) as a filter function.)
 
1032
 */
 
1033
int good_interface(const struct dirent *if_entry){
 
1034
  ssize_t ssret;
 
1035
  char *flagname = NULL;
 
1036
  if(if_entry->d_name[0] == '.'){
 
1037
    return 0;
 
1038
  }
 
1039
  int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
 
1040
                     if_entry->d_name);
 
1041
  if(ret < 0){
 
1042
    perror("asprintf");
 
1043
    return 0;
 
1044
  }
 
1045
  int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
 
1046
  if(flags_fd == -1){
 
1047
    perror("open");
 
1048
    free(flagname);
 
1049
    return 0;
 
1050
  }
 
1051
  free(flagname);
 
1052
  typedef short ifreq_flags;    /* ifreq.ifr_flags in netdevice(7) */
 
1053
  /* read line from flags_fd */
 
1054
  ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
 
1055
  char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
 
1056
  flagstring[(size_t)to_read] = '\0';
 
1057
  if(flagstring == NULL){
 
1058
    perror("malloc");
 
1059
    close(flags_fd);
 
1060
    return 0;
 
1061
  }
 
1062
  while(to_read > 0){
 
1063
    ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
 
1064
                                             (size_t)to_read));
 
1065
    if(ssret == -1){
 
1066
      perror("read");
 
1067
      free(flagstring);
 
1068
      close(flags_fd);
 
1069
      return 0;
 
1070
    }
 
1071
    to_read -= ssret;
 
1072
    if(ssret == 0){
 
1073
      break;
 
1074
    }
 
1075
  }
 
1076
  close(flags_fd);
 
1077
  intmax_t tmpmax;
 
1078
  char *tmp;
 
1079
  errno = 0;
 
1080
  tmpmax = strtoimax(flagstring, &tmp, 0);
 
1081
  if(errno != 0 or tmp == flagstring or (*tmp != '\0'
 
1082
                                         and not (isspace(*tmp)))
 
1083
     or tmpmax != (ifreq_flags)tmpmax){
 
1084
    if(debug){
 
1085
      fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
 
1086
              flagstring, if_entry->d_name);
 
1087
    }
 
1088
    free(flagstring);
 
1089
    return 0;
 
1090
  }
 
1091
  free(flagstring);
 
1092
  ifreq_flags flags = (ifreq_flags)tmpmax;
 
1093
  /* Reject the loopback device */
 
1094
  if(flags & IFF_LOOPBACK){
 
1095
    if(debug){
 
1096
      fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
 
1097
              if_entry->d_name);
 
1098
    }
 
1099
    return 0;
 
1100
  }
 
1101
  /* Accept point-to-point devices only if connect_to is specified */
 
1102
  if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
 
1103
    if(debug){
 
1104
      fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
 
1105
              if_entry->d_name);
 
1106
    }
 
1107
    return 1;
 
1108
  }
 
1109
  /* Otherwise, reject non-broadcast-capable devices */
 
1110
  if(not (flags & IFF_BROADCAST)){
 
1111
    if(debug){
 
1112
      fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
 
1113
              if_entry->d_name);
 
1114
    }
 
1115
    return 0;
 
1116
  }
 
1117
  /* Reject non-ARP interfaces (including dummy interfaces) */
 
1118
  if(flags & IFF_NOARP){
 
1119
    if(debug){
 
1120
      fprintf(stderr, "Rejecting non-ARP interface \"%s\"\n",
 
1121
              if_entry->d_name);
 
1122
    }
 
1123
    return 0;
 
1124
  }
 
1125
  /* Accept this device */
 
1126
  if(debug){
 
1127
    fprintf(stderr, "Interface \"%s\" is acceptable\n",
 
1128
            if_entry->d_name);
 
1129
  }
 
1130
  return 1;
 
1131
}
 
1132
 
 
1133
int notdotentries(const struct dirent *direntry){
 
1134
  /* Skip "." and ".." */
 
1135
  if(direntry->d_name[0] == '.'
 
1136
     and (direntry->d_name[1] == '\0'
 
1137
          or (direntry->d_name[1] == '.'
 
1138
              and direntry->d_name[2] == '\0'))){
 
1139
    return 0;
 
1140
  }
 
1141
  return 1;
 
1142
}
 
1143
 
1023
1144
int main(int argc, char *argv[]){
1024
1145
  AvahiSServiceBrowser *sb = NULL;
1025
1146
  int error;
1027
1148
  intmax_t tmpmax;
1028
1149
  char *tmp;
1029
1150
  int exitcode = EXIT_SUCCESS;
1030
 
  const char *interface = "eth0";
 
1151
  const char *interface = "";
1031
1152
  struct ifreq network;
1032
1153
  int sd = -1;
1033
1154
  bool take_down_interface = false;
1034
1155
  uid_t uid;
1035
1156
  gid_t gid;
1036
 
  char *connect_to = NULL;
1037
1157
  char tempdir[] = "/tmp/mandosXXXXXX";
1038
1158
  bool tempdir_created = false;
1039
1159
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1196
1316
  if(not debug){
1197
1317
    avahi_set_log_function(empty_log);
1198
1318
  }
 
1319
 
 
1320
  if(interface[0] == '\0'){
 
1321
    struct dirent **direntries;
 
1322
    ret = scandir(sys_class_net, &direntries, good_interface,
 
1323
                  alphasort);
 
1324
    if(ret >= 1){
 
1325
      /* Pick the first good interface */
 
1326
      interface = strdup(direntries[0]->d_name);
 
1327
      if(debug){
 
1328
        fprintf(stderr, "Using interface \"%s\"\n", interface);
 
1329
      }
 
1330
      if(interface == NULL){
 
1331
        perror("malloc");
 
1332
        free(direntries);
 
1333
        exitcode = EXIT_FAILURE;
 
1334
        goto end;
 
1335
      }
 
1336
      free(direntries);
 
1337
    } else {
 
1338
      free(direntries);
 
1339
      fprintf(stderr, "Could not find a network interface\n");
 
1340
      exitcode = EXIT_FAILURE;
 
1341
      goto end;
 
1342
    }
 
1343
  }
1199
1344
  
1200
1345
  /* Initialize Avahi early so avahi_simple_poll_quit() can be called
1201
1346
     from the signal handler */
1272
1417
  }
1273
1418
  
1274
1419
  /* If the interface is down, bring it up */
1275
 
  if(interface[0] != '\0'){
 
1420
  if(strcmp(interface, "none") != 0){
1276
1421
    if_index = (AvahiIfIndex) if_nametoindex(interface);
1277
1422
    if(if_index == 0){
1278
1423
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
1349
1494
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
1350
1495
      if(ret == -1){
1351
1496
        take_down_interface = false;
1352
 
        perror("ioctl SIOCSIFFLAGS");
 
1497
        perror("ioctl SIOCSIFFLAGS +IFF_UP");
1353
1498
        exitcode = EX_OSERR;
1354
1499
#ifdef __linux__
1355
1500
        if(restore_loglevel){
1432
1577
    goto end;
1433
1578
  }
1434
1579
  
1435
 
  tempdir_created = true;
1436
1580
  if(mkdtemp(tempdir) == NULL){
1437
 
    tempdir_created = false;
1438
1581
    perror("mkdtemp");
1439
1582
    goto end;
1440
1583
  }
 
1584
  tempdir_created = true;
1441
1585
  
1442
1586
  if(quit_now){
1443
1587
    goto end;
1497
1641
    if(quit_now){
1498
1642
      goto end;
1499
1643
    }
1500
 
    
1501
 
    ret = start_mandos_communication(address, port, if_index, af);
1502
 
    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;
 
1644
 
 
1645
    while(not quit_now){
 
1646
      ret = start_mandos_communication(address, port, if_index, af);
 
1647
      if(quit_now or ret == 0){
1520
1648
        break;
1521
1649
      }
1522
 
    } else {
 
1650
      sleep(15);
 
1651
    };
 
1652
 
 
1653
    if (not quit_now){
1523
1654
      exitcode = EXIT_SUCCESS;
1524
1655
    }
 
1656
 
1525
1657
    goto end;
1526
1658
  }
1527
1659
  
1624
1756
        network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1625
1757
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
1626
1758
        if(ret == -1){
1627
 
          perror("ioctl SIOCSIFFLAGS");
 
1759
          perror("ioctl SIOCSIFFLAGS -IFF_UP");
1628
1760
        }
1629
1761
      }
1630
1762
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
1640
1772
    }
1641
1773
  }
1642
1774
  
1643
 
  /* Removes the temp directory used by GPGME */
 
1775
  /* Removes the GPGME temp directory and all files inside */
1644
1776
  if(tempdir_created){
1645
 
    DIR *d;
1646
 
    struct dirent *direntry;
1647
 
    d = opendir(tempdir);
1648
 
    if(d == NULL){
1649
 
      if(errno != ENOENT){
1650
 
        perror("opendir");
1651
 
      }
1652
 
    } else {
1653
 
      while(true){
1654
 
        direntry = readdir(d);
1655
 
        if(direntry == NULL){
1656
 
          break;
1657
 
        }
1658
 
        /* Skip "." and ".." */
1659
 
        if(direntry->d_name[0] == '.'
1660
 
           and (direntry->d_name[1] == '\0'
1661
 
                or (direntry->d_name[1] == '.'
1662
 
                    and direntry->d_name[2] == '\0'))){
1663
 
          continue;
1664
 
        }
 
1777
    struct dirent **direntries = NULL;
 
1778
    struct dirent *direntry = NULL;
 
1779
    ret = scandir(tempdir, &direntries, notdotentries, alphasort);
 
1780
    if (ret > 0){
 
1781
      for(int i = 0; i < ret; i++){
 
1782
        direntry = direntries[i];
1665
1783
        char *fullname = NULL;
1666
1784
        ret = asprintf(&fullname, "%s/%s", tempdir,
1667
1785
                       direntry->d_name);
1676
1794
        }
1677
1795
        free(fullname);
1678
1796
      }
1679
 
      closedir(d);
 
1797
    }
 
1798
 
 
1799
    /* need to be cleaned even if ret == 0 because man page dont specify */
 
1800
    free(direntries);
 
1801
    if (ret == -1){
 
1802
      perror("scandir");
1680
1803
    }
1681
1804
    ret = rmdir(tempdir);
1682
1805
    if(ret == -1 and errno != ENOENT){