linux-c-programming.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* Sending commands via an ssh connection
@ 2003-04-16 20:13 Holger Kiehl
  0 siblings, 0 replies; only message in thread
From: Holger Kiehl @ 2003-04-16 20:13 UTC (permalink / raw)
  To: linux-c-programming

[-- 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);
}

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2003-04-16 20:13 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-04-16 20:13 Sending commands via an ssh connection Holger Kiehl

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).