summaryrefslogtreecommitdiff
path: root/tnc/tcos-net-controller.c
diff options
context:
space:
mode:
authorMario Izquierdo (mariodebian) <mariodebian@gmail.com>2012-06-22 12:42:53 +0100
committerMario Izquierdo (mariodebian) <mariodebian@gmail.com>2012-06-22 12:42:53 +0100
commit85e11fb132b2b81b50a45647b070e8f6fd648d65 (patch)
tree1238a0e269d68604457ef6435e1c7ec18ffe7e20 /tnc/tcos-net-controller.c
tcos (0.89.90) unstable; urgency=low
* debian/initramfs-tools-tcos.postrm: - piuparts, don't call delgroup if can't * Add overlayfs as aufs alternative * hooks-addons/clean_initramfs: multiarch with libpci3 * Simplify grep commands * Install conf/tcos.conf instead of conf/tcos.conf.etc * Use a global LIB_MULTIARCH var * tcos-standalone French translation, thanks to Julien Patriarca, (closes: #672135) # imported from the archive
Diffstat (limited to 'tnc/tcos-net-controller.c')
-rw-r--r--tnc/tcos-net-controller.c582
1 files changed, 582 insertions, 0 deletions
diff --git a/tnc/tcos-net-controller.c b/tnc/tcos-net-controller.c
new file mode 100644
index 0000000..e408e3b
--- /dev/null
+++ b/tnc/tcos-net-controller.c
@@ -0,0 +1,582 @@
+/*
+* tcos-net-controller.c
+* => iptables controller
+* Copyright (C) 2006,2007,2008 mariodebian at gmail
+* Copyright (C) 2006,2007,2008 vidal_joshur at gva.es
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+
+#define GROUP "tcos"
+#define IPTABLES "/sbin/iptables"
+#define BLACKLIST_PORTS "8998,8999"
+#define BSIZE 1024
+
+#ifndef DEVNULL
+#define DEVNULL "2>/dev/null"
+#endif
+
+void create_route(struct rtentry *p, char **args);
+
+char *strncpy( char *to, const char *from, size_t count );
+
+FILE *popen(const char *orden, const char *tipo);
+int pclose(FILE *flujo);
+
+void *malloc(size_t size);
+
+int getgroups(int size, gid_t list[]);
+
+/* int strcmp(const char *str1, const char *str2); */
+char *strtok( char *str1, const char *str2 );
+
+int getnameinfo(const struct sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen, int flags);
+
+#define MAXTOKENS 256
+#define MAXLINE 1024 /* fgets buff */
+#define MINLEN 3 /* skip lines shorter as */
+
+/* split string into tokens, return token array */
+/* http://www.c.happycodings.com/Miscellaneous/code37.html */
+char **split(char *string, char *delim) {
+ char **tokens = NULL;
+ char *working = NULL;
+ char *token = NULL;
+ int idx = 0;
+
+ tokens = malloc(sizeof(char *) * MAXTOKENS);
+ if(tokens == NULL)
+ return NULL;
+ working = malloc(sizeof(char) * strlen(string) + 1);
+ if(working == NULL)
+ return NULL;
+
+ /* to make sure, copy string to a safe place */
+ strcpy(working, string);
+ for(idx = 0; idx < MAXTOKENS; idx++)
+ tokens[idx] = NULL;
+
+ token = strtok(working, delim);
+ idx = 0;
+
+ /* always keep the last entry NULL termindated */
+ while((idx < (MAXTOKENS - 1)) && (token != NULL)) {
+ tokens[idx] = malloc(sizeof(char) * strlen(token) + 1);
+ if(tokens[idx] != NULL) {
+ strcpy(tokens[idx], token);
+ idx++;
+ token = strtok(NULL, delim);
+ }
+ }
+
+ free(working);
+ return tokens;
+}
+
+#ifdef DEBUG
+/* debug print to stderr */
+void debug( const char *format_str, ... ) {
+ va_list ap;
+ va_start( ap, format_str );
+ va_end( ap );
+ fprintf(stderr, "TNC-DEBUG::");
+ vfprintf(stderr, format_str , ap);
+}
+#endif
+
+
+int
+check_port (char* port)
+{
+ char blacklist[] = BLACKLIST_PORTS;
+ char *delim = ",";
+ char **tokens = NULL;
+ int i=0,j;
+
+ if (atoi(port) > 65535 || atoi(port) < 1) {
+#ifdef DEBUG
+ debug("check_port() Incorrect port: %s\n", port);
+#endif
+ i=1;
+ return(i);
+ }
+
+ tokens = split(blacklist, delim);
+ for(j = 0; tokens[j] != NULL; j++){
+#ifdef DEBUG
+ debug("check_port(): token=%s ¿=? port=%s\n", tokens[j], port);
+#endif
+ if (atoi(port) == atoi(tokens[j])) {
+ i=1;
+ }
+ }
+ for(j = 0; tokens[j] != NULL; j++) {
+ free(tokens[j]);
+ }
+ free(tokens);
+
+ return i;
+}
+
+
+static unsigned int
+get_uid (const char* user)
+{
+ struct passwd *pw = NULL;
+ uid_t value=0;
+
+ pw = getpwnam(user);
+
+ if (pw == NULL)
+ return value;
+ else
+ return pw->pw_uid;
+}
+
+
+static char
+*get_group (gid_t gid)
+{
+ struct group *grp = NULL;
+
+ grp = getgrgid (gid);
+
+ if (grp == NULL)
+ return "";
+ else
+ return grp->gr_name;
+}
+
+
+int
+check_user ()
+{
+ gid_t *list;
+ int i,n,found=0;
+ uid_t uid, euid;
+
+ if ((n = getgroups(0, NULL)) < 0) {
+ found=0;
+ }
+
+ list = (gid_t*)malloc(sizeof (gid_t) * (n + 1));
+ if (!list) {
+#ifdef DEBUG
+ debug("check_user() out of memory!\n");
+#endif
+ found=0;
+ }
+
+ n = getgroups(n, list);
+
+ uid = getuid();
+ euid = geteuid();
+
+ if (uid == 0 && euid == 0) {
+ found=1;
+ }
+ else {
+ for (i = 0; i < n; i++) {
+#ifdef DEBUG
+ debug("check_user() %lu (%s) %d %d\n", (unsigned long)list[i], get_group(list[i]), uid, euid);
+#endif
+ if ( (strcmp( get_group(list[i]), GROUP) == 0) && (euid == 0) ) {
+ /* Only work if euid is root */
+ found=1;
+ }
+ }
+ }
+ free(list);
+ return(found);
+}
+
+
+int
+status_iptables_user(char *args) {
+
+ FILE *fp;
+ char cmd[BSIZE];
+ char line[BSIZE];
+ /* iptables rules with tcos argument, allow not remove other rules. */
+ sprintf( cmd, "%s -L OUTPUT --line-numbers -n %s | grep TCOS_TNC | awk 'BEGIN{count=0}{if ($(NF-3) == %d || $(NF-3) == \"%s\") count++}END{print count}'", IPTABLES, DEVNULL, (int)get_uid(args), args);
+#ifdef DEBUG
+ debug("status_iptables_user() %s\n",cmd);
+#endif
+ if ((fp=(FILE*)popen(cmd, "r")) != NULL) {
+ (void)fgets( line, sizeof line, fp);
+ pclose(fp);
+ if ( line[strlen(line)-1] == '\n' )
+ line[strlen(line)-1] = 0;
+ if ( strcmp( line, "0") != 0 )
+ return(1);
+ }
+ return(0);
+}
+
+
+int
+flush_iptables_user(char *arg1, char *arg2) {
+
+ FILE *fp;
+ char cmd[BSIZE];
+ char *substring;
+ char line[BSIZE];
+ int i;
+
+ char *delim = " ";
+ char **tokens = NULL;
+
+ if ( (i = status_iptables_user(arg1)) == 0)
+ return(1);
+
+ substring = (char*) malloc(strlen(arg2));
+ strncpy(substring, arg2+13, strlen(arg2));
+
+ if ( strcmp( substring, "no") == 0 ) {
+ sprintf( cmd, "%s -L OUTPUT --line-numbers -n %s | grep TCOS_TNC | awk '{if ($(NF-3) == %d || $(NF-3) == \"%s\") print $1}' | tac | tr \"\\n\" \" \"", IPTABLES, DEVNULL, (int)get_uid(arg1), arg1);
+ }
+ else {
+ sprintf( cmd, "%s -L OUTPUT --line-numbers -n %s | grep TCOS_TNC | awk '{if (($(NF-3) == %d || $(NF-3) == \"%s\") && ($3 == \"tcp\")) print $1}' | tac | tr \"\\n\" \" \"", IPTABLES, DEVNULL, (int)get_uid(arg1), arg1);
+ }
+
+ free(substring);
+
+ if ((fp=(FILE*)popen(cmd, "r")) != NULL) {
+ (void)fgets( line, sizeof line, fp);
+ pclose(fp);
+ if( line[strlen(line)-1] == '\n' )
+ line[strlen(line)-1] = 0;
+
+ tokens = split(line, delim);
+ for(i = 0; tokens[i] != NULL; i++){
+ sprintf( cmd, "%s -D OUTPUT %s %s", IPTABLES, tokens[i], DEVNULL);
+#ifdef DEBUG
+ debug("flush_iptables_user() %s\n",cmd);
+#endif
+ if ((fp=(FILE*)popen(cmd, "r")) != NULL)
+ pclose(fp);
+ }
+ for(i = 0; tokens[i] != NULL; i++) {
+ free(tokens[i]);
+ }
+ free(tokens);
+ return(1);
+ }
+ return(0);
+}
+
+
+int
+add_iptables_user(char **args) {
+
+ FILE *fp;
+ char cmd[BSIZE];
+ char *substring;
+ char dirred[BSIZE];
+ int i=0,j;
+
+ char *delim = ",";
+ char **tokens = NULL;
+
+ /* Delete rules that already exists for user*/
+ flush_iptables_user(args[5], args[2]);
+
+
+ /* Obtain network destination */
+ sprintf( cmd, "ip route %s | awk '{if ($3 == \"%s\") print $1}'", DEVNULL, args[4]);
+#ifdef DEBUG
+ debug("add_iptables_user() dired cmd=%s\n",cmd);
+#endif
+ if ((fp=(FILE*)popen(cmd, "r")) != NULL) {
+ (void)fgets( dirred, sizeof dirred, fp);
+ pclose(fp);
+ if( dirred[strlen(dirred)-1] == '\n' )
+ dirred[strlen(dirred)-1] = 0;
+ }
+ else {
+ return(0);
+ }
+
+ /* block ports if especified*/
+ if(strstr(args[3], "--ports=")) {
+ substring = (char*) malloc(strlen(args[3]));
+ strncpy(substring, args[3]+8, strlen(args[3]));
+#ifdef DEBUG
+ debug("add_iptables_user() substring='%s'\n",substring);
+#endif
+
+ tokens = split(substring, delim);
+ for(j = 0; tokens[j] != NULL; j++){
+ if (check_port(tokens[j]) == 0) {
+ sprintf( cmd, "%s -A OUTPUT -p tcp --dport %s -m owner --uid-owner %s -m comment --comment TCOS_TNC -j DROP %s", IPTABLES, tokens[j], args[5], DEVNULL);
+#ifdef DEBUG
+ debug("add_iptables_user() cmd=%s\n",cmd);
+#endif
+ if ((fp=(FILE*)popen(cmd, "r")) != NULL)
+ pclose(fp);
+ }
+ }
+
+ for(j = 0; tokens[j] != NULL; j++) {
+ free(tokens[j]);
+ }
+ free(tokens);
+ free(substring);
+ i=1;
+ }
+
+ substring = (char*) malloc(strlen(args[2]));
+ strncpy(substring, args[2]+13, strlen(args[2]));
+#ifdef DEBUG
+ debug("add_iptables_user() only-ports='%s'\n",substring);
+#endif
+
+ if ( strcmp( substring, "no") == 0 ) {
+ /* Allow loopback for user*/
+ sprintf( cmd, "%s -A OUTPUT -d 127.0.0.0/8 -m owner --uid-owner %s -m comment --comment TCOS_TNC -j ACCEPT %s", IPTABLES, args[5], DEVNULL);
+#ifdef DEBUG
+ debug("add_iptables_user() cmd=%s\n",cmd);
+#endif
+ if ((fp=(FILE*)popen(cmd, "r")) != NULL) {
+ i=1;
+ pclose(fp);
+ }
+ else {
+ return(0);
+ }
+
+ /* Block output ! network*/
+ sprintf( cmd, "%s -A OUTPUT -d ! %s -m owner --uid-owner %s -m comment --comment TCOS_TNC -j DROP %s", IPTABLES, dirred, args[5], DEVNULL);
+#ifdef DEBUG
+ debug("add_iptables_user() cmd=%s\n",cmd);
+#endif
+ if ((fp=(FILE*)popen(cmd, "r")) != NULL) {
+ i=1;
+ pclose(fp);
+ }
+ else {
+ return(0);
+ }
+ }
+
+ free(substring);
+ return i;
+}
+
+char
+*ip_by_eth(char *dev) {
+ struct ifaddrs *ifaddr, *ifa;
+ int family, s;
+ static char host[255]="error";
+
+ if (getifaddrs(&ifaddr) == -1) {
+ perror("getifaddrs");
+ return host;
+ }
+
+ for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
+ family = ifa->ifa_addr->sa_family;
+ if( strcmp( dev, ifa->ifa_name) == 0 ) {
+ if (family == AF_INET) {
+ s = getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in),
+ host, 255, NULL, 0, 1);
+ if (s != 0) {
+ return "error";
+ }
+ /*fprintf(stderr, "iface=%s ip=%s\n", ifa->ifa_name, host);*/
+ return host;
+ }
+ }
+ }
+
+ freeifaddrs(ifaddr);
+ return host;
+}
+
+int
+add_route( char **args ) {
+
+ struct rtentry route;
+ int i = 1;
+ int fd;
+
+ create_route(&route, args);
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return 0;
+
+
+ /* del the route if its set before */
+ ioctl( fd, SIOCDELRT, &route );
+ if( ioctl( fd, SIOCADDRT, &route ) < 0) {
+ i = 0;
+ }
+
+ close( fd );
+ return i;
+}
+
+
+int
+del_route(char **args) {
+
+ struct rtentry route;
+ int i = 1;
+ int fd;
+
+ create_route(&route, args);
+
+ if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
+ return 0;
+
+
+ /* del the route if its set before */
+ if (ioctl( fd, SIOCDELRT, &route ) < 0) {
+ i = 0;
+ }
+
+ close( fd );
+ return i;
+}
+
+
+int main(int argc, char **argv) {
+ int i=0;
+ i = check_user();
+
+ if (argc < 2) {
+ return(1);
+ }
+
+ if (i == 0) {
+ printf("denied");
+ return(1);
+ }
+
+
+ if ( strcmp( argv[1], "disable-internet") == 0 && argc == 6) {
+ i = add_iptables_user(argv);
+ if (i == 0) {
+ flush_iptables_user(argv[5], argv[2]);
+ printf("disable-error");
+ }
+ else {
+ printf("disabled");
+ }
+ }
+ else if ( strcmp( argv[1], "enable-internet") == 0 && argc == 4) {
+ i = flush_iptables_user(argv[3], argv[2]);
+ if (i == 0) {
+ printf("enable-error");
+ }
+ else {
+ printf("enabled");
+ }
+
+ }
+ else if ( strcmp( argv[1], "status") == 0 && argc == 3) {
+ i = status_iptables_user(argv[2]);
+ if (i == 0) {
+ printf("enabled");
+ }
+ else {
+ printf("disabled");
+ }
+ }
+ else if ( strcmp( argv[1], "route-add") == 0 && argc == 5) {
+ i = add_route(argv);
+ if (i == 0) {
+ printf("error");
+ }
+ else {
+ printf("ok");
+ }
+ }
+ else if ( strcmp( argv[1], "route-del") == 0 && argc == 5) {
+ i = del_route(argv);
+ if (i == 0) {
+ printf("error");
+ }
+ else {
+ printf("ok");
+ }
+ }
+ else if ( strcmp( argv[1], "ip") == 0 && argc == 3) {
+ /*fprintf(stderr, "ip_by_eth(%s)=%s\n", argv[2], ip_by_eth(argv[2]));*/
+ printf("%s\n", ip_by_eth(argv[2]));
+ }
+ else {
+ fprintf(stderr, "ERROR => Bad command line arguments\n");
+ fprintf(stderr, "tnc :: tcos-net-controller usage\n");
+ fprintf(stderr, "\t tnc disable-internet --only-ports=[yes,no] --ports=[AA,BB,CC] ethX username\n");
+ fprintf(stderr, "\t tnc enable-internet --only-ports=[yes,no] username\n");
+ fprintf(stderr, "\t tnc route-add ip-multicast netmask ethX\n");
+ fprintf(stderr, "\t tnc route-del ip-multicast netmask ethX\n");
+ fprintf(stderr, "\t tnc status username\n");
+ fprintf(stderr, "\t tnc ip [iface]\n\n");
+ return(1);
+ }
+
+ return(0);
+}
+
+
+void create_route(struct rtentry *p, char **args) {
+
+ struct sockaddr_in singw, sindst, sinmask;
+ /*char mask[]="255.255.0.0";*/
+
+ memset( &singw, 0, sizeof( struct sockaddr ) );
+ memset( &sindst, 0, sizeof( struct sockaddr ) );
+ memset( &sinmask, 0, sizeof( struct sockaddr ) );
+ singw.sin_family = AF_INET;
+ sindst.sin_family = AF_INET;
+ sinmask.sin_family = AF_INET;
+
+ sindst.sin_addr.s_addr = inet_addr( args[2] );
+ if ( strcmp( ip_by_eth(args[4]), "error") == 0 ) {
+ return;
+ }
+ singw.sin_addr.s_addr = inet_addr( ip_by_eth(args[4]) );
+ sinmask.sin_addr.s_addr = inet_addr( args[3] );
+
+ memset( p, 0, sizeof( struct rtentry ) );
+ (*p).rt_dst = *(struct sockaddr *)&sindst;
+ (*p).rt_gateway = *(struct sockaddr *)&singw;
+ (*p).rt_genmask = *(struct sockaddr *)&sinmask;
+ (*p).rt_flags = RTF_GATEWAY;
+
+}
+