/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: 2011-07-25 18:52:11 UTC
  • mfrom: (489 trunk)
  • mto: (237.4.29 release)
  • mto: This revision was merged to the branch mainline in revision 490.
  • Revision ID: teddy@fukt.bsnet.se-20110725185211-wlitr9jvs70e1xh8
MergeĀ fromĀ trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
 * along with this program.  If not, see
27
27
 * <http://www.gnu.org/licenses/>.
28
28
 * 
29
 
 * Contact the authors at <mandos@recompile.se>.
 
29
 * Contact the authors at <mandos@fukt.bsnet.se>.
30
30
 */
31
31
 
32
32
/* Needed by GPGME, specifically gpgme_data_seek() */
127
127
bool debug = false;
128
128
static const char mandos_protocol_version[] = "1";
129
129
const char *argp_program_version = "mandos-client " VERSION;
130
 
const char *argp_program_bug_address = "<mandos@recompile.se>";
 
130
const char *argp_program_bug_address = "<mandos@fukt.bsnet.se>";
131
131
static const char sys_class_net[] = "/sys/class/net";
132
132
char *connect_to = NULL;
133
133
 
187
187
  return buffer_capacity;
188
188
}
189
189
 
190
 
/* Add server to set of servers to retry periodically */
191
190
int add_server(const char *ip, uint16_t port,
192
191
                 AvahiIfIndex if_index,
193
192
                 int af){
205
204
    perror_plus("strdup");
206
205
    return -1;
207
206
  }
208
 
  /* Special case of first server */
 
207
  /* unique case of first server */
209
208
  if (mc.current_server == NULL){
210
209
    new_server->next = new_server;
211
210
    new_server->prev = new_server;
212
211
    mc.current_server = new_server;
213
 
  /* Place the new server last in the list */
 
212
  /* Placing the new server last in the list */
214
213
  } else {
215
214
    new_server->next = mc.current_server;
216
215
    new_server->prev = mc.current_server->prev;
283
282
    return false;
284
283
  }
285
284
  
286
 
  /* Set GPGME home directory for the OpenPGP engine only */
 
285
    /* Set GPGME home directory for the OpenPGP engine only */
287
286
  rc = gpgme_get_engine_info(&engine_info);
288
287
  if(rc != GPG_ERR_NO_ERROR){
289
288
    fprintf(stderr, "bad gpgme_get_engine_info: %s: %s\n",
1092
1091
 */
1093
1092
int good_interface(const struct dirent *if_entry){
1094
1093
  ssize_t ssret;
1095
 
  int ret;
 
1094
  char *flagname = NULL;
1096
1095
  if(if_entry->d_name[0] == '.'){
1097
1096
    return 0;
1098
1097
  }
1099
 
  int s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1100
 
  if(s < 0){
1101
 
    perror_plus("socket");
1102
 
    return 0;
1103
 
  }
1104
 
  struct ifreq ifr;
1105
 
  strcpy(ifr.ifr_name, if_entry->d_name);
1106
 
  ret = ioctl(s, SIOCGIFFLAGS, &ifr);
1107
 
  if(ret == -1){
 
1098
  int ret = asprintf(&flagname, "%s/%s/flags", sys_class_net,
 
1099
                     if_entry->d_name);
 
1100
  if(ret < 0){
 
1101
    perror_plus("asprintf");
 
1102
    return 0;
 
1103
  }
 
1104
  int flags_fd = (int)TEMP_FAILURE_RETRY(open(flagname, O_RDONLY));
 
1105
  if(flags_fd == -1){
 
1106
    perror_plus("open");
 
1107
    free(flagname);
 
1108
    return 0;
 
1109
  }
 
1110
  free(flagname);
 
1111
  typedef short ifreq_flags;    /* ifreq.ifr_flags in netdevice(7) */
 
1112
  /* read line from flags_fd */
 
1113
  ssize_t to_read = 2+(sizeof(ifreq_flags)*2)+1; /* "0x1003\n" */
 
1114
  char *flagstring = malloc((size_t)to_read+1); /* +1 for final \0 */
 
1115
  flagstring[(size_t)to_read] = '\0';
 
1116
  if(flagstring == NULL){
 
1117
    perror_plus("malloc");
 
1118
    close(flags_fd);
 
1119
    return 0;
 
1120
  }
 
1121
  while(to_read > 0){
 
1122
    ssret = (ssize_t)TEMP_FAILURE_RETRY(read(flags_fd, flagstring,
 
1123
                                             (size_t)to_read));
 
1124
    if(ssret == -1){
 
1125
      perror_plus("read");
 
1126
      free(flagstring);
 
1127
      close(flags_fd);
 
1128
      return 0;
 
1129
    }
 
1130
    to_read -= ssret;
 
1131
    if(ssret == 0){
 
1132
      break;
 
1133
    }
 
1134
  }
 
1135
  close(flags_fd);
 
1136
  intmax_t tmpmax;
 
1137
  char *tmp;
 
1138
  errno = 0;
 
1139
  tmpmax = strtoimax(flagstring, &tmp, 0);
 
1140
  if(errno != 0 or tmp == flagstring or (*tmp != '\0'
 
1141
                                         and not (isspace(*tmp)))
 
1142
     or tmpmax != (ifreq_flags)tmpmax){
1108
1143
    if(debug){
1109
 
      perror_plus("ioctl SIOCGIFFLAGS");
 
1144
      fprintf(stderr, "Invalid flags \"%s\" for interface \"%s\"\n",
 
1145
              flagstring, if_entry->d_name);
1110
1146
    }
 
1147
    free(flagstring);
1111
1148
    return 0;
1112
1149
  }
 
1150
  free(flagstring);
 
1151
  ifreq_flags flags = (ifreq_flags)tmpmax;
1113
1152
  /* Reject the loopback device */
1114
 
  if(ifr.ifr_flags & IFF_LOOPBACK){
 
1153
  if(flags & IFF_LOOPBACK){
1115
1154
    if(debug){
1116
1155
      fprintf(stderr, "Rejecting loopback interface \"%s\"\n",
1117
1156
              if_entry->d_name);
1119
1158
    return 0;
1120
1159
  }
1121
1160
  /* Accept point-to-point devices only if connect_to is specified */
1122
 
  if(connect_to != NULL and (ifr.ifr_flags & IFF_POINTOPOINT)){
 
1161
  if(connect_to != NULL and (flags & IFF_POINTOPOINT)){
1123
1162
    if(debug){
1124
1163
      fprintf(stderr, "Accepting point-to-point interface \"%s\"\n",
1125
1164
              if_entry->d_name);
1127
1166
    return 1;
1128
1167
  }
1129
1168
  /* Otherwise, reject non-broadcast-capable devices */
1130
 
  if(not (ifr.ifr_flags & IFF_BROADCAST)){
 
1169
  if(not (flags & IFF_BROADCAST)){
1131
1170
    if(debug){
1132
1171
      fprintf(stderr, "Rejecting non-broadcast interface \"%s\"\n",
1133
1172
              if_entry->d_name);
1135
1174
    return 0;
1136
1175
  }
1137
1176
  /* Reject non-ARP interfaces (including dummy interfaces) */
1138
 
  if(ifr.ifr_flags & IFF_NOARP){
 
1177
  if(flags & IFF_NOARP){
1139
1178
    if(debug){
1140
1179
      fprintf(stderr, "Rejecting non-ARP interface \"%s\"\n",
1141
1180
              if_entry->d_name);
1166
1205
  struct timespec now;
1167
1206
  struct timespec waited_time;
1168
1207
  intmax_t block_time;
1169
 
  
 
1208
 
1170
1209
  while(true){
1171
1210
    if(mc.current_server == NULL){
1172
1211
      if (debug){
1197
1236
      block_time = ((retry_interval
1198
1237
                     - ((intmax_t)waited_time.tv_sec * 1000))
1199
1238
                    - ((intmax_t)waited_time.tv_nsec / 1000000));
1200
 
      
 
1239
 
1201
1240
      if (debug){
1202
 
        fprintf(stderr, "Blocking for %" PRIdMAX " ms\n", block_time);
 
1241
        fprintf(stderr, "Blocking for %ld ms\n", block_time);
1203
1242
      }
1204
 
      
 
1243
 
1205
1244
      if(block_time <= 0){
1206
1245
        ret = start_mandos_communication(mc.current_server->ip,
1207
1246
                                         mc.current_server->port,
1372
1411
        errno = 0;
1373
1412
        retry_interval = strtod(arg, &tmp);
1374
1413
        if(errno != 0 or tmp == arg or *tmp != '\0'
1375
 
           or (retry_interval * 1000) > INT_MAX
1376
 
           or retry_interval < 0){
 
1414
           or (retry_interval * 1000) > INT_MAX){
1377
1415
          argp_error(state, "Bad retry interval");
1378
1416
        }
1379
1417
        break;
1430
1468
      perror_plus("seteuid");
1431
1469
    }
1432
1470
    
1433
 
    if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){
1434
 
      int seckey_fd = open(seckey, O_RDONLY);
1435
 
      if(seckey_fd == -1){
1436
 
        perror_plus("open");
 
1471
    int seckey_fd = open(PATHDIR "/" SECKEY, O_RDONLY);
 
1472
    if(seckey_fd == -1){
 
1473
      perror_plus("open");
 
1474
    } else {
 
1475
      ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st));
 
1476
      if(ret == -1){
 
1477
        perror_plus("fstat");
1437
1478
      } else {
1438
 
        ret = (int)TEMP_FAILURE_RETRY(fstat(seckey_fd, &st));
1439
 
        if(ret == -1){
1440
 
          perror_plus("fstat");
1441
 
        } else {
1442
 
          if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){
1443
 
            ret = fchown(seckey_fd, uid, gid);
1444
 
            if(ret == -1){
1445
 
              perror_plus("fchown");
1446
 
            }
 
1479
        if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){
 
1480
          ret = fchown(seckey_fd, uid, gid);
 
1481
          if(ret == -1){
 
1482
            perror_plus("fchown");
1447
1483
          }
1448
1484
        }
1449
 
        TEMP_FAILURE_RETRY(close(seckey_fd));
1450
1485
      }
 
1486
      TEMP_FAILURE_RETRY(close(seckey_fd));
1451
1487
    }
1452
1488
    
1453
 
    if(strcmp(pubkey, PATHDIR "/" PUBKEY) == 0){
1454
 
      int pubkey_fd = open(pubkey, O_RDONLY);
1455
 
      if(pubkey_fd == -1){
1456
 
        perror_plus("open");
 
1489
    int pubkey_fd = open(PATHDIR "/" PUBKEY, O_RDONLY);
 
1490
    if(pubkey_fd == -1){
 
1491
      perror_plus("open");
 
1492
    } else {
 
1493
      ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st));
 
1494
      if(ret == -1){
 
1495
        perror_plus("fstat");
1457
1496
      } else {
1458
 
        ret = (int)TEMP_FAILURE_RETRY(fstat(pubkey_fd, &st));
1459
 
        if(ret == -1){
1460
 
          perror_plus("fstat");
1461
 
        } else {
1462
 
          if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){
1463
 
            ret = fchown(pubkey_fd, uid, gid);
1464
 
            if(ret == -1){
1465
 
              perror_plus("fchown");
1466
 
            }
 
1497
        if(S_ISREG(st.st_mode) and st.st_uid == 0 and st.st_gid == 0){
 
1498
          ret = fchown(pubkey_fd, uid, gid);
 
1499
          if(ret == -1){
 
1500
            perror_plus("fchown");
1467
1501
          }
1468
1502
        }
1469
 
        TEMP_FAILURE_RETRY(close(pubkey_fd));
1470
1503
      }
 
1504
      TEMP_FAILURE_RETRY(close(pubkey_fd));
1471
1505
    }
1472
1506
    
1473
1507
    /* Lower privileges */
1795
1829
    
1796
1830
    port = (uint16_t)tmpmax;
1797
1831
    *address = '\0';
 
1832
    address = connect_to;
1798
1833
    /* Colon in address indicates IPv6 */
1799
1834
    int af;
1800
 
    if(strchr(connect_to, ':') != NULL){
 
1835
    if(strchr(address, ':') != NULL){
1801
1836
      af = AF_INET6;
1802
 
      /* Accept [] around IPv6 address - see RFC 5952 */
1803
 
      if(connect_to[0] == '[' and address[-1] == ']')
1804
 
        {
1805
 
          connect_to++;
1806
 
          address[-1] = '\0';
1807
 
        }
1808
1837
    } else {
1809
1838
      af = AF_INET;
1810
1839
    }
1811
 
    address = connect_to;
1812
1840
    
1813
1841
    if(quit_now){
1814
1842
      goto end;
1815
1843
    }
1816
 
    
 
1844
 
1817
1845
    while(not quit_now){
1818
1846
      ret = start_mandos_communication(address, port, if_index, af);
1819
1847
      if(quit_now or ret == 0){
1820
1848
        break;
1821
1849
      }
1822
 
      if(debug){
1823
 
        fprintf(stderr, "Retrying in %d seconds\n",
1824
 
                (int)retry_interval);
1825
 
      }
1826
 
      sleep((int)retry_interval);
1827
 
    }
1828
 
    
 
1850
      sleep((int)retry_interval or 1);
 
1851
    };
 
1852
 
1829
1853
    if (not quit_now){
1830
1854
      exitcode = EXIT_SUCCESS;
1831
1855
    }
1968
1992
  if(tempdir_created){
1969
1993
    struct dirent **direntries = NULL;
1970
1994
    struct dirent *direntry = NULL;
1971
 
    int numentries = scandir(tempdir, &direntries, notdotentries,
1972
 
                             alphasort);
1973
 
    if (numentries > 0){
1974
 
      for(int i = 0; i < numentries; i++){
 
1995
    ret = scandir(tempdir, &direntries, notdotentries, alphasort);
 
1996
    if (ret > 0){
 
1997
      for(int i = 0; i < ret; i++){
1975
1998
        direntry = direntries[i];
1976
1999
        char *fullname = NULL;
1977
2000
        ret = asprintf(&fullname, "%s/%s", tempdir,
1989
2012
      }
1990
2013
    }
1991
2014
 
1992
 
    /* need to clean even if 0 because man page doesn't specify */
 
2015
    /* need to be cleaned even if ret == 0 because man page doesn't
 
2016
       specify */
1993
2017
    free(direntries);
1994
 
    if (numentries == -1){
 
2018
    if (ret == -1){
1995
2019
      perror_plus("scandir");
1996
2020
    }
1997
2021
    ret = rmdir(tempdir);