Example: Client program

/**********************************************************************/
/*                                                                    */
/* Name:           qshc.c                                             */
/*                                                                    */
/* Description:    This program is a client for an interactive qsh    */
/*                 session running on a server.  The program          */
/*                 first connects to a server on the specified        */
/*                 server and sends the user name and password of     */
/*                 the client.  After the qsh session is started,     */
/*                 the program takes input from stdin and sends it    */
/*                 to the server and receives output from the server  */
/*                 and displays it on stdout.                         */
/*                                                                    */
/* Parameters:  1. Host running the qsh server (either host name or   */
/*                 IP address).                                       */
/*                                                                    */
/* Options:     1. -n to force prompt for user name and password.     */
/*              2. -p to specify port of qsh server.                  */
/*                                                                    */
/* Notes:       1. The user name and password are sent as plain text  */
/*                 to the server.                                     */
/*              2. All translations from ASCII to EBCDIC are done by  */
/*                 this program on the client.                        */
/*              3. The program includes translation tables for        */
/*                 converting between EBCDIC code page 37 (US English)*/
/*                 and ASCII code page 850 (US English).  You can     */
/*                 modify these tables to support other code pages.   */
/*                 Or if your system supports the iconv APIs, you     */
/*                 can define USE_ICONV to translate using iconv().   */
/*              4. This program has been tested on AIX(R) 4.1.5 and      */
/*                 Linux(TM) 2.0.29.                                      */
/*                                                                    */
/**********************************************************************/

/* Remove the comments from the following line to use iconv(). */
/* #define USE_ICONV 1 */

/**********************************************************************/
/* Includes                                                           */
/**********************************************************************/

#include <stdio.h>           /* perror() */
#include <sys/socket.h>      /* socket(), bind(), and so on */
#include <netinet/in.h>      /* sockaddr_in, INADDR_ANY, and so on */
#include <unistd.h>          /* close(), read(), write() and so on */
#include <stdlib.h>          /* exit() */
#include <stdlib.h>          /* exit(), memset() */
#include <sys/ioctl.h>       /* ioctl() */
#include <errno.h>           /* errno and values */
#include <string.h>          /* strlen() */
#include <arpa/inet.h>       /* inet_addr() */
#include <netdb.h>           /* gethostbyname() */
#include <pwd.h>             /* getpwuid() */
#include <signal.h>          /* sigaction(), and so on */

#ifdef _AIX
#include <sys/select.h>      /* select() */
#include <strings.h>         /* bzero() for FD_ZERO */
#endif
#ifdef __linux__
#include <sys/time.h>        /* FD_SET(), select */
#endif 

#ifdef USE_ICONV
#include <iconv.h>           /* iconv(), and so on */
#endif

/**********************************************************************/
/* Constants */
/**********************************************************************/

#define QSH_PORT 6042
#define DEFAULT_BUF 4096

/**********************************************************************/
/* Types */
/**********************************************************************/

typedef unsigned char uchar;

/**********************************************************************/
/* Global Variables                                                   */
/**********************************************************************/

char *sysname;          /* Long host name of server system */

#ifdef USE_ICONV
iconv_t ecd;            /* Conversion descriptor for ASCII to EBCDIC */
iconv_t acd;            /* Conversion descriptor for EBCDIC to ASCII */

#else
/* EBCDIC to ASCII translation table */
static uchar AsciiTable[256] =
{
  0x00,0x01,0x02,0x03,0x20,0x09,0x20,0x7f, /* 00-07 */
  0x20,0x20,0x20,0x0b,0x0c,0x0d,0x0e,0x0f, /* 08-0f */
  0x10,0x11,0x12,0x13,0x20,0x0a,0x08,0x20, /* 10-17 */
  0x18,0x19,0x20,0x20,0x20,0x1d,0x1e,0x1f, /* 18-1f */
  0x20,0x20,0x1c,0x20,0x20,0x0a,0x17,0x1b, /* 20-27 */
  0x20,0x20,0x20,0x20,0x20,0x05,0x06,0x07, /* 28-2f */
  0x20,0x20,0x16,0x20,0x20,0x20,0x20,0x04, /* 30-37 */
  0x20,0x20,0x20,0x20,0x14,0x15,0x20,0x1a, /* 38-3f */
  0x20,0x20,0x83,0x84,0x85,0xa0,0xc6,0x86, /* 40-47 */
  0x87,0xa4,0xbd,0x2e,0x3c,0x28,0x2b,0x7c, /* 48-4f */
  0x26,0x82,0x88,0x89,0x8a,0xa1,0x8c,0x8b, /* 50-57 */
  0x8d,0xe1,0x21,0x24,0x2a,0x29,0x3b,0xaa, /* 58-5f */
  0x2d,0x2f,0xb6,0x8e,0xb7,0xb5,0xc7,0x8f, /* 60-67 */
  0x80,0xa5,0xdd,0x2c,0x25,0x5f,0x3e,0x3f, /* 68-6f */
  0x9b,0x90,0xd2,0xd3,0xd4,0xd6,0xd7,0xd8, /* 70-77 */
  0xde,0x60,0x3a,0x23,0x40,0x27,0x3d,0x22, /* 78-7f */
  0x9d,0x61,0x62,0x63,0x64,0x65,0x66,0x67, /* 80-87 */
  0x68,0x69,0xae,0xaf,0xd0,0xec,0xe7,0xf1, /* 88-8f */
  0xf8,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70, /* 90-97 */
  0x71,0x72,0xa6,0xa7,0x91,0xf7,0x92,0xcf, /* 98-9f */
  0xe6,0x7e,0x73,0x74,0x75,0x76,0x77,0x78, /* a8-a7 */
  0x79,0x7a,0xad,0xa8,0xd1,0xed,0xe8,0xa9, /* a8-af */
  0x5e,0x9c,0xbe,0xfa,0xb8,0x15,0x14,0xac, /* b0-b7 */
  0xab,0xf3,0x5b,0x5d,0xee,0xf9,0xef,0x9e, /* b8-bf */
  0x7b,0x41,0x42,0x43,0x44,0x45,0x46,0x47, /* c0-c7 */
  0x48,0x49,0xf0,0x93,0x94,0x95,0xa2,0xe4, /* c8-cf */
  0x7d,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50, /* d0-d7 */
  0x51,0x52,0xfb,0x96,0x81,0x97,0xa3,0x98, /* d8-df */
  0x5c,0xf6,0x53,0x54,0x55,0x56,0x57,0x58, /* e0-e7 */
  0x59,0x5a,0xfc,0xe2,0x99,0xe3,0xe0,0xe5, /* e8-ef */
  0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, /* f0-f7 */
  0x38,0x39,0xfd,0xea,0x9a,0xeb,0xe9,0xff  /* f8-ff */
};

/* ASCII to EBCDIC translation table */
static uchar EbcdicTable[256] =
{
  0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, /* 00-07 */
  0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, /* 08-0f */
  0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, /* 10-17 */
  0x18,0x19,0x3f,0x27,0x22,0x1d,0x1e,0x1f, /* 18-1f */
  0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, /* 20-27 */
  0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, /* 28-2f */
  0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, /* 30-37 */
  0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, /* 38-3f */
  0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, /* 40-47 */
  0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, /* 48-4f */
  0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, /* 50-57 */
  0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, /* 58-5f */
  0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, /* 60-67 */
  0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, /* 68-6f */
  0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, /* 70-77 */
  0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, /* 78-7f */
  0x68,0xdc,0x51,0x42,0x43,0x44,0x47,0x48, /* 80-87 */
  0x52,0x53,0x54,0x57,0x56,0x58,0x63,0x67, /* 88-8f */
  0x71,0x9c,0x9e,0xcb,0xcc,0xcd,0xdb,0xdd, /* 90-97 */
  0xdf,0xec,0xfc,0x70,0xb1,0x80,0xbf,0x40, /* 98-9f */
  0x45,0x55,0xee,0xde,0x49,0x69,0x9a,0x9b, /* a8-a7 */
  0xab,0xaf,0x5f,0xb8,0xb7,0xaa,0x8a,0x8b, /* a8-af */
  0x40,0x40,0x40,0x40,0x40,0x65,0x62,0x64, /* b0-b7 */
  0xb4,0x40,0x40,0x40,0x40,0x4a,0xb2,0x40, /* b8-bf */
  0x40,0x40,0x40,0x40,0x40,0x40,0x46,0x66, /* c0-c7 */
  0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x9f, /* c8-cf */
  0x8c,0xac,0x72,0x73,0x74,0x89,0x75,0x76, /* d0-d7 */
  0x77,0x40,0x40,0x40,0x40,0x6a,0x78,0x40, /* d8-df */
  0xee,0x59,0xeb,0xed,0xcf,0xef,0xa0,0x8e, /* e0-e7 */
  0xae,0xfe,0xfb,0xfd,0x8d,0xad,0xbc,0xbe, /* e8-ef */
  0xca,0x8f,0x40,0xb9,0xb6,0xb5,0xe1,0x9d, /* f0-f7 */
  0x90,0xbd,0xb3,0xda,0xea,0xfa,0x40,0x40  /* f8-ff */
};
#endif /* USE_ICONV */

/**********************************************************************/
/* Function Prototypes                                                */
/**********************************************************************/

int ConvertToEBCDIC(char *, size_t, char *, size_t);
int ConvertToASCII(char *, size_t, char *, size_t);
int GetPassword(char *, char *, char *);
int Translate(uchar *, size_t, uchar *, uchar *);
void MySignalHandler(int);
void usage(void);

int main (int argc, char *argv[])
{
  struct sigaction sigact;   /* Signal action */
  int c;                     /* Option letter */
  int nflag=0;               /* True when -n option is specified */
  int port=QSH_PORT;         /* Port to connect to on server */
  int sd;                    /* Socket to server */
  fd_set read_set;           /* For select() */
  int rc;                    /* Return code */
  struct sockaddr_in svr_addr; /* AF_INET socket address */
  long ip_addr;              /* IP address of server system */
  struct in_addr host_addr;  /* Host address for gethostbyaddr() */
  char *hostname;            /* Short host name of server system */
  size_t len;                /* Length of input string */
  char *ascii_user;          /* Username in ASCII */
  char *ebcdic_user;         /* Username in EBCDIC */
  char *ascii_pwd;           /* Password in ASCII */
  char *ebcdic_pwd;          /* Password in EBCDIC */
  struct hostent *host_p;    /* Pointer to hostent structure returned by
                                gethostbyname() */
  char *ascii_buf;           /* Buffer for ASCII text */
  char *ebcdic_buf;          /* Buffer for EBCDIC text */
  int buf_size;              /* Amount of data read from server */

  /********************************************************************/
  /* Initialization. */
  /********************************************************************/

  #ifdef USE_ICONV
  /* Open the conversion descriptors for converting between ASCII and
     EBCDIC.  Assume the server job is running in CCSID 37. 
     This must be changed if the server job is running in a
     different CCSID.  The input parameters to iconv_open() may need to
     be changed depending on the operating system.  This ioonv_open() is
     coded for AIX. */
  if ((acd = iconv_open("IBM-850", "IBM-037")) < 0) {
    perror("qshc: iconv_open() failed for ASCII to EBCDIC");
    exit(1);
  }
  
  if ((ecd = iconv_open("IBM-037", "IBM-850")) < 0) {
    perror("qshc: iconv_open() failed for EBCDIC to ASCII");
    exit(1);
  }
  #endif /* USE_IOONV */

  /* Set up a signal handler for SIGINT.  The signal is sent to the
     process when the user presses <ctrl>c. */
  sigemptyset(&sigact.sa_mask);
  sigact.sa_flags = 0;
  sigact.sa_handler = MySignalHandler;
  if (sigaction(SIGINT, &sigact, NULL) != 0) {
    perror("qshc: sigaction(SIGINT) failed");
    exit(1);
  }
  
  /********************************************************************/
  /* Process the input parameters. */
  /********************************************************************/

  if (argc < 2) {
    usage();
  }

  /* Process the options. */
  while ((c = getopt(argc, argv, "hnp:")) != EOF) {
    switch (c) {
      case 'n':
        nflag = 1;
        break;
      case 'p':
        port = atoi(optarg);
        break;
      case 'h':
      default:
        usage();
        break;
    } /* End of switch */
  } /* End of while */

  /* Convert a dotted decimal address to a 32-bit IP address. */
  hostname = argv[optind];
  ip_addr = inet_addr(hostname);

  /* When inet_addr() returns -1 assume the user specified 
     a host name. */
  if (ip_addr == -1) {
    /*  Try to find the host by name. */
    host_p = gethostbyname(hostname);
    if (host_p) {
      memcpy(&ip_addr, host_p->h_addr, host_p->h_length);
      sysname = host_p->h_name;
    }
    
    else {
      fprintf(stderr, "qshc: Could not find host %s\n", hostname);
      exit(1);
    }
  } /* End of if */

  /* The user specified a IP address. */
  else {
    /* Try to find the host by address. */
    host_addr.s_addr = ip_addr;
    host_p = gethostbyaddr((char *)&host_addr.s_addr, sizeof(host_addr),
                           AF_INET);
    if (host_p) {
      sysname = host_p->h_name;
    }

    else {
      fprintf(stderr, "qshc: Could not find host %s\n", hostname);
      exit(1);
    }
  } /* End of else */

  /********************************************************************/
  /* Connect to the qsh server on the specified system. */
  /********************************************************************/
  
  /* Create a socket. */
  if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP)) < 0) {
    perror("qshc: socket() failed");
    exit(1);
  }

  /* Connect to the qsh server on the specified system. */
  memset(&svr_addr, '\0', sizeof(svr_addr));
  svr_addr.sin_family = AF_INET;
  svr_addr.sin_port = htons(port);
  svr_addr.sin_addr.s_addr = ip_addr;
  if (connect(sd, (struct sockaddr *)&svr_addr, sizeof(svr_addr)) != 0) {
    perror("qshc: connect() failed");
    exit(1);
  }

  /********************************************************************/
  /* Send the user name and password to the server. */
  /********************************************************************/

  /* Allocate buffers for translating input and output. */
  ascii_buf = (char *)malloc(DEFAULT_BUF);
  memset(ascii_buf, '\0', DEFAULT_BUF);
  ebcdic_buf = (char *)malloc(DEFAULT_BUF);
  memset(ebcdic_buf, '\0', DEFAULT_BUF);

  ascii_user = ascii_buf;
  ascii_pwd = ascii_buf + 100;
  ebcdic_user = ebcdic_buf;
  ebcdic_pwd = ebcdic_buf + 100;
  
  /* Prompt the user for the user name and password. */
  if (nflag) {
    printf("Enter user name: ");
    gets(ascii_user);
    ascii_pwd = getpass("Enter password: ");
  }
  
  /* Get the user name and password from the ~/.netrc file. */
  else {
    if (GetPassword(hostname, ascii_user, ascii_pwd) != 0) {
      fprintf(stderr, "qshc: Could not find user or password in ~/.netrc\n");
      exit(1);
    }
  }

  /* Convert the user name and password to EBCDIC. */
  if (ConvertToEBCDIC(ascii_user, strlen(ascii_user)+1, ebcdic_user, 11) < 0) {
    fprintf(stderr, "qshc: Could not convert user %s to EBCDIC\n", ascii_user);
    exit(1);
  }
  
  if (ConvertToEBCDIC(ascii_pwd, strlen(ascii_pwd)+1, ebcdic_pwd, 11) < 0) {
    fprintf(stderr, "qshc: Could not convert password %s to EBCDIC\n",
            ascii_pwd);
    exit(1);
  }
  
  /* Send the user name and password to the qsh server.  Note that the
     user name and password are sent as plain text. */
  if ((rc = write(sd, (void *)ebcdic_user, strlen(ebcdic_user)+1)) < 0) {
    perror("qshc: write() failed sending username\n");
    close(sd);
    exit(1);
  }
  
  if ((rc = write(sd, (void *)ebcdic_pwd, strlen(ebcdic_pwd)+1)) < 0) {
    perror("qshc: write() failed sending password\n");
    close(sd);
    exit(1);
  }
  printf("Started qsh session on %s\n\n", sysname);

  /********************************************************************/
  /* Process input and output between the user and the remote shell. */
  /********************************************************************/

  /* Loop forever. */
  while (1) {
    /* Select on stdin and the socket connected to the remote shell. */
    FD_ZERO(&read_set);
    FD_SET(0, &read_set);
    FD_SET(sd, &read_set);

    rc = select(sd+1, &read_set, NULL, NULL, NULL);

    if ((rc < 0) && (errno != EINTR)) {
      perror("qshc: select() failed");
      exit(1);
    }

    if (rc == 0) {
      continue;
    }

    /* Process data entered by the terminal user. */
    if (FD_ISSET(0, &read_set)) {
      /* Read the data from the terminal. */
      gets(ascii_buf);

      /* Convert the string to EBCDIC. */
      len = strlen(ascii_buf);
      if (ConvertToEBCDIC(ascii_buf, len, ebcdic_buf, DEFAULT_BUF) < 0) {
        fprintf(stderr, "qshc: Could not convert input string to EBCDIC\n");
        continue;
      }
      
      /* Put a newline on the end of the string. */
      *(ebcdic_buf+len) = 0x25;

      /* Send the data to the remote shell. */
      if (write(sd, ebcdic_buf, len+1) < 0) {
        perror("qshc: write() failed sending input");
      }
    }

    /* Process data from the remote shell. */
    if (FD_ISSET(sd, &read_set)) {
      /* Read the data from the remote shell. */
      buf_size = read(sd, ebcdic_buf, DEFAULT_BUF-1);

      /* There was a failure reading from the remote shell. */
      if (buf_size < 0) {
        perror("\nqshc: error reading data from remote shell");
        printf("Ended qsh session on %s\n", sysname);
        exit(0);
      }

      /* The remote shell process ended. */
      else if (buf_size == 0) {
        printf("\nEnded qsh session on %s\n", sysname);
        exit(0);
      }

      /* Process the data from the remote shell. */
      else {
        /* Convert to ASCII. */
        *(ebcdic_buf+buf_size) = '\0';
        if (ConvertToASCII(ebcdic_buf, buf_size+1, ascii_buf,
                           DEFAULT_BUF) >= 0) {
          write(1, ascii_buf, buf_size); 
        }
      }
    }
  } /* End of while */
  
  exit(0);
} /* End of main() */


/*
 * Convert a string from ASCII to EBCDIC.
 */

int
ConvertToEBCDIC(char *ibuf, size_t ileft, char *obuf, size_t oleft)
{
  int rc;

  #ifdef USE_ICONV
  rc = iconv(ecd, (const char**)&ibuf, &ileft, &obuf, &oleft);
  #else
  rc = Translate((uchar *)ibuf, ileft, (uchar *)obuf, EbcdicTable);
  #endif
  if (rc < 0)
    perror("qshc: error converting to EBCDIC");
  
  return rc;
} /* End of ConvertToEBCDIC() */


/*
 * Convert a string from EBCDIC to ASCII.
 */

int
ConvertToASCII(char *ibuf, size_t ileft, char *obuf, size_t oleft)
{
  int rc;

  #ifdef USE_ICONV
  rc = iconv(acd, (const char**)&ibuf, &ileft, &obuf, &oleft);
  #else
  rc = Translate((uchar *)ibuf, ileft, (uchar *)obuf, AsciiTable);
  #endif
  if (rc < 0)
    perror("qshc: error converting to ASCII");
  
  return rc;
} /* End of ConvertToASCII() */


/*
 * Get the user name and password for the specified system from the
 * ~/.netrc file.
 */

int
GetPassword(char *sysname, char *logname, char *password)
{
  #define BUFSIZE 256
  char buffer[BUFSIZE];
  char *systag, *logtag;
  int logflag = 0, pwdflag = 0;
  FILE *netrc;
  struct passwd *pwdbuf;
  int rc=0;

  /* Get user's home directory. */
  pwdbuf = getpwuid(getuid());

  /* Does user have a .netrc file in their home directory? */
  strcat(strcpy(buffer, pwdbuf->pw_dir), "/.netrc");

  if ((netrc = fopen(buffer, "r")) == NULL) {
    perror("qshc: open() failed for ~/.netrc file");
    return -1;
  }

  while (!(logflag || pwdflag) && fgets(buffer, BUFSIZE, netrc) != NULL) {
    /* Find system name in ~/.netrc. */
    if ((systag = (char*)strtok(buffer, " \t\n")) != NULL &&
        !strncmp(systag, "machine", 7)) {
      systag = (char *)strtok(NULL, " \t\n");
      if (!strcmp(systag, sysname)) {
        /* Find login and password. */
        while (!logflag || !pwdflag) {
          if ((logtag = (char *)strtok(NULL, " \t\n")) == NULL) {
            /* Nothing else on that line... get another. */
            while (!logtag) {
              fgets(buffer, BUFSIZE, netrc);
              logtag = (char *)strtok(buffer, " \t\n");
            }
          }

          if (!strncmp(logtag, "login", 5)) {
            strcpy(logname, strtok(NULL, " \n\t"));
            ++logflag;
          }
          else if (!strncmp(logtag, "password", 8)) {
            strcpy(password, strtok(NULL, " \n\t"));
            ++pwdflag;
          }
          else
            ;
        } /* while flags not set */
      } /* if found login and passwd in .netrc */
    } /* if machine in .netrc */
  } /* while fgets */

  fclose(netrc);

  /* Login and password not found for system. */
  if (!(logflag && pwdflag)) {
    rc = -1;
  }

  return rc;
} /* End of GetPassword() */


#ifndef USE_ICONV
/*
 * Translate bytes using the specified translation table.
 */

int
Translate(uchar *ip, size_t ilen, uchar *op, uchar *table)
{
  int index;
  for (index = 0; index < ilen; ++index) {
    *op = table[*ip];
    ip++;
    op++;
  }

  return 0;
} /* End of Translate() */
#endif


/*
 * Signal handler.
 */

void
MySignalHandler(int signo)
{
  switch (signo) {
    case SIGINT:
      printf("\nqshc: <ctrl>c ends this program\n");
      printf("Ended qsh session on %s\n", sysname);
      exit(0);
      break;
      
    default:
      exit(1);
      break;
  } /* End of switch */

  return;
} /* End of MySignalHandler() */


/*
 * Display usage message.
 */

void usage(void)
{
  fprintf(stderr, "Usage: qshc [-n] [-p port] hostname\n");
  exit(1);
} /* End of usage() */

Note: By using the code examples, you agree to the terms of the Code license and disclaimer information.