131457Sminshall #include <sys/types.h> 231457Sminshall #include <sys/socket.h> 331457Sminshall #include <netinet/in.h> 431455Sminshall #include <sys/wait.h> 531455Sminshall 631457Sminshall #include <errno.h> 731457Sminshall extern int errno; 831457Sminshall 931457Sminshall #include <netdb.h> 1031457Sminshall #include <signal.h> 1131455Sminshall #include <stdio.h> 1231457Sminshall #include <pwd.h> 1331455Sminshall 1431455Sminshall #include "../general/general.h" 1531455Sminshall #include "../api/api.h" 16*31463Sminshall #include "../apilib/api_exch.h" 1731455Sminshall 1831455Sminshall #include "../general/globals.h" 1931455Sminshall 2031455Sminshall 2131455Sminshall static int shell_pid = 0; 2231455Sminshall 2331457Sminshall static char *ourENVlist[200]; /* Lots of room */ 2431457Sminshall 2531457Sminshall static int sock = -1; 2631457Sminshall 2731457Sminshall static enum { DEAD, UNCONNECTED, CONNECTED } state; 2831457Sminshall 2931455Sminshall static int 30*31463Sminshall storage_location, /* Address we have */ 3131457Sminshall storage_length = 0, /* Length we have */ 3231457Sminshall storage_must_send = 0, /* Storage belongs on other side of wire */ 3331457Sminshall storage_accessed = 0; /* The storage is accessed (so leave alone)! */ 3431457Sminshall 3531457Sminshall static long storage[250]; 3631457Sminshall 37*31463Sminshall static union REGS inputRegs; 38*31463Sminshall static struct SREGS inputSregs; 3931457Sminshall 40*31463Sminshall 41*31463Sminshall static void 4231457Sminshall kill_connection() 4331457Sminshall { 4431457Sminshall state = DEAD; 4531457Sminshall (void) close(sock); 4631457Sminshall sock = -1; 4731457Sminshall } 4831457Sminshall 4931457Sminshall 5031457Sminshall static int 51*31463Sminshall nextstore() 5231455Sminshall { 53*31463Sminshall struct storage_descriptor sd; 5431455Sminshall 55*31463Sminshall if (api_exch_incommand(EXCH_HEREIS) == -1) { 5631457Sminshall fprintf(stderr, "Bad data from other side.\n"); 5731457Sminshall fprintf(stderr, "(Encountered at %s, %s.)\n", __FILE__, __LINE__); 5831457Sminshall return -1; 5931457Sminshall } 60*31463Sminshall if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 6131457Sminshall storage_length = 0; 6231457Sminshall return -1; 6331457Sminshall } 64*31463Sminshall storage_length = ntohs(sd.length); 65*31463Sminshall storage_location = ntohl(sd.location); 66*31463Sminshall if (storage_length > sizeof storage) { 6731457Sminshall fprintf(stderr, "API client tried to send too much storage (%d).\n", 6831457Sminshall storage_length); 69*31463Sminshall storage_length = 0; 7031457Sminshall return -1; 7131457Sminshall } 72*31463Sminshall if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage) == -1) { 73*31463Sminshall storage_length = 0; 74*31463Sminshall return -1; 75*31463Sminshall } 7631457Sminshall } 7731457Sminshall 7831457Sminshall 7931457Sminshall static int 8031457Sminshall doreject(message) 8131457Sminshall char *message; 8231457Sminshall { 83*31463Sminshall struct storage_descriptor sd; 8431457Sminshall int length = strlen(message); 8531457Sminshall 86*31463Sminshall if (api_exch_outcommand(EXCH_REJECTED) == -1) { 8731457Sminshall return -1; 8831457Sminshall } 89*31463Sminshall sd.length = htons(length); 90*31463Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, sizeof sd, (char *)&sd) == -1) { 91*31463Sminshall return -1; 92*31463Sminshall } 93*31463Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) { 94*31463Sminshall return -1; 95*31463Sminshall } 9631457Sminshall return 0; 9731457Sminshall } 9831457Sminshall 9931457Sminshall 10031455Sminshall /* 10131457Sminshall * doconnect() 10231457Sminshall * 10331457Sminshall * Negotiate with the other side and try to do something. 10431457Sminshall */ 10531457Sminshall 10631457Sminshall static int 10731457Sminshall doconnect() 10831457Sminshall { 10931457Sminshall struct passwd *pwent; 11031457Sminshall char 11131457Sminshall promptbuf[100], 11231457Sminshall buffer[200]; 11331457Sminshall int length; 11431457Sminshall int was; 115*31463Sminshall struct storage_descriptor sd; 11631457Sminshall 11731457Sminshall if ((pwent = getpwuid(geteuid())) == 0) { 11831457Sminshall return -1; 11931457Sminshall } 12031457Sminshall sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name); 121*31463Sminshall api_exch_outcommand(EXCH_SEND_AUTH); 122*31463Sminshall api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf); 123*31463Sminshall api_exch_outtype(EXCH_TYPE_BYTES, strlen(pwent->pw_name), pwent->pw_name); 124*31463Sminshall if (api_exch_incommand(EXCH_AUTH) == -1) { 12531457Sminshall return -1; 12631457Sminshall } 127*31463Sminshall if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 128*31463Sminshall return -1; 12931457Sminshall } 130*31463Sminshall sd.length = ntohs(sd.length); 131*31463Sminshall if (sd.length > sizeof buffer) { 13231457Sminshall doreject("Password entered was too long"); 13331457Sminshall return 0; 13431457Sminshall } 135*31463Sminshall if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) { 13631457Sminshall return -1; 13731457Sminshall } 138*31463Sminshall buffer[sd.length] = 0; 13931457Sminshall 14031457Sminshall /* Is this the correct password? */ 14131457Sminshall if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) == 0) { 142*31463Sminshall api_exch_outcommand(EXCH_CONNECTED); 14331457Sminshall } else { 14431457Sminshall doreject("Invalid password"); 14531457Sminshall sleep(10); /* Don't let us do too many of these */ 14631457Sminshall } 14731457Sminshall return 0; 14831457Sminshall } 14931457Sminshall 15031457Sminshall 15131457Sminshall void 15231457Sminshall freestorage() 15331457Sminshall { 15431457Sminshall char buffer[40]; 155*31463Sminshall struct storage_descriptor sd; 15631457Sminshall 15731457Sminshall if (storage_accessed) { 15831457Sminshall fprintf(stderr, "Internal error - attempt to free accessed storage.\n"); 15931457Sminshall fprintf(stderr, "(Enountered in file %s at line %s.)\n", 16031457Sminshall __FILE__, __LINE__); 16131457Sminshall quit(); 16231457Sminshall } 16331457Sminshall if (storage_must_send == 0) { 16431457Sminshall return; 16531457Sminshall } 16631457Sminshall storage_must_send = 0; 167*31463Sminshall if (api_exch_outcommand(EXCH_HEREIS) == -1) { 16831457Sminshall kill_connection(); 16931457Sminshall return; 17031457Sminshall } 171*31463Sminshall sd.length = htons(storage_length); 172*31463Sminshall sd.location = htonl(storage_location); 173*31463Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 17431457Sminshall kill_connection(); 17531457Sminshall return; 17631457Sminshall } 177*31463Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage) == -1) { 178*31463Sminshall kill_connection(); 179*31463Sminshall return; 180*31463Sminshall } 18131457Sminshall } 18231457Sminshall 18331457Sminshall 184*31463Sminshall static int 18531457Sminshall getstorage(address, length) 18631457Sminshall { 187*31463Sminshall struct storage_descriptor sd; 18831457Sminshall char buffer[40]; 18931457Sminshall 19031457Sminshall freestorage(); 19131457Sminshall if (storage_accessed) { 19231457Sminshall fprintf(stderr, 19331457Sminshall "Internal error - attempt to get while storage accessed.\n"); 19431457Sminshall fprintf(stderr, "(Enountered in file %s at line %s.)\n", 19531457Sminshall __FILE__, __LINE__); 19631457Sminshall quit(); 19731457Sminshall } 19831457Sminshall if (storage_must_send == 0) { 19931457Sminshall return; 20031457Sminshall } 20131457Sminshall storage_must_send = 0; 202*31463Sminshall if (api_exch_outcommand(EXCH_GIMME) == -1) { 20331457Sminshall kill_connection(); 204*31463Sminshall return -1; 20531457Sminshall } 206*31463Sminshall sd.location = htonl(storage_location); 207*31463Sminshall sd.length = htons(storage_length); 208*31463Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 209*31463Sminshall kill_connection(); 210*31463Sminshall return -1; 211*31463Sminshall } 21231457Sminshall if (nextstore() == -1) { 21331457Sminshall kill_connection(); 214*31463Sminshall return -1; 21531457Sminshall } 216*31463Sminshall return 0; 21731457Sminshall } 21831457Sminshall 21931457Sminshall void 22031457Sminshall movetous(local, es, di, length) 22131457Sminshall char 22231457Sminshall *local; 22331457Sminshall int 22431457Sminshall es, 22531457Sminshall di; 22631457Sminshall int 22731457Sminshall length; 22831457Sminshall { 22931457Sminshall if (length > sizeof storage) { 23031457Sminshall fprintf(stderr, "Internal API error - movetous() length too long.\n"); 23131457Sminshall fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 23231457Sminshall quit(); 23331457Sminshall } else if (length == 0) { 23431457Sminshall return; 23531457Sminshall } 23631457Sminshall getstorage(di, length); 237*31463Sminshall memcpy(local, storage+(di-storage_location), length); 23831457Sminshall } 23931457Sminshall 24031457Sminshall void 24131457Sminshall movetothem(es, di, local, length) 24231457Sminshall int 24331457Sminshall es, 24431457Sminshall di; 24531457Sminshall char 24631457Sminshall *local; 24731457Sminshall int 24831457Sminshall length; 24931457Sminshall { 25031457Sminshall if (length > sizeof storage) { 25131457Sminshall fprintf(stderr, "Internal API error - movetothem() length too long.\n"); 25231457Sminshall fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 25331457Sminshall quit(); 25431457Sminshall } else if (length == 0) { 25531457Sminshall return; 25631457Sminshall } 25731457Sminshall freestorage(); 25831457Sminshall memcpy((char *)storage, local, length); 25931457Sminshall storage_length = length; 260*31463Sminshall storage_location = di; 26131457Sminshall storage_must_send = 1; 26231457Sminshall } 26331457Sminshall 26431457Sminshall 26531457Sminshall char * 26631457Sminshall access_api(location, length) 26731457Sminshall int 26831457Sminshall location, 26931457Sminshall length; 27031457Sminshall { 27131457Sminshall if (storage_accessed) { 27231457Sminshall fprintf(stderr, "Internal error - storage accessed twice\n"); 27331457Sminshall fprintf(stderr, "(Encountered in file %s, line %s.)\n", 27431457Sminshall __FILE__, __LINE__); 27531457Sminshall quit(); 27631457Sminshall } else if (length != 0) { 27731457Sminshall storage_accessed = 1; 27831457Sminshall freestorage(); 27931457Sminshall getstorage(location, length); 28031457Sminshall } 28131457Sminshall return (char *) storage; 28231457Sminshall } 28331457Sminshall 28431457Sminshall unaccess_api(location, local, length) 28531457Sminshall int location; 28631457Sminshall char *local; 28731457Sminshall int length; 28831457Sminshall { 28931457Sminshall if (storage_accessed == 0) { 29031457Sminshall fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n"); 29131457Sminshall fprintf(stderr, "(Encountered in file %s, line %s.)\n", 29231457Sminshall __FILE__, __LINE__); 29331457Sminshall quit(); 29431457Sminshall } 29531457Sminshall storage_accessed = 0; 29631457Sminshall storage_must_send = 1; /* Needs to go back */ 29731457Sminshall } 29831457Sminshall 29931457Sminshall 30031457Sminshall /* 30131455Sminshall * shell_continue() actually runs the command, and looks for API 30231455Sminshall * requests coming back in. 30331455Sminshall * 30431455Sminshall * We are called from the main loop in telnet.c. 30531455Sminshall */ 30631455Sminshall 30731455Sminshall int 30831455Sminshall shell_continue() 30931455Sminshall { 31031457Sminshall switch (state) { 31131457Sminshall case DEAD: 31231457Sminshall pause(); /* Nothing to do */ 31331457Sminshall break; 31431457Sminshall case UNCONNECTED: 315*31463Sminshall if (api_exch_incommand(EXCH_CONNECT) == -1) { 31631457Sminshall kill_connection(); 31731457Sminshall } else { 31831457Sminshall switch (doconnect()) { 31931457Sminshall case -1: 32031457Sminshall kill_connection(); 32131457Sminshall break; 32231457Sminshall case 0: 32331457Sminshall break; 32431457Sminshall case 1: 32531457Sminshall state = CONNECTED; 32631457Sminshall } 32731457Sminshall } 32831457Sminshall break; 32931457Sminshall case CONNECTED: 330*31463Sminshall if (api_exch_incommand(EXCH_REQUEST) == -1) { 331*31463Sminshall kill_connection(); 332*31463Sminshall } else if (api_exch_intype(EXCH_TYPE_BYTES, sizeof inputRegs, 333*31463Sminshall (char *)&inputRegs) == -1) { 334*31463Sminshall kill_connection(); 335*31463Sminshall } else if (api_exch_intype(EXCH_TYPE_BYTES, sizeof inputSregs, 336*31463Sminshall (char *)&inputSregs) == -1) { 337*31463Sminshall kill_connection(); 338*31463Sminshall } else if (nextstore() == -1) { 339*31463Sminshall kill_connection(); 340*31463Sminshall } else { 34131457Sminshall handle_api(&inputRegs, &inputSregs); 342*31463Sminshall freestorage(); /* Send any storage back */ 343*31463Sminshall if (api_exch_outcommand(EXCH_REPLY) == -1) { 344*31463Sminshall kill_connection(); 345*31463Sminshall } else if (api_exch_outtype(EXCH_TYPE_BYTES, sizeof inputRegs, 346*31463Sminshall (char *)&inputRegs) == -1) { 347*31463Sminshall kill_connection(); 348*31463Sminshall } else if (api_exch_outtype(EXCH_TYPE_BYTES, sizeof inputSregs, 349*31463Sminshall (char *)&inputSregs) == -1) { 350*31463Sminshall kill_connection(); 351*31463Sminshall } 352*31463Sminshall /* Done, and it all worked! */ 35331457Sminshall } 35431457Sminshall } 35531455Sminshall return shell_active; 35631455Sminshall } 35731455Sminshall 35831455Sminshall 359*31463Sminshall static int 360*31463Sminshall child_died() 361*31463Sminshall { 362*31463Sminshall union wait *status; 363*31463Sminshall register int pid; 364*31463Sminshall 365*31463Sminshall while ((pid = wait3(&status, WNOHANG, 0)) > 0) { 366*31463Sminshall if (pid == shell_pid) { 367*31463Sminshall char inputbuffer[100]; 368*31463Sminshall 369*31463Sminshall shell_active = 0; 370*31463Sminshall if (sock != -1) { 371*31463Sminshall (void) close(sock); 372*31463Sminshall sock = -1; 373*31463Sminshall printf("[Hit return to continue]"); 374*31463Sminshall fflush(stdout); 375*31463Sminshall (void) gets(inputbuffer); 376*31463Sminshall setconnmode(); 377*31463Sminshall ConnectScreen(); /* Turn screen on (if need be) */ 378*31463Sminshall } 379*31463Sminshall } 380*31463Sminshall } 381*31463Sminshall signal(SIGCHLD, child_died); 382*31463Sminshall } 383*31463Sminshall 384*31463Sminshall 38531455Sminshall /* 38631455Sminshall * Called from telnet.c to fork a lower command.com. We 38731455Sminshall * use the spint... routines so that we can pick up 38831455Sminshall * interrupts generated by application programs. 38931455Sminshall */ 39031455Sminshall 39131455Sminshall 39231455Sminshall int 39331455Sminshall shell(argc,argv) 39431455Sminshall int argc; 39531455Sminshall char *argv[]; 39631455Sminshall { 39731457Sminshall int serversock, length; 39831457Sminshall struct sockaddr_in server; 39931457Sminshall char sockNAME[100]; 40031457Sminshall static char **whereAPI = 0; 40131457Sminshall 40231457Sminshall /* First, create the socket which will be connected to */ 40331457Sminshall serversock = socket(AF_INET, SOCK_STREAM, 0); 40431457Sminshall if (serversock < 0) { 40531457Sminshall perror("opening API socket"); 40631457Sminshall return 0; 40731457Sminshall } 40831457Sminshall server.sin_family = AF_INET; 40931457Sminshall server.sin_addr.s_addr = INADDR_ANY; 41031457Sminshall server.sin_port = 0; 41131457Sminshall if (bind(serversock, &server, sizeof server) < 0) { 41231457Sminshall perror("binding API socket"); 41331457Sminshall return 0; 41431457Sminshall } 41531457Sminshall length = sizeof server; 41631457Sminshall if (getsockname(serversock, &server, &length) < 0) { 41731457Sminshall perror("getting API socket name"); 41831457Sminshall (void) close(serversock); 41931457Sminshall } 42031457Sminshall listen(serversock, 1); 42131457Sminshall /* Get name to advertise in address list */ 42231457Sminshall strcpy(sockNAME, "API3270="); 42331457Sminshall gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME)); 42431457Sminshall if (strlen(sockNAME) > (sizeof sockNAME-10)) { 42531457Sminshall fprintf(stderr, "Local hostname too large; using 'localhost'.\n"); 42631457Sminshall strcpy(sockNAME, "localhost"); 42731457Sminshall } 42831457Sminshall sprintf(sockNAME+strlen(sockNAME), ":%d", ntohs(server.sin_port)); 42931457Sminshall 43031457Sminshall if (whereAPI == 0) { 43131457Sminshall char **ptr, **nextenv; 43231457Sminshall extern char **environ; 43331457Sminshall 43431457Sminshall ptr = environ; 43531457Sminshall nextenv = ourENVlist; 43631457Sminshall while (*ptr) { 43731457Sminshall if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) { 43831457Sminshall fprintf(stderr, "Too many environmental variables\n"); 43931457Sminshall break; 44031457Sminshall } 44131457Sminshall *nextenv++ = *ptr++; 44231457Sminshall } 44331457Sminshall whereAPI = nextenv++; 44431457Sminshall *nextenv++ = 0; 44531457Sminshall environ = ourENVlist; /* New environment */ 44631457Sminshall } 44731457Sminshall *whereAPI = sockNAME; 44831457Sminshall 44931457Sminshall child_died(); /* Start up signal handler */ 45031457Sminshall shell_active = 1; /* We are running down below */ 45131457Sminshall if (shell_pid = vfork()) { 45231457Sminshall if (shell_pid == -1) { 45331457Sminshall perror("vfork"); 45431457Sminshall (void) close(serversock); 45531457Sminshall } else { 45631457Sminshall fd_set fdset; 45731457Sminshall int i; 45831457Sminshall 45931457Sminshall FD_ZERO(&fdset); 46031457Sminshall FD_SET(serversock, &fdset); 46131457Sminshall while (shell_active) { 46231457Sminshall if ((i = select(serversock+1, &fdset, 0, 0, 0)) < 0) { 46331457Sminshall if (errno = EINTR) { 46431457Sminshall continue; 46531457Sminshall } else { 46631457Sminshall perror("in select waiting for API connection"); 46731457Sminshall break; 46831457Sminshall } 46931457Sminshall } else { 47031457Sminshall i = accept(serversock, 0, 0); 47131457Sminshall if (i == -1) { 47231457Sminshall perror("accepting API connection"); 47331457Sminshall } 47431457Sminshall sock = i; 475*31463Sminshall api_exch_init(sock); 476*31463Sminshall state = UNCONNECTED; 47731457Sminshall break; 47831457Sminshall } 47931457Sminshall } 48031457Sminshall (void) close(serversock); 48131457Sminshall /* If the process has already exited, we may need to close */ 48231457Sminshall if ((shell_active == 0) && (sock != -1)) { 48331457Sminshall (void) close(sock); 48431457Sminshall sock = -1; 48531457Sminshall setcommandmode(); /* In case child_died sneaked in */ 48631457Sminshall } 48731457Sminshall } 48831455Sminshall } else { /* New process */ 48931455Sminshall register int i; 49031455Sminshall 49131455Sminshall for (i = 3; i < 30; i++) { 49231455Sminshall (void) close(i); 49331455Sminshall } 49431455Sminshall if (argc == 1) { /* Just get a shell */ 49531455Sminshall char *cmdname; 49631457Sminshall extern char *getenv(); 49731455Sminshall 49831455Sminshall cmdname = getenv("SHELL"); 49931455Sminshall execlp(cmdname, cmdname, 0); 50031455Sminshall perror("Exec'ing new shell...\n"); 50131455Sminshall exit(1); 50231455Sminshall } else { 50331455Sminshall execvp(argv[1], &argv[1]); 50431455Sminshall perror("Exec'ing command.\n"); 50531455Sminshall exit(1); 50631455Sminshall } 50731455Sminshall /*NOTREACHED*/ 50831455Sminshall } 50931457Sminshall return shell_active; /* Go back to main loop */ 51031455Sminshall } 511