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 <[email protected]> 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}. +...@node rexec invocation +...@chapter @command{talk}: a remote execution program +...@cindex talk + +...@command{rexec} is a program that executes a program on another host. + +...@section Invoking + +The command line arguments are as follows: + +...@table @var +...@item --error +Specify the TCP port to use for stderr redirection, in case it is not +specified a random port will be used. + +...@item --host +Specify the host where connect to. + +...@item --noerr +If specified, an error stream will not be created. + +...@item --password +Specify the password for logging-in. + +...@item --port +Specify to which port connect to, if it is not specified by default +use 512. + +...@item --user +Specify the user to log into the server. +...@end 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 = + +...@pathdefs_make@ + +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 <[email protected]>. */ + +#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
