Example #1
0
int execute_cmd(char *cmd, int in)
{
    char *p = cmd;
    char *start_cmd = cmd;
    int pipefd[2];
    while (*p) {
        switch (*p) {
            case '|':
                *p++ = 0;
                //创建一个管道
                pipe(pipefd);
                //下面的语句执行后,程序分叉,第一叉在当前捕获的命令,第二
                //叉在后面继续解析命令
                //将写管道传给当前捕获的命令用于重定向其stdout
                if (fork_and_exec(start_cmd, in, pipefd[1]) > 0) {
                    //将读管道传给将要被捕获的命令用于重定向其stdin
                    goto call_forward_pipe_chain;
                }
                break;
            default:
                p++;
        }
    }
    fork_and_exec(start_cmd, in, -1);
    fflush(stdout);
    return 0;
call_forward_pipe_chain:
    execute_cmd(p, pipefd[0]);
    fflush(stdout);
    return 0;
}
Example #2
0
static void
do_help (saver_screen_info *ssi)
{
  saver_info *si = ssi->global;
  saver_preferences *p = &si->prefs;
  char *help_command = 0;

  if (!p->load_url_command || !*p->load_url_command)
    {
      fprintf (stderr, "%s: no URL command has been specified.\n", blurb());
      return;
    }
  if (!p->help_url || !*p->help_url)
    {
      fprintf (stderr, "%s: no Help URL has been specified.\n", blurb());
      return;
    }

  help_command = (char *) malloc (strlen (p->load_url_command) +
				  (strlen (p->help_url) * 4) + 10);
  sprintf (help_command, p->load_url_command,
           p->help_url, p->help_url, p->help_url, p->help_url);

  fork_and_exec (ssi, help_command);
  free (help_command);
}
void VMError::show_message_box(char *buf, int buflen) {
  bool yes;
  do {
    error_string(buf, buflen);
    int len = (int)strlen(buf);
    char *p = &buf[len];

    jio_snprintf(p, buflen - len,
               "\n\n"
               "Do you want to debug the problem?\n\n"
               "To debug, run 'gdb /proc/%d/exe %d'; then switch to thread " INTX_FORMAT "\n"
               "Enter 'yes' to launch gdb automatically (PATH must include gdb)\n"
               "Otherwise, press RETURN to abort...",
               os::current_process_id(), os::current_process_id(),
               os::current_thread_id());

    yes = os::message_box("Unexpected Error", buf);

    if (yes) {
      // yes, user asked VM to launch debugger
      jio_snprintf(buf, buflen, "gdb /proc/%d/exe %d", 
                   os::current_process_id(), os::current_process_id());

      fork_and_exec(buf);
    }
  } while (yes);
}
Example #4
0
static void
do_prefs (saver_screen_info *ssi)
{
  saver_info *si = ssi->global;
  saver_preferences *p = &si->prefs;
  const char *cmd = p->prefs_command;

  if (command && *command)
    fork_and_exec (ssi, cmd);
  else
    fprintf (stderr, "%s: no preferences command has been specified.\n",
             blurb());
}
Example #5
0
int		do_pipes(t_dlist *list, char ***env)
{
  t_pipes	var;

  init_function_pipe(&var);
  while (var.i < list->taille)
    {
      if (list->begin->s != NULL && list->begin->s[0] == '<')
        {
	  list->begin = list->begin->next;
	  if ((var.fd_in = redirection_left(list, &var.i, &var.j)) == -1)
            return (0);
        }
      if (do_next_command(list->begin, list->end, &var) == -1)
	return (0);
      if (var.j == 0)
	fork_and_exec(list->begin, env, var.fd_in, var.fd_out);
      else
	var.j = fork_and_exec(list->begin->prev, env, var.fd_in, var.fd_out);
      close_function_pipe(&var);
      list->begin = list->begin->next;
    }
  return (0);
}
Example #6
0
int main()
{

char cmdline[1024];
char *args[64];
char * pathArgs[64];
char fullcmd [100];
int i;

printf("%s","This is a Simple Shell \n");

	while(1)
	{
		i = 0;
		print_prompt();
//		printf("%s", "test 1");
		read_command(cmdline);
//		printf("%s", "test 2");
//		printf("After read_command %s \n", buf);
		

		parse_command(cmdline, args);
//		printf("%s", "test 3");
//		printf("After parse_command %s \n", buf);
//		printf("After parse_comamnd %s \n", args);
//		printf("More curiosity \n");
		file_find(pathArgs, cmdline, fullcmd);
		 // while (pathArgs[i] != NULL){
		 // 	strcat(pathArgs[i], "/");
		 //  	//printf("args [i] is: %s/ls\n", pathArgs[i]);
		 //  	i++;
		 // }
//		printf("After file_find %s \n", args);		
//		printf("%s", "test 4");		
//		printf("%s", *args);
		fork_and_exec(args, fullcmd);
		//printf("After fork %s", buf);	
		//printf("%s", "test 5 \n");	

	return 0;
}
}
Example #7
0
int
main (int argc, char *const *argv)
{
    char *sbin_iptables;
    char *bin_vpn;
    char *bin_exit;
    char *bin_dns;
    char *srv_dns;
    struct stat s;
    gid_t my_gid;
    char *const iptables_args[] =
    {
        "iptables", "-t", "mangle", "-L", "-v", NULL
    };

    if (0 == access ("/sbin/iptables", X_OK))
        sbin_iptables = "/sbin/iptables";
    else if (0 == access ("/usr/sbin/iptables", X_OK))
        sbin_iptables = "/usr/sbin/iptables";
    else
    {
        fprintf (stderr,
                 "Executable iptables not found in approved directories: %s, skipping\n",
                 strerror (errno));
        return 0;
    }

    if (0 != fork_and_exec (sbin_iptables, iptables_args))
    {
        fprintf (stderr,
                 "Failed to run `iptables -t mangle -L -v'. Skipping test.\n");
        return 0;
    }

    if (0 != ACCESS ("/dev/net/tun", R_OK))
    {
        GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
                                  "access",
                                  "/dev/net/tun");
        fprintf (stderr,
                 "WARNING: System unable to run test, skipping.\n");
        return 0;
    }

    bin_vpn = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-vpn");
    bin_exit = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-exit");
    bin_dns = GNUNET_OS_get_libexec_binary_path ("gnunet-helper-dns");
    srv_dns = GNUNET_OS_get_libexec_binary_path ("gnunet-service-dns");
    if ( (0 != geteuid ()) &&
            ( (GNUNET_YES !=
               GNUNET_OS_check_helper_binary (bin_vpn, GNUNET_YES, "-d gnunet-vpn - - 169.1.3.3.7 255.255.255.0")) || //ipv4 only please!
              (GNUNET_YES !=
               GNUNET_OS_check_helper_binary (bin_exit, GNUNET_YES, "-d gnunet-vpn - - - 169.1.3.3.7 255.255.255.0")) || //no nat, ipv4 only
              (GNUNET_YES !=
               GNUNET_OS_check_helper_binary (bin_dns, GNUNET_YES, NULL))) ) // TODO: once we have a windows-testcase, add test parameters here
    {
        fprintf (stderr,
                 "WARNING: gnunet-helper-{exit,vpn,dns} binaries in $PATH are not SUID, refusing to run test (as it would have to fail).\n");
        fprintf (stderr,
                 "Change $PATH ('.' in $PATH before $GNUNET_PREFIX/bin is problematic) or permissions (run 'make install' as root) to fix this!\n");
        GNUNET_free (bin_vpn);
        GNUNET_free (bin_exit);
        GNUNET_free (bin_dns);
        GNUNET_free (srv_dns);
        return 0;
    }
    GNUNET_free (bin_vpn);
    GNUNET_free (bin_exit);
    my_gid = getgid ();
    if ( (0 != stat (bin_dns, &s)) ||
            (my_gid == s.st_gid) ||
            ( (0 == (S_ISUID & s.st_mode)) && (0 != getuid()) ) )
    {
        fprintf (stderr,
                 "WARNING: %s has wrong permissions (%d, %d, %d), refusing to run test (as it would have to fail).\n",
                 bin_dns,
                 (0 != stat (bin_dns, &s)),
                 (my_gid == s.st_gid),
                 (0 == (S_ISUID & s.st_mode)) || (0 != getuid()) );
        GNUNET_free (bin_dns);
        GNUNET_free (srv_dns);
        return 0;
    }
    if ( (0 != stat (srv_dns, &s)) ||
            (my_gid == s.st_gid) ||
            (0 == (S_ISGID & s.st_mode)) )
    {
        fprintf (stderr,
                 "WARNING: %s has wrong permissions (%d, %d, %d), refusing to run test (as it would have to fail).\n",
                 srv_dns,
                 (0 != stat (bin_dns, &s)),
                 (my_gid == s.st_gid),
                 (0 == (S_ISGID & s.st_mode)) );
        GNUNET_free (bin_dns);
        GNUNET_free (srv_dns);
        return 0;
    }
    GNUNET_free (bin_dns);
    GNUNET_free (srv_dns);

    dest_ip = "169.254.86.1";
    dest_af = AF_INET;
    src_af = AF_INET;

    if (GNUNET_OK == GNUNET_NETWORK_test_pf (PF_INET6))
        use_v6 = GNUNET_YES;
    else
        use_v6 = GNUNET_NO;

    if ( (GNUNET_OK != GNUNET_NETWORK_test_pf (src_af)) ||
            (GNUNET_OK != GNUNET_NETWORK_test_pf (dest_af)) )
    {
        fprintf (stderr,
                 "Required address families not supported by this system, skipping test.\n");
        return 0;
    }
    if (0 != curl_global_init (CURL_GLOBAL_WIN32))
    {
        fprintf (stderr, "failed to initialize curl\n");
        return 2;
    }


    if (0 != GNUNET_TESTING_peer_run ("test-gnunet-vpn",
                                      "test_gns_vpn.conf",
                                      &run, NULL))
        return 1;
    GNUNET_DISK_directory_remove ("/tmp/gnunet-test-vpn");
    return global_ret;
}
Example #8
0
static void
run (void *cls,
     const struct GNUNET_CONFIGURATION_Handle *cfg,
     struct GNUNET_TESTING_Peer *peer)
{
    enum MHD_FLAG flags;

    char *bin;
    char *bin_identity;
    char *bin_gns;
    char *config;

    if (GNUNET_OK !=
            GNUNET_CONFIGURATION_get_value_string (cfg,
                    "arm",
                    "CONFIG",
                    &config))
    {
        fprintf (stderr,
                 "Failed to locate configuration file. Skipping test.\n");
        GNUNET_SCHEDULER_shutdown ();
        return;
    }

    char *const identity_args[] =
    {
        "gnunet-identity",
        "-C", "master-zone",
        "-c", config,
        NULL
    };
    char *const identity2_args[] =
    {
        "gnunet-identity",
        "-e", "master-zone",
        "-s", "gns-master",
        "-c", config,
        NULL
    };
    char *const identity3_args[] =
    {
        "gnunet-identity",
        "-e", "master-zone",
        "-s", "gns-intercept",
        "-c", config,
        NULL
    };
    char *const gns_args[] =
    {
        "gnunet-gns",
        "-u", "www.gns",
        "-c", config,
        NULL
    };
    GNUNET_TESTING_peer_get_identity (peer, &id);
    GNUNET_SCHEDULER_add_delayed (TIMEOUT,
                                  &do_shutdown,
                                  NULL);
    bin = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR);
    GNUNET_asprintf (&bin_identity,
                     "%s/%s",
                     bin,
                     "gnunet-identity");
    if (0 != fork_and_exec (bin_identity, identity_args))
    {
        fprintf (stderr,
                 "Failed to run `gnunet-identity -C. Skipping test.\n");
        GNUNET_SCHEDULER_shutdown ();
        GNUNET_free (bin_identity);
        GNUNET_free (config);
        GNUNET_free (bin);
        return;
    }
    if (0 != fork_and_exec (bin_identity, identity2_args))
    {
        fprintf (stderr,
                 "Failed to run `gnunet-identity -e. Skipping test.\n");
        GNUNET_SCHEDULER_shutdown ();
        GNUNET_free (bin_identity);
        GNUNET_free (config);
        GNUNET_free (bin);
        return;
    }
    if (0 != fork_and_exec (bin_identity, identity3_args))
    {
        fprintf (stderr,
                 "Failed to run `gnunet-identity -e. Skipping test.\n");
        GNUNET_SCHEDULER_shutdown ();
        GNUNET_free (bin_identity);
        GNUNET_free (config);
        GNUNET_free (bin);
        return;
    }
    GNUNET_free (bin_identity);

    /* do lookup just to launch GNS service */
    GNUNET_asprintf (&bin_gns,
                     "%s/%s",
                     bin,
                     "gnunet-gns");
    if (0 != fork_and_exec (bin_gns, gns_args))
    {
        fprintf (stderr,
                 "Failed to run `gnunet-gns -u. Skipping test.\n");
        GNUNET_SCHEDULER_shutdown ();
        GNUNET_free (bin_gns);
        GNUNET_free (config);
        GNUNET_free (bin);
        return;
    }
    GNUNET_free (bin_gns);
    GNUNET_free (config);
    GNUNET_free (bin);


    namestore = GNUNET_NAMESTORE_connect (cfg);
    GNUNET_assert (NULL != namestore);
    flags = MHD_USE_DEBUG;
    if (GNUNET_YES == use_v6)
        flags |= MHD_USE_DUAL_STACK;
    mhd = MHD_start_daemon (flags,
                            PORT,
                            NULL, NULL,
                            &mhd_ahc, NULL,
                            MHD_OPTION_END);
    GNUNET_assert (NULL != mhd);
    mhd_main ();

    identity = GNUNET_IDENTITY_connect (cfg,
                                        &identity_cb,
                                        NULL);
}
Example #9
0
/**
 * Main function of "gnunet-helper-dns", which opens a VPN tunnel interface,
 * redirects all outgoing DNS traffic (except from the specified port) to that
 * interface and then passes traffic from and to the interface via stdin/stdout.
 *
 * Once stdin/stdout close or have other errors, the tunnel is closed and the
 * DNS traffic redirection is stopped.
 *
 * @param argc number of arguments
 * @param argv 0: binary name (should be "gnunet-helper-vpn")
 *             1: tunnel interface name (typically "gnunet-dns")
 *             2: IPv6 address for the tunnel ("FE80::1")
 *             3: IPv6 netmask length in bits ("64")
 *             4: IPv4 address for the tunnel ("1.2.3.4")
 *             5: IPv4 netmask ("255.255.0.0")
 *             6: skip sysctl, routing and iptables setup ("0")
 * @return 0 on success, otherwise code indicating type of error:
 *         1 wrong number of arguments
 *         2 invalid arguments (i.e. port number / prefix length wrong)
 *         3 iptables not executable
 *         4 ip not executable
 *         5 failed to initialize tunnel interface
 *         6 failed to initialize control pipe
 *         8 failed to change routing table, cleanup successful
 *         9-23 failed to change routing table and failed to undo some changes to routing table
 *         24 failed to drop privs
 *         25-39 failed to drop privs and then failed to undo some changes to routing table
 *         40 failed to regain privs
 *         41-55 failed to regain prisv and then failed to undo some changes to routing table
 *         254 insufficient priviledges
 *         255 failed to handle kill signal properly
 */
int
main (int argc, char *const*argv)
{
  int r;
  char dev[IFNAMSIZ];
  char mygid[32];
  int fd_tun;
  uid_t uid;
  int nortsetup = 0;

  if (7 != argc)
  {
    fprintf (stderr, "Fatal: must supply 6 arguments!\n");
    return 1;
  }

  /* assert privs so we can modify the firewall rules! */
  uid = getuid ();
#ifdef HAVE_SETRESUID
  if (0 != setresuid (uid, 0, 0))
  {
    fprintf (stderr, "Failed to setresuid to root: %s\n", strerror (errno));
    return 254;
  }
#else
  if (0 != seteuid (0))
  {
    fprintf (stderr, "Failed to seteuid back to root: %s\n", strerror (errno));
    return 254;
  }
#endif
  if (0 == strncmp (argv[6], "1", 2))
    nortsetup = 1;

  if (0 == nortsetup)
  {
    /* verify that the binaries we care about are executable */
    if (0 == access ("/sbin/iptables", X_OK))
      sbin_iptables = "/sbin/iptables";
    else if (0 == access ("/usr/sbin/iptables", X_OK))
      sbin_iptables = "/usr/sbin/iptables";
    else
    {
      fprintf (stderr,
	       "Fatal: executable iptables not found in approved directories: %s\n",
	       strerror (errno));
      return 3;
    }
    if (0 == access ("/sbin/ip6tables", X_OK))
      sbin_ip6tables = "/sbin/ip6tables";
    else if (0 == access ("/usr/sbin/ip6tables", X_OK))
      sbin_ip6tables = "/usr/sbin/ip6tables";
    else
    {
      fprintf (stderr,
	       "Fatal: executable ip6tables not found in approved directories: %s\n",
	       strerror (errno));
      return 3;
    }
    if (0 == access ("/sbin/ip", X_OK))
      sbin_ip = "/sbin/ip";
    else if (0 == access ("/usr/sbin/ip", X_OK))
      sbin_ip = "/usr/sbin/ip";
    else
    {
      fprintf (stderr,
	       "Fatal: executable ip not found in approved directories: %s\n",
	       strerror (errno));
      return 4;
    }
    if (0 == access ("/sbin/sysctl", X_OK))
      sbin_sysctl = "/sbin/sysctl";
    else if (0 == access ("/usr/sbin/sysctl", X_OK))
      sbin_sysctl = "/usr/sbin/sysctl";
    else
    {
      fprintf (stderr,
               "Fatal: executable sysctl not found in approved directories: %s\n",
               strerror (errno));
      return 5;
    }
  }

  /* setup 'mygid' string */
  snprintf (mygid, sizeof (mygid), "%d", (int) getegid());

  /* do not die on SIGPIPE */
  if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
  {
    fprintf (stderr, "Failed to protect against SIGPIPE: %s\n",
             strerror (errno));
    return 7;
  }

  /* setup pipe to shutdown nicely on SIGINT */
  if (0 != pipe (cpipe))
  {
    fprintf (stderr,
	     "Fatal: could not setup control pipe: %s\n",
	     strerror (errno));
    return 6;
  }
  if (cpipe[0] >= FD_SETSIZE)
  {
    fprintf (stderr, "Pipe file descriptor to large: %d", cpipe[0]);
    (void) close (cpipe[0]);
    (void) close (cpipe[1]);
    return 6;
  }
  {
    /* make pipe non-blocking, as we theoretically could otherwise block
       in the signal handler */
    int flags = fcntl (cpipe[1], F_GETFL);
    if (-1 == flags)
    {
      fprintf (stderr, "Failed to read flags for pipe: %s", strerror (errno));
      (void) close (cpipe[0]);
      (void) close (cpipe[1]);
      return 6;
    }
    flags |= O_NONBLOCK;
    if (0 != fcntl (cpipe[1], F_SETFL, flags))
    {
      fprintf (stderr, "Failed to make pipe non-blocking: %s", strerror (errno));
      (void) close (cpipe[0]);
      (void) close (cpipe[1]);
      return 6;
    }
  }
  if ( (SIG_ERR == signal (SIGTERM, &signal_handler)) ||
#if (SIGTERM != GNUNET_TERM_SIG)
       (SIG_ERR == signal (GNUNET_TERM_SIG, &signal_handler)) ||
#endif
       (SIG_ERR == signal (SIGINT, &signal_handler)) ||
       (SIG_ERR == signal (SIGHUP, &signal_handler)) )
  {
    fprintf (stderr,
	     "Fatal: could not initialize signal handler: %s\n",
	     strerror (errno));
    (void) close (cpipe[0]);
    (void) close (cpipe[1]);
    return 7;
  }


  /* get interface name */
  strncpy (dev, argv[1], IFNAMSIZ);
  dev[IFNAMSIZ - 1] = '\0';

  /* Disable rp filtering */
  if (0 == nortsetup)
  {
    char *const sysctl_args[] = {"sysctl", "-w",
      "net.ipv4.conf.all.rp_filter=0", NULL};
    char *const sysctl_args2[] = {"sysctl", "-w",
      "net.ipv4.conf.default.rp_filter=0", NULL};
    if ((0 != fork_and_exec (sbin_sysctl, sysctl_args)) ||
        (0 != fork_and_exec (sbin_sysctl, sysctl_args2)))
    {
      fprintf (stderr,
               "Failed to disable rp filtering.\n");
      return 5;
    }
  }


  /* now open virtual interface (first part that requires root) */
  if (-1 == (fd_tun = init_tun (dev)))
  {
    fprintf (stderr, "Fatal: could not initialize tun-interface\n");
    (void) signal (SIGTERM, SIG_IGN);
#if (SIGTERM != GNUNET_TERM_SIG)
    (void) signal (GNUNET_TERM_SIG, SIG_IGN);
#endif
    (void) signal (SIGINT, SIG_IGN);
    (void) signal (SIGHUP, SIG_IGN);
    (void) close (cpipe[0]);
    (void) close (cpipe[1]);
    return 5;
  }

  /* now set interface addresses */
  {
    const char *address = argv[2];
    long prefix_len = atol (argv[3]);

    if ((prefix_len < 1) || (prefix_len > 127))
    {
      fprintf (stderr, "Fatal: prefix_len out of range\n");
      (void) signal (SIGTERM, SIG_IGN);
#if (SIGTERM != GNUNET_TERM_SIG)
    (void) signal (GNUNET_TERM_SIG, SIG_IGN);
#endif
      (void) signal (SIGINT, SIG_IGN);
      (void) signal (SIGHUP, SIG_IGN);
      (void) close (cpipe[0]);
      (void) close (cpipe[1]);
      return 2;
    }
    set_address6 (dev, address, prefix_len);
  }

  {
    const char *address = argv[4];
    const char *mask = argv[5];

    set_address4 (dev, address, mask);
  }


  /* update routing tables -- next part why we need SUID! */
  /* Forward everything from our EGID (which should only be held
     by the 'gnunet-service-dns') and with destination
     to port 53 on UDP, without hijacking */
  if (0 == nortsetup)
  {
    r = 8; /* failed to fully setup routing table */
    {
      char *const mangle_args[] =
        {
	 "iptables", "-m", "owner", "-t", "mangle", "-I", "OUTPUT", "1", "-p",
	 "udp", "--gid-owner", mygid, "--dport", DNS_PORT, "-j",
	 "ACCEPT", NULL
        };
      if (0 != fork_and_exec (sbin_iptables, mangle_args))
        goto cleanup_rest;
    }
    {
      char *const mangle_args[] =
        {
	 "ip6tables", "-m", "owner", "-t", "mangle", "-I", "OUTPUT", "1", "-p",
	 "udp", "--gid-owner", mygid, "--dport", DNS_PORT, "-j",
	 "ACCEPT", NULL
        };
      if (0 != fork_and_exec (sbin_ip6tables, mangle_args))
        goto cleanup_mangle_1b;
    }
    /* Mark all of the other DNS traffic using our mark DNS_MARK,
       unless it is on a link-local IPv6 address, which we cannot support. */
    {
      char *const mark_args[] =
        {
	 "iptables", "-t", "mangle", "-I", "OUTPUT", "2", "-p",
	 "udp", "--dport", DNS_PORT,
         "-j", "MARK", "--set-mark", DNS_MARK,
	 NULL
        };
      if (0 != fork_and_exec (sbin_iptables, mark_args))
        goto cleanup_mangle_1;
    }
    {
      char *const mark_args[] =
        {
	 "ip6tables", "-t", "mangle", "-I", "OUTPUT", "2", "-p",
	 "udp", "--dport", DNS_PORT,
         "!", "-s", "fe80::/10", /* this line excludes link-local traffic */
         "-j", "MARK", "--set-mark", DNS_MARK,
	 NULL
        };
      if (0 != fork_and_exec (sbin_ip6tables, mark_args))
        goto cleanup_mark_2b;
    }
    /* Forward all marked DNS traffic to our DNS_TABLE */
    {
      char *const forward_args[] =
        {
	 "ip", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL
        };
      if (0 != fork_and_exec (sbin_ip, forward_args))
        goto cleanup_mark_2;
    }
    {
      char *const forward_args[] =
        {
          "ip", "-6", "rule", "add", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL
        };
      if (0 != fork_and_exec (sbin_ip, forward_args))
        goto cleanup_forward_3b;
    }
    /* Finally, add rule in our forwarding table to pass to our virtual interface */
    {
      char *const route_args[] =
        {
	 "ip", "route", "add", "default", "dev", dev,
	 "table", DNS_TABLE, NULL
        };
      if (0 != fork_and_exec (sbin_ip, route_args))
        goto cleanup_forward_3;
    }
    {
      char *const route_args[] =
        {
          "ip", "-6", "route", "add", "default", "dev", dev,
          "table", DNS_TABLE, NULL
        };
      if (0 != fork_and_exec (sbin_ip, route_args))
        goto cleanup_route_4b;
    }
  }

  /* drop privs *except* for the saved UID; this is not perfect, but better
     than doing nothing */
#ifdef HAVE_SETRESUID
  if (0 != setresuid (uid, uid, 0))
  {
    fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
    r = 24;
    goto cleanup_route_4;
  }
#else
  /* Note: no 'setuid' here as we must keep our saved UID as root */
  if (0 != seteuid (uid))
  {
    fprintf (stderr, "Failed to seteuid: %s\n", strerror (errno));
    r = 24;
    goto cleanup_route_4;
  }
#endif

  r = 0; /* did fully setup routing table (if nothing else happens, we were successful!) */

  /* now forward until we hit a problem */
  run (fd_tun);

  /* now need to regain privs so we can remove the firewall rules we added! */
#ifdef HAVE_SETRESUID
  if (0 != setresuid (uid, 0, 0))
  {
    fprintf (stderr, "Failed to setresuid back to root: %s\n", strerror (errno));
    r = 40;
    goto cleanup_route_4;
  }
#else
  if (0 != seteuid (0))
  {
    fprintf (stderr, "Failed to seteuid back to root: %s\n", strerror (errno));
    r = 40;
    goto cleanup_route_4;
  }
#endif

  /* update routing tables again -- this is why we could not fully drop privs */
  /* now undo updating of routing tables; normal exit or clean-up-on-error case */
 cleanup_route_4:
  if (0 == nortsetup)
  {
    char *const route_clean_args[] =
      {
	"ip", "-6", "route", "del", "default", "dev", dev,
	"table", DNS_TABLE, NULL
      };
    if (0 != fork_and_exec (sbin_ip, route_clean_args))
      r += 1;
  }
 cleanup_route_4b:
  if (0 == nortsetup)
  {
    char *const route_clean_args[] =
      {
	"ip", "route", "del", "default", "dev", dev,
	"table", DNS_TABLE, NULL
      };
    if (0 != fork_and_exec (sbin_ip, route_clean_args))
      r += 1;
  }
 cleanup_forward_3:
  if (0 == nortsetup)
  {
    char *const forward_clean_args[] =
      {
	"ip", "-6", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL
      };
    if (0 != fork_and_exec (sbin_ip, forward_clean_args))
      r += 2;
  }
 cleanup_forward_3b:
  if (0 == nortsetup)
  {
    char *const forward_clean_args[] =
      {
	"ip", "rule", "del", "fwmark", DNS_MARK, "table", DNS_TABLE, NULL
      };
    if (0 != fork_and_exec (sbin_ip, forward_clean_args))
      r += 2;
  }
 cleanup_mark_2:
  if (0 == nortsetup)
  {
    char *const mark_clean_args[] =
      {
	"ip6tables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp",
	"--dport", DNS_PORT,
        "!", "-s", "fe80::/10", /* this line excludes link-local traffic */
        "-j", "MARK", "--set-mark", DNS_MARK, NULL
      };
    if (0 != fork_and_exec (sbin_ip6tables, mark_clean_args))
      r += 4;
  }
 cleanup_mark_2b:
  if (0 == nortsetup)
  {
    char *const mark_clean_args[] =
      {
	"iptables", "-t", "mangle", "-D", "OUTPUT", "-p", "udp",
	"--dport", DNS_PORT, "-j", "MARK", "--set-mark", DNS_MARK, NULL
      };
    if (0 != fork_and_exec (sbin_iptables, mark_clean_args))
      r += 4;
  }
 cleanup_mangle_1:
  if (0 == nortsetup)
  {
    char *const mangle_clean_args[] =
      {
	"ip6tables", "-m", "owner", "-t", "mangle", "-D", "OUTPUT", "-p", "udp",
	 "--gid-owner", mygid, "--dport", DNS_PORT, "-j", "ACCEPT",
	NULL
      };
    if (0 != fork_and_exec (sbin_ip6tables, mangle_clean_args))
      r += 8;
  }
 cleanup_mangle_1b:
  if (0 == nortsetup)
  {
    char *const mangle_clean_args[] =
      {
	"iptables", "-m", "owner", "-t", "mangle", "-D", "OUTPUT", "-p", "udp",
	 "--gid-owner", mygid, "--dport", DNS_PORT, "-j", "ACCEPT",
	NULL
      };
    if (0 != fork_and_exec (sbin_iptables, mangle_clean_args))
      r += 8;
  }

 cleanup_rest:
  /* close virtual interface */
  (void) close (fd_tun);
  /* remove signal handler so we can close the pipes */
  (void) signal (SIGTERM, SIG_IGN);
#if (SIGTERM != GNUNET_TERM_SIG)
    (void) signal (GNUNET_TERM_SIG, SIG_IGN);
#endif
  (void) signal (SIGINT, SIG_IGN);
  (void) signal (SIGHUP, SIG_IGN);
  (void) close (cpipe[0]);
  (void) close (cpipe[1]);
  return r;
}
Example #10
0
/**
 * Open VPN tunnel interface.
 *
 * @param argc must be 6
 * @param argv 0: binary name ("gnunet-helper-exit")
 *             1: tunnel interface name ("gnunet-exit")
 *             2: IPv4 "physical" interface name ("eth0"), or "%" to not do IPv4 NAT
 *             3: IPv6 address ("::1"), or "-" to skip IPv6
 *             4: IPv6 netmask length in bits ("64") [ignored if #4 is "-"]
 *             5: IPv4 address ("1.2.3.4"), or "-" to skip IPv4
 *             6: IPv4 netmask ("255.255.0.0") [ignored if #4 is "-"]
 */
int
main (int argc, char **argv)
{
  char dev[IFNAMSIZ];
  int fd_tun;
  int global_ret;

  if (7 != argc)
  {
    fprintf (stderr, "Fatal: must supply 6 arguments!\n");
    return 1;
  }
  if ( (0 == strcmp (argv[3], "-")) &&
       (0 == strcmp (argv[5], "-")) )
  {
    fprintf (stderr, "Fatal: disabling both IPv4 and IPv6 makes no sense.\n");
    return 1;
  }
  if (0 == access ("/sbin/iptables", X_OK))
    sbin_iptables = "/sbin/iptables";
  else if (0 == access ("/usr/sbin/iptables", X_OK))
    sbin_iptables = "/usr/sbin/iptables";
  else
  {
    fprintf (stderr, 
	     "Fatal: executable iptables not found in approved directories: %s\n",
	     strerror (errno));
    return 1;
  }
  if (0 == access ("/sbin/sysctl", X_OK))
    sbin_sysctl = "/sbin/sysctl";
  else if (0 == access ("/usr/sbin/sysctl", X_OK))
    sbin_sysctl = "/usr/sbin/sysctl";
  else
  {
    fprintf (stderr,
	     "Fatal: executable sysctl not found in approved directories: %s\n",
	     strerror (errno));
    return 1;
  }

  strncpy (dev, argv[1], IFNAMSIZ);
  dev[IFNAMSIZ - 1] = '\0';

  if (-1 == (fd_tun = init_tun (dev)))
  {
    fprintf (stderr, 
	     "Fatal: could not initialize tun-interface `%s' with IPv6 %s/%s and IPv4 %s/%s\n",
	     dev,
	     argv[3],
	     argv[4],
	     argv[5],
	     argv[6]);
    return 1;
  }

  if (0 != strcmp (argv[3], "-"))
  {
    {
      const char *address = argv[3];
      long prefix_len = atol (argv[4]);
      
      if ((prefix_len < 1) || (prefix_len > 127))
      {
	fprintf (stderr, "Fatal: prefix_len out of range\n");
	return 1;
      }      
      set_address6 (dev, address, prefix_len);    
    }
    {
      char *const sysctl_args[] =
	{
	  "sysctl", "-w", "net.ipv6.conf.all.forwarding=1", NULL
	};
      if (0 != fork_and_exec (sbin_sysctl,
			      sysctl_args))
      {
	fprintf (stderr,
		 "Failed to enable IPv6 forwarding.  Will continue anyway.\n");
      }    
    }
  }

  if (0 != strcmp (argv[5], "-"))
  {
    {
      const char *address = argv[5];
      const char *mask = argv[6];
      
      set_address4 (dev, address, mask);
    }
    {
      char *const sysctl_args[] =
	{
	  "sysctl", "-w", "net.ipv4.ip_forward=1", NULL
	};
      if (0 != fork_and_exec (sbin_sysctl,
			      sysctl_args))
      {
	fprintf (stderr,
		 "Failed to enable IPv4 forwarding.  Will continue anyway.\n");
      }    
    }
    if (0 != strcmp (argv[2], "%"))
    {
      char *const iptables_args[] =
	{
	  "iptables", "-t", "nat", "-A", "POSTROUTING", "-o", argv[2], "-j", "MASQUERADE", NULL
	};
      if (0 != fork_and_exec (sbin_iptables,
			      iptables_args))
      {
	fprintf (stderr,
		 "Failed to enable IPv4 masquerading (NAT).  Will continue anyway.\n");
      }    
    }
  }
  
  uid_t uid = getuid ();
#ifdef HAVE_SETRESUID
  if (0 != setresuid (uid, uid, uid))
  {
    fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
    global_ret = 2;
    goto cleanup;
  }
#else
  if (0 != (setuid (uid) | seteuid (uid)))
  {
    fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
    global_ret = 2;
    goto cleanup;
  }
#endif

  if (SIG_ERR == signal (SIGPIPE, SIG_IGN))
  {
    fprintf (stderr, "Failed to protect against SIGPIPE: %s\n",
             strerror (errno));
    /* no exit, we might as well die with SIGPIPE should it ever happen */
  }
  run (fd_tun);
  global_ret = 0;
 cleanup:
  (void) close (fd_tun);
  return global_ret;
}