/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 at bsnet
  • Date: 2011-12-24 19:43:48 UTC
  • mfrom: (505.1.27 teddy)
  • Revision ID: teddy@fukt.bsnet.se-20111224194348-0buonmve2dnwcnzw
Merge from Teddy

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-2012 Teddy Hogeborn
13
 
 * Copyright © 2008-2012 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
41
41
 
42
42
#include <stdio.h>              /* fprintf(), stderr, fwrite(),
43
43
                                   stdout, ferror(), remove() */
44
 
#include <stdint.h>             /* uint16_t, uint32_t, intptr_t */
 
44
#include <stdint.h>             /* uint16_t, uint32_t */
45
45
#include <stddef.h>             /* NULL, size_t, ssize_t */
46
46
#include <stdlib.h>             /* free(), EXIT_SUCCESS, srand(),
47
47
                                   strtof(), abort() */
135
135
static const char sys_class_net[] = "/sys/class/net";
136
136
char *connect_to = NULL;
137
137
const char *hookdir = HOOKDIR;
138
 
uid_t uid = 65534;
139
 
gid_t gid = 65534;
140
138
 
141
139
/* Doubly linked list that need to be circularly linked when used */
142
140
typedef struct server{
172
170
 
173
171
/* Function to use when printing errors */
174
172
void perror_plus(const char *print_text){
175
 
  int e = errno;
176
173
  fprintf(stderr, "Mandos plugin %s: ",
177
174
          program_invocation_short_name);
178
 
  errno = e;
179
175
  perror(print_text);
180
176
}
181
177
 
182
 
__attribute__((format (gnu_printf, 2, 3)))
183
178
int fprintf_plus(FILE *stream, const char *format, ...){
184
179
  va_list ap;
185
180
  va_start (ap, format);
823
818
    goto mandos_end;
824
819
  }
825
820
  
826
 
  /* This casting via intptr_t is to eliminate warning about casting
827
 
     an int to a pointer type.  This is exactly how the GnuTLS Guile
828
 
     function "set-session-transport-fd!" does it. */
829
 
  gnutls_transport_set_ptr(session,
830
 
                           (gnutls_transport_ptr_t)(intptr_t)tcp_sd);
 
821
  /* Spurious warning from -Wint-to-pointer-cast */
 
822
  gnutls_transport_set_ptr(session, (gnutls_transport_ptr_t) tcp_sd);
831
823
  
832
824
  if(quit_now){
833
825
    errno = EINTR;
1392
1384
  }
1393
1385
}
1394
1386
 
1395
 
/* Set effective uid to 0, return errno */
1396
 
int raise_privileges(void){
1397
 
  int old_errno = errno;
1398
 
  int ret_errno = 0;
1399
 
  errno = 0;
1400
 
  if(seteuid(0) == -1){
1401
 
    perror_plus("seteuid");
1402
 
  }
1403
 
  ret_errno = errno;
1404
 
  errno = old_errno;
1405
 
  return ret_errno;
1406
 
}
1407
 
 
1408
 
/* Set effective and real user ID to 0.  Return errno. */
1409
 
int raise_privileges_permanently(void){
1410
 
  int old_errno = errno;
1411
 
  int ret_errno = raise_privileges();
1412
 
  if(ret_errno != 0){
1413
 
    errno = old_errno;
1414
 
    return ret_errno;
1415
 
  }
1416
 
  errno = 0;
1417
 
  if(setuid(0) == -1){
1418
 
    perror_plus("seteuid");
1419
 
  }
1420
 
  ret_errno = errno;
1421
 
  errno = old_errno;
1422
 
  return ret_errno;
1423
 
}
1424
 
 
1425
 
/* Set effective user ID to unprivileged saved user ID */
1426
 
int lower_privileges(void){
1427
 
  int old_errno = errno;
1428
 
  int ret_errno = 0;
1429
 
  errno = 0;
1430
 
  if(seteuid(uid) == -1){
1431
 
    perror_plus("seteuid");
1432
 
  }
1433
 
  ret_errno = errno;
1434
 
  errno = old_errno;
1435
 
  return ret_errno;
1436
 
}
1437
 
 
1438
1387
bool run_network_hooks(const char *mode, const char *interface,
1439
1388
                       const float delay){
1440
1389
  struct dirent **direntries;
1462
1411
      if(hook_pid == 0){
1463
1412
        /* Child */
1464
1413
        /* Raise privileges */
1465
 
        raise_privileges_permanently();
 
1414
        errno = 0;
 
1415
        ret = seteuid(0);
 
1416
        if(ret == -1){
 
1417
          perror_plus("seteuid");
 
1418
        }
 
1419
        /* Raise privileges even more */
 
1420
        errno = 0;
 
1421
        ret = setuid(0);
 
1422
        if(ret == -1){
 
1423
          perror_plus("setuid");
 
1424
        }
1466
1425
        /* Set group */
1467
1426
        errno = 0;
1468
1427
        ret = setgid(0);
1488
1447
          perror_plus("setenv");
1489
1448
          _exit(EX_OSERR);
1490
1449
        }
1491
 
        ret = setenv("VERBOSITY", debug ? "1" : "0", 1);
 
1450
        ret = setenv("VERBOSE", debug ? "1" : "0", 1);
1492
1451
        if(ret == -1){
1493
1452
          perror_plus("setenv");
1494
1453
          _exit(EX_OSERR);
1511
1470
          _exit(EX_OSERR);
1512
1471
        }
1513
1472
        free(delaystring);
1514
 
        if(connect_to != NULL){
1515
 
          ret = setenv("CONNECT", connect_to, 1);
1516
 
          if(ret == -1){
1517
 
            perror_plus("setenv");
1518
 
            _exit(EX_OSERR);
1519
 
          }
1520
 
        }
1521
 
        if(execl(fullname, direntry->d_name, mode, NULL) == -1){
1522
 
          perror_plus("execl");
1523
 
          _exit(EXIT_FAILURE);
1524
 
        }
 
1473
        ret = execl(fullname, direntry->d_name, mode, NULL);
 
1474
        perror_plus("execl");
1525
1475
      } else {
1526
1476
        int status;
1527
1477
        if(TEMP_FAILURE_RETRY(waitpid(hook_pid, &status, 0)) == -1){
1561
1511
  return true;
1562
1512
}
1563
1513
 
1564
 
int bring_up_interface(const char * const interface, const float delay){
1565
 
  int sd = -1;
1566
 
  int ret;
1567
 
  struct ifreq network;
1568
 
  AvahiIfIndex if_index = (AvahiIfIndex)if_nametoindex(interface);
1569
 
  if(if_index == 0){
1570
 
    fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
1571
 
    return EX_UNAVAILABLE;
1572
 
  }
1573
 
  
1574
 
  if(quit_now){
1575
 
    return EINTR;
1576
 
  }
1577
 
  
1578
 
  /* Re-raise priviliges */
1579
 
  raise_privileges();
1580
 
    
1581
 
#ifdef __linux__
1582
 
  /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
1583
 
     messages about the network interface to mess up the prompt */
1584
 
  ret = klogctl(8, NULL, 5);
1585
 
  bool restore_loglevel = true;
1586
 
  if(ret == -1){
1587
 
    restore_loglevel = false;
1588
 
    perror_plus("klogctl");
1589
 
  }
1590
 
#endif  /* __linux__ */
1591
 
    
1592
 
  sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
1593
 
  if(sd < 0){
1594
 
    perror_plus("socket");
1595
 
#ifdef __linux__
1596
 
    if(restore_loglevel){
1597
 
      ret = klogctl(7, NULL, 0);
1598
 
      if(ret == -1){
1599
 
        perror_plus("klogctl");
1600
 
      }
1601
 
    }
1602
 
#endif  /* __linux__ */
1603
 
    /* Lower privileges */
1604
 
    lower_privileges();
1605
 
    return EX_OSERR;
1606
 
;
1607
 
  }
1608
 
  strcpy(network.ifr_name, interface);
1609
 
  ret = ioctl(sd, SIOCGIFFLAGS, &network);
1610
 
  if(ret == -1){
1611
 
    perror_plus("ioctl SIOCGIFFLAGS");
1612
 
#ifdef __linux__
1613
 
    if(restore_loglevel){
1614
 
      ret = klogctl(7, NULL, 0);
1615
 
      if(ret == -1){
1616
 
        perror_plus("klogctl");
1617
 
      }
1618
 
    }
1619
 
#endif  /* __linux__ */
1620
 
    /* Lower privileges */
1621
 
    lower_privileges();
1622
 
    return EX_OSERR;
1623
 
  }
1624
 
  if((network.ifr_flags & IFF_UP) == 0){
1625
 
    network.ifr_flags |= IFF_UP;
1626
 
    ret = ioctl(sd, SIOCSIFFLAGS, &network);
1627
 
    if(ret == -1){
1628
 
      perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
1629
 
#ifdef __linux__
1630
 
      if(restore_loglevel){
1631
 
        ret = klogctl(7, NULL, 0);
1632
 
        if(ret == -1){
1633
 
          perror_plus("klogctl");
1634
 
        }
1635
 
      }
1636
 
#endif  /* __linux__ */
1637
 
        /* Lower privileges */
1638
 
      lower_privileges();
1639
 
      return EX_OSERR;
1640
 
    }
1641
 
  }
1642
 
  /* Sleep checking until interface is running.
1643
 
     Check every 0.25s, up to total time of delay */
1644
 
  for(int i=0; i < delay * 4; i++){
1645
 
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
1646
 
    if(ret == -1){
1647
 
      perror_plus("ioctl SIOCGIFFLAGS");
1648
 
    } else if(network.ifr_flags & IFF_RUNNING){
1649
 
      break;
1650
 
    }
1651
 
    struct timespec sleeptime = { .tv_nsec = 250000000 };
1652
 
    ret = nanosleep(&sleeptime, NULL);
1653
 
    if(ret == -1 and errno != EINTR){
1654
 
      perror_plus("nanosleep");
1655
 
    }
1656
 
  }
1657
 
  /* Close the socket */
1658
 
  ret = (int)TEMP_FAILURE_RETRY(close(sd));
1659
 
  if(ret == -1){
1660
 
    perror_plus("close");
1661
 
  }
1662
 
#ifdef __linux__
1663
 
  if(restore_loglevel){
1664
 
    /* Restores kernel loglevel to default */
1665
 
    ret = klogctl(7, NULL, 0);
1666
 
    if(ret == -1){
1667
 
      perror_plus("klogctl");
1668
 
    }
1669
 
  }
1670
 
#endif  /* __linux__ */
1671
 
  /* Lower privileges */
1672
 
  lower_privileges();
1673
 
  return errno;
1674
 
}
1675
 
 
1676
1514
int main(int argc, char *argv[]){
1677
1515
  AvahiSServiceBrowser *sb = NULL;
1678
1516
  int error;
1684
1522
  struct ifreq network;
1685
1523
  int sd = -1;
1686
1524
  bool take_down_interface = false;
 
1525
  uid_t uid;
 
1526
  gid_t gid;
1687
1527
  char tempdir[] = "/tmp/mandosXXXXXX";
1688
1528
  bool tempdir_created = false;
1689
1529
  AvahiIfIndex if_index = AVAHI_IF_UNSPEC;
1756
1596
        .group = 2 },
1757
1597
      { .name = "retry", .key = 132,
1758
1598
        .arg = "SECONDS",
1759
 
        .doc = "Retry interval used when denied by the Mandos server",
 
1599
        .doc = "Retry interval used when denied by the mandos server",
1760
1600
        .group = 2 },
1761
1601
      { .name = "network-hook-dir", .key = 133,
1762
1602
        .arg = "DIR",
1869
1709
       <http://bugs.debian.org/633582> */
1870
1710
    
1871
1711
    /* Re-raise priviliges */
1872
 
    if(raise_privileges() == 0){
 
1712
    errno = 0;
 
1713
    ret = seteuid(0);
 
1714
    if(ret == -1){
 
1715
      perror_plus("seteuid");
 
1716
    } else {
1873
1717
      struct stat st;
1874
1718
      
1875
1719
      if(strcmp(seckey, PATHDIR "/" SECKEY) == 0){
2040
1884
  }
2041
1885
  
2042
1886
  /* If the interface is down, bring it up */
2043
 
  if((interface[0] != '\0') and (strcmp(interface, "none") != 0)){
2044
 
    ret = bring_up_interface(interface, delay);
2045
 
    if(ret){
2046
 
      errno = ret;
2047
 
      perror_plus("Failed to bring up interface");
 
1887
  if(strcmp(interface, "none") != 0){
 
1888
    if_index = (AvahiIfIndex) if_nametoindex(interface);
 
1889
    if(if_index == 0){
 
1890
      fprintf_plus(stderr, "No such interface: \"%s\"\n", interface);
 
1891
      exitcode = EX_UNAVAILABLE;
 
1892
      goto end;
 
1893
    }
 
1894
    
 
1895
    if(quit_now){
 
1896
      goto end;
 
1897
    }
 
1898
    
 
1899
    /* Re-raise priviliges */
 
1900
    errno = 0;
 
1901
    ret = seteuid(0);
 
1902
    if(ret == -1){
 
1903
      perror_plus("seteuid");
 
1904
    }
 
1905
    
 
1906
#ifdef __linux__
 
1907
    /* Lower kernel loglevel to KERN_NOTICE to avoid KERN_INFO
 
1908
       messages about the network interface to mess up the prompt */
 
1909
    ret = klogctl(8, NULL, 5);
 
1910
    bool restore_loglevel = true;
 
1911
    if(ret == -1){
 
1912
      restore_loglevel = false;
 
1913
      perror_plus("klogctl");
 
1914
    }
 
1915
#endif  /* __linux__ */
 
1916
    
 
1917
    sd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_IP);
 
1918
    if(sd < 0){
 
1919
      perror_plus("socket");
 
1920
      exitcode = EX_OSERR;
 
1921
#ifdef __linux__
 
1922
      if(restore_loglevel){
 
1923
        ret = klogctl(7, NULL, 0);
 
1924
        if(ret == -1){
 
1925
          perror_plus("klogctl");
 
1926
        }
 
1927
      }
 
1928
#endif  /* __linux__ */
 
1929
      /* Lower privileges */
 
1930
      errno = 0;
 
1931
      ret = seteuid(uid);
 
1932
      if(ret == -1){
 
1933
        perror_plus("seteuid");
 
1934
      }
 
1935
      goto end;
 
1936
    }
 
1937
    strcpy(network.ifr_name, interface);
 
1938
    ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1939
    if(ret == -1){
 
1940
      perror_plus("ioctl SIOCGIFFLAGS");
 
1941
#ifdef __linux__
 
1942
      if(restore_loglevel){
 
1943
        ret = klogctl(7, NULL, 0);
 
1944
        if(ret == -1){
 
1945
          perror_plus("klogctl");
 
1946
        }
 
1947
      }
 
1948
#endif  /* __linux__ */
 
1949
      exitcode = EX_OSERR;
 
1950
      /* Lower privileges */
 
1951
      errno = 0;
 
1952
      ret = seteuid(uid);
 
1953
      if(ret == -1){
 
1954
        perror_plus("seteuid");
 
1955
      }
 
1956
      goto end;
 
1957
    }
 
1958
    if((network.ifr_flags & IFF_UP) == 0){
 
1959
      network.ifr_flags |= IFF_UP;
 
1960
      take_down_interface = true;
 
1961
      ret = ioctl(sd, SIOCSIFFLAGS, &network);
 
1962
      if(ret == -1){
 
1963
        take_down_interface = false;
 
1964
        perror_plus("ioctl SIOCSIFFLAGS +IFF_UP");
 
1965
        exitcode = EX_OSERR;
 
1966
#ifdef __linux__
 
1967
        if(restore_loglevel){
 
1968
          ret = klogctl(7, NULL, 0);
 
1969
          if(ret == -1){
 
1970
            perror_plus("klogctl");
 
1971
          }
 
1972
        }
 
1973
#endif  /* __linux__ */
 
1974
        /* Lower privileges */
 
1975
        errno = 0;
 
1976
        ret = seteuid(uid);
 
1977
        if(ret == -1){
 
1978
          perror_plus("seteuid");
 
1979
        }
 
1980
        goto end;
 
1981
      }
 
1982
    }
 
1983
    /* Sleep checking until interface is running.
 
1984
       Check every 0.25s, up to total time of delay */
 
1985
    for(int i=0; i < delay * 4; i++){
 
1986
      ret = ioctl(sd, SIOCGIFFLAGS, &network);
 
1987
      if(ret == -1){
 
1988
        perror_plus("ioctl SIOCGIFFLAGS");
 
1989
      } else if(network.ifr_flags & IFF_RUNNING){
 
1990
        break;
 
1991
      }
 
1992
      struct timespec sleeptime = { .tv_nsec = 250000000 };
 
1993
      ret = nanosleep(&sleeptime, NULL);
 
1994
      if(ret == -1 and errno != EINTR){
 
1995
        perror_plus("nanosleep");
 
1996
      }
 
1997
    }
 
1998
    if(not take_down_interface){
 
1999
      /* We won't need the socket anymore */
 
2000
      ret = (int)TEMP_FAILURE_RETRY(close(sd));
 
2001
      if(ret == -1){
 
2002
        perror_plus("close");
 
2003
      }
 
2004
    }
 
2005
#ifdef __linux__
 
2006
    if(restore_loglevel){
 
2007
      /* Restores kernel loglevel to default */
 
2008
      ret = klogctl(7, NULL, 0);
 
2009
      if(ret == -1){
 
2010
        perror_plus("klogctl");
 
2011
      }
 
2012
    }
 
2013
#endif  /* __linux__ */
 
2014
    /* Lower privileges */
 
2015
    errno = 0;
 
2016
    /* Lower privileges */
 
2017
    ret = seteuid(uid);
 
2018
    if(ret == -1){
 
2019
      perror_plus("seteuid");
2048
2020
    }
2049
2021
  }
2050
2022
  
2091
2063
    /* Connect directly, do not use Zeroconf */
2092
2064
    /* (Mainly meant for debugging) */
2093
2065
    char *address = strrchr(connect_to, ':');
2094
 
    
2095
2066
    if(address == NULL){
2096
2067
      fprintf_plus(stderr, "No colon in address\n");
2097
2068
      exitcode = EX_USAGE;
2260
2231
  
2261
2232
  /* Re-raise priviliges */
2262
2233
  {
2263
 
    raise_privileges();
 
2234
    errno = 0;
 
2235
    ret = seteuid(0);
 
2236
    if(ret == -1){
 
2237
      perror_plus("seteuid");
 
2238
    }
2264
2239
    
2265
2240
    /* Take down the network interface */
2266
2241
    if(take_down_interface and geteuid() == 0){