/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

Merge from trunk.  Just a minor release to make it lintian clean.

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-2010 Teddy Hogeborn
 
13
 * Copyright © 2008-2010 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
  
1020
1024
  errno = old_errno;
1021
1025
}
1022
1026
 
 
1027
/* 
 
1028
 * This function determines if a directory entry in /sys/class/net
 
1029
 * corresponds to an acceptable network device.
 
1030
 * (This function is passed to scandir(3) as a filter function.)
 
1031
 */
 
1032
int good_interface(const struct dirent *if_entry){
 
1033
  ssize_t ssret;
 
1034
  char *flagname = NULL;
 
1035
  int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
 
1036
                     if_entry->d_name);
 
1037
  if(ret < 0){
 
1038
    perror("asprintf");
 
1039
    return 0;
 
1040
  }
 
1041
  if(if_entry->d_name[0] == '.'){
 
1042
    return 0;
 
1043
  }
 
1044
  int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
 
1045
  if(flags_fd == -1){
 
1046
    perror("open");
 
1047
    return 0;
 
1048
  }
 
1049
  typedef short ifreq_flags;    /* ifreq.ifr_flags in netdevice(7) */
 
1050
  /* read line from flags_fd */
 
1051
  ssize_t to_read = (sizeof(ifreq_flags)*2)+3; /* "0x1003\n" */
 
1052
  char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
 
1053
  flagstring[(size_t)to_read] = '\0';
 
1054
  if(flagstring == NULL){
 
1055
    perror("malloc");
 
1056
    close(flags_fd);
 
1057
    return 0;
 
1058
  }
 
1059
  while(to_read > 0){
 
1060
    ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
 
1061
                                             (size_t)to_read));
 
1062
    if(ssret == -1){
 
1063
      perror("read");
 
1064
      free(flagstring);
 
1065
      close(flags_fd);
 
1066
      return 0;
 
1067
    }
 
1068
    to_read -= ssret;
 
1069
    if(ssret == 0){
 
1070
      break;
 
1071
    }
 
1072
  }
 
1073
  close(flags_fd);
 
1074
  intmax_t tmpmax;
 
1075
  char *tmp;
 
1076
  errno = 0;
 
1077
  tmpmax = strtoimax(flagstring, &tmp, 0);
 
1078
  if(errno != 0 or tmp == flagstring or (*tmp != '\0'
 
1079
                                         and not (isspace(*tmp)))
 
1080
     or tmpmax != (ifreq_flags)tmpmax){
 
1081
    if(debug){
 
1082
      fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
 
1083
              flagstring, if_entry->d_name);
 
1084
    }
 
1085
    free(flagstring);
 
1086
    return 0;
 
1087
  }
 
1088
  free(flagstring);
 
1089
  ifreq_flags flags = (ifreq_flags)tmpmax;
 
1090
  /* Reject the loopback device */
 
1091
  if(flags & IFF_LOOPBACK){
 
1092
    if(debug){
 
1093
      fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
 
1094
              if_entry->d_name);
 
1095
    }
 
1096
    return 0;
 
1097
  }
 
1098
  /* Accept point-to-point devices only if connect_to is specified */
 
1099
  if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
 
1100
    if(debug){
 
1101
      fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
 
1102
              if_entry->d_name);
 
1103
    }
 
1104
    return 1;
 
1105
  }
 
1106
  /* Otherwise, reject non-broadcast-capable devices */
 
1107
  if(not (flags & IFF_BROADCAST)){
 
1108
    if(debug){
 
1109
      fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
 
1110
              if_entry->d_name);
 
1111
    }
 
1112
    return 0;
 
1113
  }
 
1114
  /* Accept this device */
 
1115
  if(debug){
 
1116
    fprintf(stderr, "Interface \"%s\" is acceptable\n",
 
1117
            if_entry->d_name);
 
1118
  }
 
1119
  return 1;
 
1120
}
 
1121
 
1023
1122
int main(int argc, char *argv[]){
1024
1123
  AvahiSServiceBrowser *sb = NULL;
1025
1124
  int error;
1027
1126
  intmax_t tmpmax;
1028
1127
  char *tmp;
1029
1128
  int exitcode = EXIT_SUCCESS;
1030
 
  const char *interface = "eth0";
 
1129
  const char *interface = "";
1031
1130
  struct ifreq network;
1032
1131
  int sd = -1;
1033
1132
  bool take_down_interface = false;
1034
1133
  uid_t uid;
1035
1134
  gid_t gid;
1036
 
  char *connect_to = NULL;
1037
1135
  char tempdir[] = "/tmp/mandosXXXXXX";
1038
1136
  bool tempdir_created = false;
1039
1137
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1196
1294
  if(not debug){
1197
1295
    avahi_set_log_function(empty_log);
1198
1296
  }
 
1297
 
 
1298
  if(interface[0] == '\0'){
 
1299
    struct dirent **direntries;
 
1300
    ret = scandir(sys_class_net, &direntries, good_interface,
 
1301
                  alphasort);
 
1302
    if(ret >= 1){
 
1303
      /* Pick the first good interface */
 
1304
      interface = strdup(direntries[0]->d_name);
 
1305
      if(debug){
 
1306
        fprintf(stderr, "Using interface \"%s\"\n", interface);
 
1307
      }
 
1308
      if(interface == NULL){
 
1309
        perror("malloc");
 
1310
        free(direntries);
 
1311
        exitcode = EXIT_FAILURE;
 
1312
        goto end;
 
1313
      }
 
1314
      free(direntries);
 
1315
    } else {
 
1316
      free(direntries);
 
1317
      fprintf(stderr, "Could not find a network interface\n");
 
1318
      exitcode = EXIT_FAILURE;
 
1319
      goto end;
 
1320
    }
 
1321
  }
1199
1322
  
1200
1323
  /* Initialize Avahi early so avahi_simple_poll_quit() can be called
1201
1324
     from the signal handler */
1272
1395
  }
1273
1396
  
1274
1397
  /* If the interface is down, bring it up */
1275
 
  if(interface[0] != '\0'){
 
1398
  if(strcmp(interface, "none") != 0){
1276
1399
    if_index = (AvahiIfIndex) if_nametoindex(interface);
1277
1400
    if(if_index == 0){
1278
1401
      fprintf(stderr, "No such interface: \"%s\"\n", interface);
1349
1472
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
1350
1473
      if(ret == -1){
1351
1474
        take_down_interface = false;
1352
 
        perror("ioctl SIOCSIFFLAGS");
 
1475
        perror("ioctl SIOCSIFFLAGS +IFF_UP");
1353
1476
        exitcode = EX_OSERR;
1354
1477
#ifdef __linux__
1355
1478
        if(restore_loglevel){
1497
1620
    if(quit_now){
1498
1621
      goto end;
1499
1622
    }
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;
 
1623
 
 
1624
    while(not quit_now){
 
1625
      ret = start_mandos_communication(address, port, if_index, af);
 
1626
      if(quit_now or ret == 0){
1520
1627
        break;
1521
1628
      }
1522
 
    } else {
 
1629
      sleep(15);
 
1630
    };
 
1631
 
 
1632
    if (not quit_now){
1523
1633
      exitcode = EXIT_SUCCESS;
1524
1634
    }
 
1635
 
1525
1636
    goto end;
1526
1637
  }
1527
1638
  
1624
1735
        network.ifr_flags &= ~(short)IFF_UP; /* clear flag */
1625
1736
        ret = ioctl(sd, SIOCSIFFLAGS, &network);
1626
1737
        if(ret == -1){
1627
 
          perror("ioctl SIOCSIFFLAGS");
 
1738
          perror("ioctl SIOCSIFFLAGS -IFF_UP");
1628
1739
        }
1629
1740
      }
1630
1741
      ret = (int)TEMP_FAILURE_RETRY(close(sd));