/**********************************************************************/ /* */ /* 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.