From: Holger Kiehl <Holger.Kiehl@dwd.de>
To: linux-c-programming@vger.kernel.org
Subject: Sending commands via an ssh connection
Date: Wed, 16 Apr 2003 20:13:35 +0000 (GMT) [thread overview]
Message-ID: <Pine.LNX.4.44.0304162011330.18820-200000@praktifix.dwd.de> (raw)
[-- Attachment #1: Type: TEXT/PLAIN, Size: 604 bytes --]
Hello
I am trying to write an ssh client to send some commands to a remote
host via ssh. But for reasons unknown to me, this client does not
want to work correctly. It seems that the remote side does not
always get the commands, so I assume there must be something wrong
with my pty communication handling. The reason why I use a pty device
is because I want this client to be called by some daemon and ssh
needs one to enter the password.
I have attached the source code of my client, maybe someone can tell
me what I am doing wrong.
Thanks,
Holger
--
[-- Attachment #2: Type: TEXT/PLAIN, Size: 12069 bytes --]
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <signal.h>
#include <termios.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
/* External global variables */
char msg_str[4096];
long transfer_timeout = 10L;
/* Local global variables */
static int ctrl_fd = -1;
static struct timeval timeout;
/* Local function prototypes. */
static int get_reply(void),
ptym_open(char *),
ptys_open(char *),
ssh_connect(char *, char *, char *),
tty_raw(int);
static size_t pipe_write(int, char *, size_t);
static void scp_quit(void);
#define INCORRECT -1
#define SUCCESS 0
/*$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ main() $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$*/
int
main(int argc, char *argv[])
{
int cmd_length,
status;
char *cmd;
if (argc != 5)
{
(void)fprintf(stderr, "Usage: %s <host> <user> <passwd> <cmd>\n", argv[0]);
exit(1);
}
(void)fprintf(stdout, "--> Connecting...\n");
if ((status = ssh_connect(argv[1], argv[2], argv[3])) == INCORRECT)
{
(void)fprintf(stderr, "ERROR: Failed to make ssh connection (%d) : %s\n",
status, msg_str);
exit(1);
}
(void)fprintf(stdout, " -- Connected : %s\n", msg_str);
if ((status = get_reply()) != SUCCESS)
{
(void)fprintf(stderr, "ERROR: Failed to read prompt (%d) : %s\n",
status, msg_str);
exit(1);
}
(void)fprintf(stdout, "--> Sending command : %s ...\n", argv[4]);
cmd_length = strlen(argv[4]);
if ((cmd = malloc(cmd_length + 1)) == NULL)
{
(void)fprintf(stderr, "ERROR: malloc() error : %s\n", strerror(errno));
exit(1);
}
cmd[cmd_length] = '\n';
if ((status = pipe_write(ctrl_fd, argv[4], cmd_length + 1)) != cmd_length + 1)
{
(void)fprintf(stderr,
"ERROR: Failed to write() command to pipe [%d] : %s\n",
status, strerror(errno));
}
if ((status = get_reply()) != SUCCESS)
{
(void)fprintf(stderr, "ERROR: Failed to read prompt (%d) : %s\n",
status, msg_str);
exit(1);
}
scp_quit();
exit(0);
}
/*+++++++++++++++++++++++++++++ ssh_connect() +++++++++++++++++++++++++++*/
static int
ssh_connect(char *host, char *user, char *passwd)
{
int fdm, len, status, pipe_fd[2];
char pts_name[11], *ptr;
if ((fdm = ptym_open(pts_name)) < 0)
{
(void)fprintf(stderr, "ERROR: ptym_open() error.\n");
return(INCORRECT);
}
/* Prepare pipes for parent/child synchronization. */
if (pipe(pipe_fd) == -1)
{
(void)fprintf(stderr, "ERROR: pipe() error : %s\n", strerror(errno));
status = INCORRECT;
}
else
{
pid_t ctrl_pid;
if ((ctrl_pid = fork()) == 0) /* Child process */
{
char *args[5], dummy;
int fds;
setsid();
if ((fds = ptys_open(pts_name)) < 0)
{
(void)fprintf(stderr, "ERROR: ptys_open() error.\n");
(void)close(fdm);
return(INCORRECT);
}
(void)close(fdm);
(void)tty_raw(fds);
/* Synchronize with parent. */
(void)close(pipe_fd[1]);
if (read(pipe_fd[0], &dummy, 1) != 1)
{
(void)close(pipe_fd[0]);
(void)fprintf(stderr, "ERROR: read() error : %s\n", strerror(errno));
return(INCORRECT);
}
(void)close(pipe_fd[0]);
dup2(fds, STDIN_FILENO);
dup2(fds, STDOUT_FILENO);
dup2(fds, STDERR_FILENO);
if (fds > 2)
{
close(fds);
}
args[0] = "ssh";
args[1] = "-l";
args[2] = user;
args[3] = host;
args[4] = NULL;
(void)execvp("ssh", args);
(void)fprintf(stderr, "ERROR: execvp() error : %s\n",
strerror(errno));
_exit(INCORRECT);
}
else if (ctrl_pid > 0) /* Parent process. */
{
(void)tty_raw(fdm);
ctrl_fd = fdm;
/* Synchronize with child. */
(void)close(pipe_fd[0]);
if (pipe_write(pipe_fd[1], "", 1) != 1)
{
(void)fprintf(stderr, "ERROR: write() error : %s\n",
strerror(errno));
(void)close(pipe_fd[1]);
return(INCORRECT);
}
(void)close(pipe_fd[1]);
if ((status = get_reply()) == SUCCESS)
{
if (strstr(msg_str, "assword:") != NULL)
{
size_t length = strlen(passwd) + 1;
char *str_passwd;
if ((str_passwd = malloc(length)) == NULL)
{
(void)fprintf(stderr, "malloc() error\n");
exit(1);
}
(void)memcpy(str_passwd, passwd, length - 1);
str_passwd[length - 1] = '\n';
if ((status = pipe_write(ctrl_fd, str_passwd, length)) != length)
{
if (errno != 0)
{
(void)fprintf(stderr, "ERROR: pipe_write() error (%d) : %s\n",
status, strerror(errno));
}
status = INCORRECT;
}
else
{
if ((status = get_reply()) != SUCCESS)
{
(void)fprintf(stderr, "ERROR: get_repy() error\n");
status = INCORRECT;
}
}
}
else
{
status = INCORRECT;
}
}
else
{
(void)fprintf(stderr, "ERROR: get_reply() error (%d).\n", status);
}
}
else /* Failed to fork(). */
{
(void)fprintf(stderr, "ERROR: fork() error : %s\n", strerror(errno));
status = INCORRECT;
}
}
return(status);
}
/*+++++++++++++++++++++++++++++ scp_quit() ++++++++++++++++++++++++++++++*/
void
scp_quit(void)
{
if (ctrl_fd != -1)
{
int status;
char cmd[5];
(void)fprintf(stdout,
"--> Sending exit on control connection.\n");
cmd[0] = 'e'; cmd[1] = 'x'; cmd[2] = 'i'; cmd[3] = 't'; cmd[4] = '\n';
if ((status = pipe_write(ctrl_fd, cmd, 5)) != 5)
{
cmd[4] = '\0';
(void)fprintf(stderr,
"ERROR: Failed to write() command to pipe [%d] : %s\n",
cmd, status, strerror(errno));
status = INCORRECT;
}
else
{
if ((status = get_reply()) != SUCCESS)
{
(void)fprintf(stderr, "ERROR: Failed to read reply [%d]\n", status);
}
}
(void)close(ctrl_fd);
ctrl_fd = -1;
}
return;
}
/*----------------------------- pipe_write() ----------------------------*/
static size_t
pipe_write(int fd, char *buf, size_t count)
{
if (fd != -1)
{
int status;
fd_set wset;
/* Initialise descriptor set */
FD_ZERO(&wset);
FD_SET(fd, &wset);
timeout.tv_usec = 0L;
timeout.tv_sec = transfer_timeout;
/* Wait for message x seconds and then continue. */
status = select(fd + 1, NULL, &wset, NULL, &timeout);
if (status == 0)
{
/* Timeout has arrived. */
(void)fprintf(stderr, "There is no reply from pipe, failed to send command %s\n.", buf);
}
else if (FD_ISSET(fd, &wset))
{
return(write(fd, buf, count));
}
else
{
(void)fprintf(stderr, "ERROR: select() error : %s\n",
strerror(errno));
}
}
errno = 0;
return(INCORRECT);
}
/*----------------------------- get_reply() -----------------------------*/
static int
get_reply(void)
{
int status;
fd_set rset;
FD_ZERO(&rset);
FD_SET(ctrl_fd, &rset);
timeout.tv_usec = 0L;
timeout.tv_sec = transfer_timeout;
status = select(ctrl_fd + 1, &rset, NULL, NULL, &timeout);
if (status == 0)
{
(void)fprintf(stderr, "ERROR: select() timeout.\n");
}
else if (FD_ISSET(ctrl_fd, &rset))
{
if ((status = read(ctrl_fd, msg_str, 4096)) < 0)
{
(void)fprintf(stderr, "ERROR: read() error : %s\n",
strerror(errno));
}
else
{
msg_str[status] = '\0';
if (status == 0)
{
(void)fprintf(stderr, "ERROR: Other side closed the pipe.\n");
}
else
{
char *ptr = msg_str;
while (*ptr)
{
if (*ptr == '\n')
{
*ptr = ' ';
}
ptr++;
}
if (status == 1)
{
(void)fprintf(stdout, "<-- get_reply() reading ONE Byte %d\n",
(int)msg_str[0]);
}
else
{
(void)fprintf(stdout, "<-- get_reply() reading %d Bytes : %s\n",
status, msg_str);
}
return(SUCCESS);
}
}
}
else
{
(void)fprintf(stderr,
"ERROR: select() error : %s\n", strerror(errno));
}
return(INCORRECT);
}
/*----------------------------- ptym_open() -----------------------------*/
static int
ptym_open(char *pts_name)
{
int fd;
char *pos1, *pos2;
(void)strcpy(pts_name, "/dev/ptyXY");
for (pos1 = "pqrstuvwxyzPQRST"; *pos1 != '\0'; pos1++)
{
pts_name[8] = *pos1;
for (pos2 = "0123456789abcdef"; *pos2 != '\0'; pos2++)
{
pts_name[9] = *pos2;
if ((fd = open(pts_name, O_RDWR)) == -1)
{
if (errno == ENOENT)
{
return (-1);
}
else
{
continue;
}
}
pts_name[5] = 't';
return(fd);
}
}
return(-1);
}
/*----------------------------- ptys_open() -----------------------------*/
static int
ptys_open(char *pts_name)
{
int fds;
if ((fds = open(pts_name, O_RDWR)) < 0)
{
return(-1);
}
#if defined(TIOCSCTTY) && !defined(CIBAUD)
if (ioctl(fds, TIOCSCTTY, (char *) 0) < 0)
{
(void)close(fds);
return(-1);
}
#endif
return(fds);
}
/*------------------------------ tty_raw() ------------------------------*/
static int
tty_raw(int fd)
{
struct termios buf;
if (tcgetattr(fd, &buf) < 0)
{
return(-1);
}
buf.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
buf.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
buf.c_cflag &= ~(CSIZE | PARENB);
buf.c_cflag |= CS8;
buf.c_oflag &= ~(OPOST);
buf.c_cc[VMIN] = 1;
buf.c_cc[VTIME] = 0;
if (tcsetattr(fd, TCSANOW, &buf) < 0)
{
return(-1);
}
return(0);
}
reply other threads:[~2003-04-16 20:13 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=Pine.LNX.4.44.0304162011330.18820-200000@praktifix.dwd.de \
--to=holger.kiehl@dwd.de \
--cc=linux-c-programming@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).