bug-inetutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[bug-inetutils] [PATCH] rexec client


From: Giuseppe Scrivano
Subject: [bug-inetutils] [PATCH] rexec client
Date: Tue, 28 Jul 2009 23:11:06 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/23.0.96 (gnu/linux)

Hello,

I saw inetutils has a rexec server but it is missing a rexec client, so
I wrote one.

Regards,
Giuseppe


>From 0577ce495883b1a240c946602db2031783f37d23 Mon Sep 17 00:00:00 2001
From: Giuseppe Scrivano <address@hidden>
Date: Tue, 28 Jul 2009 17:43:45 +0200
Subject: [PATCH] rexec: new program

* configure.ac: Build rexec.
* Makefile.am: Ditto.
* doc/inetutils.texi: Document the new program.
* rexec/Makefile.am: New file.
* rexec/rexec.c: New file.
---
 Makefile.am        |    2 +-
 configure.ac       |    2 +
 doc/inetutils.texi |   34 ++++++
 rexec/Makefile.am  |   34 ++++++
 rexec/rexec.c      |  328 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 399 insertions(+), 1 deletions(-)
 create mode 100644 rexec/Makefile.am
 create mode 100644 rexec/rexec.c

diff --git a/Makefile.am b/Makefile.am
index 061af2b..7d2d1b8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -25,7 +25,7 @@ EXTRA_DIST = README-alpha paths ChangeLog.0
 SUBDIRS = lib headers libinetutils libtelnet \
        hostname inetd telnetd libls ftpd rshd rlogind uucpd rexecd syslogd \
        tftpd talkd telnet ftp rsh rcp rlogin tftp logger gwhois talk \
-       libicmp ping doc ifconfig traceroute tests
+       libicmp ping doc ifconfig traceroute rexec tests
 
 DISTCLEANFILES = pathdefs.make paths.defs
 
diff --git a/configure.ac b/configure.ac
index fdff8d3..0b8ebb5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -108,6 +108,7 @@ IU_ENABLE_CLIENT(hostname)
 IU_ENABLE_CLIENT(ping)
 IU_ENABLE_CLIENT(ping6)
 IU_ENABLE_CLIENT(rcp)
+IU_ENABLE_CLIENT(rexec)
 IU_ENABLE_CLIENT(rlogin)
 IU_ENABLE_CLIENT(rsh)
 IU_ENABLE_CLIENT(logger)
@@ -820,6 +821,7 @@ ftpd/Makefile
 hostname/Makefile
 inetd/Makefile
 rcp/Makefile
+rexec/Makefile
 rexecd/Makefile
 rlogin/Makefile
 rlogind/Makefile
diff --git a/doc/inetutils.texi b/doc/inetutils.texi
index 86360fd..555508f 100644
--- a/doc/inetutils.texi
+++ b/doc/inetutils.texi
@@ -34,6 +34,7 @@
 * logger: (inetutils)logger invocation.           Send messages to the system 
log.
 * ping: (inetutils)ping invocation.               Packets to network hosts.
 * rcp: (inetutils)rcp invocation.                 Remote copy
+* rexec: (inetutils)rexec invocation.             Remote execution client.
 * rexecd: (inetutils)rexecd invocation.           Remote execution server.
 * rlogin: (inetutils)rlogin invocation.           Remote login.
 * rlogind: (inetutils)rlogind invocation.         Remote login server.
@@ -107,6 +108,7 @@ Clients
 * tftp invocation::                    TFTP client.
 * rsh invocation::                     Remote shell.
 * rlogin invocation::                  Remote login.
+* rexec invocation::                   Remote execution client.
 * rcp invocation::                     Remote copy
 * talk invocation::                    Talk client.
 * telnet invocation::                  User interface to TELNET.
@@ -1751,6 +1753,38 @@ The destination user and hostname may have to be 
specified as
 @samp{rhost.rname} when the destination machine is running the 4.2BSD
 version of @command{rcp}.
 
address@hidden rexec invocation
address@hidden @command{talk}: a remote execution program
address@hidden talk
+
address@hidden is a program that executes a program on another host.
+
address@hidden Invoking
+
+The command line arguments are as follows:
+
address@hidden @var
address@hidden --error
+Specify the TCP port to use for stderr redirection, in case it is not
+specified a random port will be used.
+
address@hidden --host
+Specify the host where connect to.
+
address@hidden --noerr
+If specified, an error stream will not be created.
+
address@hidden --password
+Specify the password for logging-in.
+
address@hidden --port
+Specify to which port connect to, if it is not specified by default
+use 512.
+
address@hidden --user
+Specify the user to log into the server.
address@hidden table
+
 @node talk invocation
 @chapter @command{talk}: a communication program
 @cindex talk
diff --git a/rexec/Makefile.am b/rexec/Makefile.am
new file mode 100644
index 0000000..49a69cb
--- /dev/null
+++ b/rexec/Makefile.am
@@ -0,0 +1,34 @@
+# Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc.
+# This file is part of GNU Inetutils.
+#
+# GNU Inetutils 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 3, or (at your option)
+# any later version.
+#
+# GNU Inetutils is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR 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 GNU Inetutils; see the file COPYING.  If not, write
+# to the Free Software Foundation, Inc., 51 Franklin Street,
+# Fifth Floor, Boston, MA 02110-1301 USA.
+
+bin_PROGRAMS = @rexec_BUILD@
+
+EXTRA_PROGRAMS = rexec
+
+rexec_SOURCES = rexec.c
+
+noinst_HEADERS = 
+
address@hidden@
+
+INCLUDES = -I$(top_srcdir)/lib -I../lib -I$(top_srcdir)/libinetutils 
+AM_CPPFLAGS = $(PATHDEF_DEFPATH) $(PATHDEF_BSHELL)
+
+LIBCRYPT = @LIBCRYPT@
+
+LDADD = -L../libinetutils -linetutils -L../lib -lgnu $(LIBCRYPT)
diff --git a/rexec/rexec.c b/rexec/rexec.c
new file mode 100644
index 0000000..3819af1
--- /dev/null
+++ b/rexec/rexec.c
@@ -0,0 +1,328 @@
+/*
+  Copyright (C) 2009 Free Software Foundation, Inc.
+
+  This file is part of GNU Inetutils.
+
+  GNU Inetutils 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 3 of the License, or
+  (at your option) any later version.
+
+  GNU Inetutils 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, see <http://www.gnu.org/licenses/>.
+*/
+
+/* Written by Giuseppe Scrivano <address@hidden>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_FILIO_H
+# include <sys/filio.h>
+#endif
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#include <stdarg.h>
+#include <progname.h>
+#include <argp.h>
+#include <error.h>
+#include "libinetutils.h"
+
+#define MAX3(a, b, c) (MAX (MAX (a, b), c))
+
+const char doc[] = "remote execution client";
+static char args_doc[] = "COMMAND";
+
+const char *program_authors[] =
+  {
+    "Giuseppe Scrivano",
+    NULL
+  };
+
+static struct argp_option options[] = {
+  {"user",  'u', "user", 0, "Specify the user"},
+  {"host",  'h', "host", 0, "Specify the host"},
+  {"password",  'p', "password", 0, "Specify the password"},
+  {"port",  'P', "port", 0, "Specify the port to connect to"},
+  {"noerr", 'n', NULL, 0, "Disable the stderr stream"},
+  {"error",  'e', "error", 0, "Specify a TCP port to use for stderr"},
+  { 0 }
+};
+
+struct arguments
+{
+  const char *host;
+  const char *user;
+  const char *password;
+  const char *command;
+  int port;
+  int use_err;
+  int err_port;
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+  struct arguments *arguments = state->input;
+
+  switch (key)
+    {
+    case 'u':
+      arguments->user = arg;
+      break;
+    case 'p':
+      arguments->password = arg;
+      break;
+    case 'P':
+      arguments->port = atoi (arg);
+      break;
+    case 'e':
+      arguments->err_port = atoi (arg);
+      break;
+    case 'h':
+      arguments->host = arg;
+      break;
+    case 'n':
+      arguments->use_err = 0;
+      break;
+    case ARGP_KEY_ARG:
+      arguments->command = arg;
+      state->next = state->argc;
+    }
+
+  return 0;
+}
+
+static struct argp argp = {options, parse_opt, args_doc, doc};
+
+static void do_rexec (struct arguments *arguments);
+
+int
+main (int argc, char **argv)
+{
+  struct arguments arguments;
+     
+  set_program_name (argv[0]);
+
+  iu_argp_init ("rexec", program_authors);
+
+  arguments.user = NULL;
+  arguments.password = NULL;
+  arguments.host = NULL;
+  arguments.command = NULL;
+  arguments.err_port = 0;
+  arguments.use_err = 1;
+  arguments.port = 512;
+
+  argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, &arguments);
+
+  if (arguments.user == NULL)
+    error (EXIT_FAILURE, 0, "user not specified");
+
+  if (arguments.password == NULL)
+    error (EXIT_FAILURE, 0, "password not specified");
+
+  if (arguments.host == NULL)
+    error (EXIT_FAILURE, 0, "host not specified");
+
+  if (arguments.command == NULL)
+    error (EXIT_FAILURE, 0, "command not specified");
+
+  do_rexec (&arguments);
+
+  exit (0);
+}
+
+static void
+safe_write (int socket, const char *str, size_t len)
+{
+  if (write (socket, str, len) < 0)
+    error (EXIT_FAILURE, errno, "error sending data");
+}
+
+void
+do_rexec (struct arguments *arguments)
+{
+  int err;
+  char buffer[1024];
+  int sock;
+  char port_str[6];
+  struct sockaddr_in addr;
+  struct hostent *host;
+  int stdin = STDIN_FILENO;
+  int err_sock = -1;
+
+  sock = socket (AF_INET, SOCK_STREAM, 0);
+  if (sock < 0)
+    error (EXIT_FAILURE, errno, "cannot open socket");
+
+  host = gethostbyname (arguments->host);
+
+  if (host == NULL)
+    error (EXIT_FAILURE, errno, "cannot find host");
+
+  memset (&addr, 0, sizeof (addr));
+
+  addr.sin_family = AF_INET;
+  memmove ((caddr_t) &addr.sin_addr,
+#ifdef HAVE_STRUCT_HOSTENT_H_ADDR_LIST
+              host->h_addr_list[0],
+#else
+              host->h_addr,
+#endif
+              host->h_length);
+
+  addr.sin_port = htons ((short)arguments->port);
+
+  if (connect (sock, &addr, sizeof (addr)) < 0)
+    error (EXIT_FAILURE, errno, "cannot connect to the specified host");
+
+  if (!arguments->use_err)
+    {
+      port_str[0] = '0';
+      port_str[1] = '\0';
+      safe_write (sock, port_str, 2);
+      arguments->err_port = 0;
+    }
+  else
+    {
+      struct sockaddr_in serv_addr;
+      socklen_t len;
+      int serv_sock = socket (AF_INET, SOCK_STREAM, 0);
+
+      if (serv_sock < 0)
+        error (EXIT_FAILURE, errno, "cannot open socket");
+
+      memset (&serv_addr, 0, sizeof (serv_addr));
+
+      serv_addr.sin_port = arguments->err_port;
+      if (bind (serv_sock, &serv_addr, sizeof (serv_addr)) < 0)
+        error (EXIT_FAILURE, errno, "cannot bind socket");
+
+      len = sizeof (serv_addr);
+      if (getsockname (serv_sock, &serv_addr, &len))
+        error (EXIT_FAILURE, errno, "error reading socket port");
+
+      arguments->err_port = ntohs (serv_addr.sin_port);
+
+      if (listen (serv_sock, 1))
+        error (EXIT_FAILURE, errno, "error listening on socket");
+
+      sprintf (port_str, "%i", arguments->err_port);
+      safe_write (sock, port_str, strlen (port_str) + 1);
+
+      err_sock = accept (serv_sock, &serv_addr, &len);
+
+      if (err_sock < 0)
+        error (EXIT_FAILURE, errno, "error accepting connection");
+
+      shutdown (err_sock, SHUT_WR);
+      
+      close (serv_sock);
+    }    
+
+  safe_write (sock, arguments->user, strlen (arguments->user) + 1);
+  safe_write (sock, arguments->password, strlen (arguments->password) + 1);
+  safe_write (sock, arguments->command, strlen (arguments->command) + 1);
+
+  while (1)
+    {
+      int ret;
+      fd_set rsocks;
+
+      /* No other data to read.  */
+      if (sock < 0 && err_sock < 0)
+        break;
+
+      FD_ZERO (&rsocks);
+      if (0 <= sock)
+        FD_SET (sock, &rsocks);
+      if (0 <= stdin)
+        FD_SET (stdin, &rsocks);
+      if (0 <= err_sock)
+        FD_SET (err_sock, &rsocks);
+
+      ret = select (MAX3 (sock, stdin, err_sock) + 1, &rsocks, NULL, NULL, 
NULL);
+
+      if (ret == -1)
+        error (EXIT_FAILURE, errno, "error select");
+
+     if (0 <= stdin && FD_ISSET (stdin, &rsocks))
+        {
+          err = read (stdin, buffer, 1024);
+
+          if (err < 0)
+            error (EXIT_FAILURE, errno, "error reading stdin");
+
+          if (!err)
+            {
+              shutdown (sock, SHUT_WR);
+              close (stdin);
+              stdin = -1;
+              continue;
+            }
+
+          if (write (STDOUT_FILENO, buffer, err) < 0)
+            error (EXIT_FAILURE, errno, "error writing");
+        }
+
+      if (0 <= sock && FD_ISSET (sock, &rsocks))
+        {
+          err = read (sock, buffer, 1024);
+
+          if (err < 0)
+            error (EXIT_FAILURE, errno, "error reading out stream");
+
+          if (!err)
+            {
+              close (sock);
+              sock = -1;
+              continue;
+            }
+
+          if (write (STDOUT_FILENO, buffer, err) < 0)
+            error (EXIT_FAILURE, errno, "error writing");
+        }
+
+     if (0 <= err_sock && FD_ISSET (err_sock, &rsocks))
+        {
+          err = read (err_sock, buffer, 1024);
+
+          if (err < 0)
+            error (EXIT_FAILURE, errno, "error reading err stream");
+
+          if (!err)
+            {
+              close (err_sock);
+              err_sock = -1;
+              continue;
+            }
+
+          if (write (STDERR_FILENO, buffer, err) < 0)
+            error (EXIT_FAILURE, errno, "error writing");
+        }
+    }
+}
-- 
1.6.3.3





reply via email to

[Prev in Thread] Current Thread [Next in Thread]