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" 1631463Sminshall #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 25*31465Sminshall static int 26*31465Sminshall sock = -1, /* Connected socket */ 27*31465Sminshall serversock; /* Server (listening) socket */ 2831457Sminshall 2931457Sminshall static enum { DEAD, UNCONNECTED, CONNECTED } state; 3031457Sminshall 3131455Sminshall static int 3231463Sminshall storage_location, /* Address we have */ 3331457Sminshall storage_length = 0, /* Length we have */ 3431457Sminshall storage_must_send = 0, /* Storage belongs on other side of wire */ 3531457Sminshall storage_accessed = 0; /* The storage is accessed (so leave alone)! */ 3631457Sminshall 3731457Sminshall static long storage[250]; 3831457Sminshall 3931463Sminshall static union REGS inputRegs; 4031463Sminshall static struct SREGS inputSregs; 4131457Sminshall 4231463Sminshall 4331463Sminshall static void 4431457Sminshall kill_connection() 4531457Sminshall { 46*31465Sminshall state = UNCONNECTED; 47*31465Sminshall if (sock != -1) { 48*31465Sminshall (void) close(sock); 49*31465Sminshall sock = -1; 50*31465Sminshall } 5131457Sminshall } 5231457Sminshall 5331457Sminshall 5431457Sminshall static int 5531463Sminshall nextstore() 5631455Sminshall { 5731463Sminshall struct storage_descriptor sd; 5831455Sminshall 5931463Sminshall if (api_exch_incommand(EXCH_HEREIS) == -1) { 6031457Sminshall fprintf(stderr, "Bad data from other side.\n"); 6131457Sminshall fprintf(stderr, "(Encountered at %s, %s.)\n", __FILE__, __LINE__); 6231457Sminshall return -1; 6331457Sminshall } 6431463Sminshall if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 6531457Sminshall storage_length = 0; 6631457Sminshall return -1; 6731457Sminshall } 6831463Sminshall storage_length = ntohs(sd.length); 6931463Sminshall storage_location = ntohl(sd.location); 7031463Sminshall if (storage_length > sizeof storage) { 7131457Sminshall fprintf(stderr, "API client tried to send too much storage (%d).\n", 7231457Sminshall storage_length); 7331463Sminshall storage_length = 0; 7431457Sminshall return -1; 7531457Sminshall } 7631463Sminshall if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage) == -1) { 7731463Sminshall storage_length = 0; 7831463Sminshall return -1; 7931463Sminshall } 8031457Sminshall } 8131457Sminshall 8231457Sminshall 8331457Sminshall static int 8431457Sminshall doreject(message) 8531457Sminshall char *message; 8631457Sminshall { 8731463Sminshall struct storage_descriptor sd; 8831457Sminshall int length = strlen(message); 8931457Sminshall 9031463Sminshall if (api_exch_outcommand(EXCH_REJECTED) == -1) { 9131457Sminshall return -1; 9231457Sminshall } 9331463Sminshall sd.length = htons(length); 94*31465Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 9531463Sminshall return -1; 9631463Sminshall } 9731463Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) { 9831463Sminshall return -1; 9931463Sminshall } 10031457Sminshall return 0; 10131457Sminshall } 10231457Sminshall 10331457Sminshall 10431455Sminshall /* 105*31465Sminshall * doassociate() 10631457Sminshall * 10731457Sminshall * Negotiate with the other side and try to do something. 10831457Sminshall */ 10931457Sminshall 11031457Sminshall static int 111*31465Sminshall doassociate() 11231457Sminshall { 11331457Sminshall struct passwd *pwent; 11431457Sminshall char 11531457Sminshall promptbuf[100], 11631457Sminshall buffer[200]; 11731457Sminshall int length; 11831457Sminshall int was; 11931463Sminshall struct storage_descriptor sd; 12031457Sminshall 12131457Sminshall if ((pwent = getpwuid(geteuid())) == 0) { 12231457Sminshall return -1; 12331457Sminshall } 12431457Sminshall sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name); 125*31465Sminshall if (api_exch_outcommand(EXCH_SEND_AUTH) == -1) { 126*31465Sminshall return -1; 127*31465Sminshall } 128*31465Sminshall sd.length = htons(strlen(promptbuf)); 129*31465Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 130*31465Sminshall return -1; 131*31465Sminshall } 132*31465Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf) == -1) { 133*31465Sminshall return -1; 134*31465Sminshall } 135*31465Sminshall sd.length = htons(strlen(pwent->pw_name)); 136*31465Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 137*31465Sminshall return -1; 138*31465Sminshall } 139*31465Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, 140*31465Sminshall strlen(pwent->pw_name), pwent->pw_name) == -1) { 141*31465Sminshall return -1; 142*31465Sminshall } 14331463Sminshall if (api_exch_incommand(EXCH_AUTH) == -1) { 14431457Sminshall return -1; 14531457Sminshall } 14631463Sminshall if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 14731463Sminshall return -1; 14831457Sminshall } 14931463Sminshall sd.length = ntohs(sd.length); 15031463Sminshall if (sd.length > sizeof buffer) { 15131457Sminshall doreject("Password entered was too long"); 152*31465Sminshall return -1; 15331457Sminshall } 15431463Sminshall if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) { 15531457Sminshall return -1; 15631457Sminshall } 15731463Sminshall buffer[sd.length] = 0; 15831457Sminshall 15931457Sminshall /* Is this the correct password? */ 160*31465Sminshall if (strlen(pwent->pw_name)) { 161*31465Sminshall char *ptr; 162*31465Sminshall int i; 163*31465Sminshall 164*31465Sminshall ptr = pwent->pw_name; 165*31465Sminshall i = 0; 166*31465Sminshall while (i < sd.length) { 167*31465Sminshall buffer[i++] ^= *ptr++; 168*31465Sminshall if (*ptr == 0) { 169*31465Sminshall ptr = pwent->pw_name; 170*31465Sminshall } 171*31465Sminshall } 172*31465Sminshall } 17331457Sminshall if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) == 0) { 174*31465Sminshall if (api_exch_outcommand(EXCH_ASSOCIATED) == -1) { 175*31465Sminshall return -1; 176*31465Sminshall } 17731457Sminshall } else { 17831457Sminshall doreject("Invalid password"); 17931457Sminshall sleep(10); /* Don't let us do too many of these */ 18031457Sminshall } 18131457Sminshall return 0; 18231457Sminshall } 18331457Sminshall 18431457Sminshall 18531457Sminshall void 18631457Sminshall freestorage() 18731457Sminshall { 18831457Sminshall char buffer[40]; 18931463Sminshall struct storage_descriptor sd; 19031457Sminshall 19131457Sminshall if (storage_accessed) { 19231457Sminshall fprintf(stderr, "Internal error - attempt to free accessed storage.\n"); 19331457Sminshall fprintf(stderr, "(Enountered in file %s at line %s.)\n", 19431457Sminshall __FILE__, __LINE__); 19531457Sminshall quit(); 19631457Sminshall } 19731457Sminshall if (storage_must_send == 0) { 19831457Sminshall return; 19931457Sminshall } 20031457Sminshall storage_must_send = 0; 20131463Sminshall if (api_exch_outcommand(EXCH_HEREIS) == -1) { 20231457Sminshall kill_connection(); 20331457Sminshall return; 20431457Sminshall } 20531463Sminshall sd.length = htons(storage_length); 20631463Sminshall sd.location = htonl(storage_location); 20731463Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 20831457Sminshall kill_connection(); 20931457Sminshall return; 21031457Sminshall } 21131463Sminshall if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage) == -1) { 21231463Sminshall kill_connection(); 21331463Sminshall return; 21431463Sminshall } 21531457Sminshall } 21631457Sminshall 21731457Sminshall 21831463Sminshall static int 21931457Sminshall getstorage(address, length) 22031457Sminshall { 22131463Sminshall struct storage_descriptor sd; 22231457Sminshall char buffer[40]; 22331457Sminshall 22431457Sminshall freestorage(); 22531457Sminshall if (storage_accessed) { 22631457Sminshall fprintf(stderr, 22731457Sminshall "Internal error - attempt to get while storage accessed.\n"); 22831457Sminshall fprintf(stderr, "(Enountered in file %s at line %s.)\n", 22931457Sminshall __FILE__, __LINE__); 23031457Sminshall quit(); 23131457Sminshall } 23231457Sminshall if (storage_must_send == 0) { 23331457Sminshall return; 23431457Sminshall } 23531457Sminshall storage_must_send = 0; 23631463Sminshall if (api_exch_outcommand(EXCH_GIMME) == -1) { 23731457Sminshall kill_connection(); 23831463Sminshall return -1; 23931457Sminshall } 24031463Sminshall sd.location = htonl(storage_location); 24131463Sminshall sd.length = htons(storage_length); 24231463Sminshall if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 24331463Sminshall kill_connection(); 24431463Sminshall return -1; 24531463Sminshall } 24631457Sminshall if (nextstore() == -1) { 24731457Sminshall kill_connection(); 24831463Sminshall return -1; 24931457Sminshall } 25031463Sminshall return 0; 25131457Sminshall } 25231457Sminshall 25331457Sminshall void 25431457Sminshall movetous(local, es, di, length) 25531457Sminshall char 25631457Sminshall *local; 25731457Sminshall int 25831457Sminshall es, 25931457Sminshall di; 26031457Sminshall int 26131457Sminshall length; 26231457Sminshall { 26331457Sminshall if (length > sizeof storage) { 26431457Sminshall fprintf(stderr, "Internal API error - movetous() length too long.\n"); 26531457Sminshall fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 26631457Sminshall quit(); 26731457Sminshall } else if (length == 0) { 26831457Sminshall return; 26931457Sminshall } 27031457Sminshall getstorage(di, length); 27131463Sminshall memcpy(local, storage+(di-storage_location), length); 27231457Sminshall } 27331457Sminshall 27431457Sminshall void 27531457Sminshall movetothem(es, di, local, length) 27631457Sminshall int 27731457Sminshall es, 27831457Sminshall di; 27931457Sminshall char 28031457Sminshall *local; 28131457Sminshall int 28231457Sminshall length; 28331457Sminshall { 28431457Sminshall if (length > sizeof storage) { 28531457Sminshall fprintf(stderr, "Internal API error - movetothem() length too long.\n"); 28631457Sminshall fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 28731457Sminshall quit(); 28831457Sminshall } else if (length == 0) { 28931457Sminshall return; 29031457Sminshall } 29131457Sminshall freestorage(); 29231457Sminshall memcpy((char *)storage, local, length); 29331457Sminshall storage_length = length; 29431463Sminshall storage_location = di; 29531457Sminshall storage_must_send = 1; 29631457Sminshall } 29731457Sminshall 29831457Sminshall 29931457Sminshall char * 30031457Sminshall access_api(location, length) 30131457Sminshall int 30231457Sminshall location, 30331457Sminshall length; 30431457Sminshall { 30531457Sminshall if (storage_accessed) { 30631457Sminshall fprintf(stderr, "Internal error - storage accessed twice\n"); 30731457Sminshall fprintf(stderr, "(Encountered in file %s, line %s.)\n", 30831457Sminshall __FILE__, __LINE__); 30931457Sminshall quit(); 31031457Sminshall } else if (length != 0) { 31131457Sminshall storage_accessed = 1; 31231457Sminshall freestorage(); 31331457Sminshall getstorage(location, length); 31431457Sminshall } 31531457Sminshall return (char *) storage; 31631457Sminshall } 31731457Sminshall 31831457Sminshall unaccess_api(location, local, length) 31931457Sminshall int location; 32031457Sminshall char *local; 32131457Sminshall int length; 32231457Sminshall { 32331457Sminshall if (storage_accessed == 0) { 32431457Sminshall fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n"); 32531457Sminshall fprintf(stderr, "(Encountered in file %s, line %s.)\n", 32631457Sminshall __FILE__, __LINE__); 32731457Sminshall quit(); 32831457Sminshall } 32931457Sminshall storage_accessed = 0; 33031457Sminshall storage_must_send = 1; /* Needs to go back */ 33131457Sminshall } 33231457Sminshall 333*31465Sminshall /* 334*31465Sminshall * Accept a connection from an API client, aborting if the child dies. 335*31465Sminshall */ 33631457Sminshall 337*31465Sminshall static int 338*31465Sminshall doconnect() 339*31465Sminshall { 340*31465Sminshall fd_set fdset; 341*31465Sminshall int i; 342*31465Sminshall 343*31465Sminshall sock = -1; 344*31465Sminshall FD_ZERO(&fdset); 345*31465Sminshall while (shell_active && (sock == -1)) { 346*31465Sminshall FD_SET(serversock, &fdset); 347*31465Sminshall if ((i = select(serversock+1, &fdset, 0, 0, 0)) < 0) { 348*31465Sminshall if (errno = EINTR) { 349*31465Sminshall continue; 350*31465Sminshall } else { 351*31465Sminshall perror("in select waiting for API connection"); 352*31465Sminshall return -1; 353*31465Sminshall } 354*31465Sminshall } else { 355*31465Sminshall i = accept(serversock, 0, 0); 356*31465Sminshall if (i == -1) { 357*31465Sminshall perror("accepting API connection"); 358*31465Sminshall return -1; 359*31465Sminshall } 360*31465Sminshall sock = i; 361*31465Sminshall } 362*31465Sminshall } 363*31465Sminshall /* If the process has already exited, we may need to close */ 364*31465Sminshall if ((shell_active == 0) && (sock != -1)) { 365*31465Sminshall (void) close(sock); 366*31465Sminshall sock = -1; 367*31465Sminshall setcommandmode(); /* In case child_died sneaked in */ 368*31465Sminshall } 369*31465Sminshall } 370*31465Sminshall 37131457Sminshall /* 37231455Sminshall * shell_continue() actually runs the command, and looks for API 37331455Sminshall * requests coming back in. 37431455Sminshall * 37531455Sminshall * We are called from the main loop in telnet.c. 37631455Sminshall */ 37731455Sminshall 37831455Sminshall int 37931455Sminshall shell_continue() 38031455Sminshall { 38131457Sminshall switch (state) { 38231457Sminshall case DEAD: 38331457Sminshall pause(); /* Nothing to do */ 38431457Sminshall break; 38531457Sminshall case UNCONNECTED: 386*31465Sminshall if (doconnect() == -1) { 38731457Sminshall kill_connection(); 388*31465Sminshall return -1; 389*31465Sminshall } 390*31465Sminshall if (api_exch_init(sock, "client") == -1) { 391*31465Sminshall return -1; 392*31465Sminshall } 393*31465Sminshall while (state == UNCONNECTED) { 394*31465Sminshall if (api_exch_incommand(EXCH_ASSOCIATE) == -1) { 39531457Sminshall kill_connection(); 396*31465Sminshall return -1; 397*31465Sminshall } else { 398*31465Sminshall switch (doassociate()) { 399*31465Sminshall case -1: 400*31465Sminshall kill_connection(); 401*31465Sminshall return -1; 402*31465Sminshall case 0: 403*31465Sminshall break; 404*31465Sminshall case 1: 405*31465Sminshall state = CONNECTED; 406*31465Sminshall } 40731457Sminshall } 40831457Sminshall } 40931457Sminshall break; 41031457Sminshall case CONNECTED: 41131463Sminshall if (api_exch_incommand(EXCH_REQUEST) == -1) { 41231463Sminshall kill_connection(); 41331463Sminshall } else if (api_exch_intype(EXCH_TYPE_BYTES, sizeof inputRegs, 41431463Sminshall (char *)&inputRegs) == -1) { 41531463Sminshall kill_connection(); 41631463Sminshall } else if (api_exch_intype(EXCH_TYPE_BYTES, sizeof inputSregs, 41731463Sminshall (char *)&inputSregs) == -1) { 41831463Sminshall kill_connection(); 41931463Sminshall } else if (nextstore() == -1) { 42031463Sminshall kill_connection(); 42131463Sminshall } else { 42231457Sminshall handle_api(&inputRegs, &inputSregs); 42331463Sminshall freestorage(); /* Send any storage back */ 42431463Sminshall if (api_exch_outcommand(EXCH_REPLY) == -1) { 42531463Sminshall kill_connection(); 42631463Sminshall } else if (api_exch_outtype(EXCH_TYPE_BYTES, sizeof inputRegs, 42731463Sminshall (char *)&inputRegs) == -1) { 42831463Sminshall kill_connection(); 42931463Sminshall } else if (api_exch_outtype(EXCH_TYPE_BYTES, sizeof inputSregs, 43031463Sminshall (char *)&inputSregs) == -1) { 43131463Sminshall kill_connection(); 43231463Sminshall } 43331463Sminshall /* Done, and it all worked! */ 43431457Sminshall } 43531457Sminshall } 43631455Sminshall return shell_active; 43731455Sminshall } 43831455Sminshall 43931455Sminshall 44031463Sminshall static int 44131463Sminshall child_died() 44231463Sminshall { 44331463Sminshall union wait *status; 44431463Sminshall register int pid; 44531463Sminshall 44631463Sminshall while ((pid = wait3(&status, WNOHANG, 0)) > 0) { 44731463Sminshall if (pid == shell_pid) { 44831463Sminshall char inputbuffer[100]; 44931463Sminshall 45031463Sminshall shell_active = 0; 45131463Sminshall if (sock != -1) { 45231463Sminshall (void) close(sock); 45331463Sminshall sock = -1; 45431463Sminshall printf("[Hit return to continue]"); 45531463Sminshall fflush(stdout); 45631463Sminshall (void) gets(inputbuffer); 45731463Sminshall } 458*31465Sminshall setconnmode(); 459*31465Sminshall ConnectScreen(); /* Turn screen on (if need be) */ 460*31465Sminshall (void) close(serversock); 46131463Sminshall } 46231463Sminshall } 46331463Sminshall signal(SIGCHLD, child_died); 46431463Sminshall } 46531463Sminshall 46631463Sminshall 46731455Sminshall /* 46831455Sminshall * Called from telnet.c to fork a lower command.com. We 46931455Sminshall * use the spint... routines so that we can pick up 47031455Sminshall * interrupts generated by application programs. 47131455Sminshall */ 47231455Sminshall 47331455Sminshall 47431455Sminshall int 47531455Sminshall shell(argc,argv) 47631455Sminshall int argc; 47731455Sminshall char *argv[]; 47831455Sminshall { 479*31465Sminshall int length; 48031457Sminshall struct sockaddr_in server; 48131457Sminshall char sockNAME[100]; 48231457Sminshall static char **whereAPI = 0; 48331457Sminshall 48431457Sminshall /* First, create the socket which will be connected to */ 48531457Sminshall serversock = socket(AF_INET, SOCK_STREAM, 0); 48631457Sminshall if (serversock < 0) { 48731457Sminshall perror("opening API socket"); 48831457Sminshall return 0; 48931457Sminshall } 49031457Sminshall server.sin_family = AF_INET; 49131457Sminshall server.sin_addr.s_addr = INADDR_ANY; 49231457Sminshall server.sin_port = 0; 49331457Sminshall if (bind(serversock, &server, sizeof server) < 0) { 49431457Sminshall perror("binding API socket"); 49531457Sminshall return 0; 49631457Sminshall } 49731457Sminshall length = sizeof server; 49831457Sminshall if (getsockname(serversock, &server, &length) < 0) { 49931457Sminshall perror("getting API socket name"); 50031457Sminshall (void) close(serversock); 50131457Sminshall } 50231457Sminshall listen(serversock, 1); 50331457Sminshall /* Get name to advertise in address list */ 50431457Sminshall strcpy(sockNAME, "API3270="); 50531457Sminshall gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME)); 50631457Sminshall if (strlen(sockNAME) > (sizeof sockNAME-10)) { 50731457Sminshall fprintf(stderr, "Local hostname too large; using 'localhost'.\n"); 50831457Sminshall strcpy(sockNAME, "localhost"); 50931457Sminshall } 51031457Sminshall sprintf(sockNAME+strlen(sockNAME), ":%d", ntohs(server.sin_port)); 51131457Sminshall 51231457Sminshall if (whereAPI == 0) { 51331457Sminshall char **ptr, **nextenv; 51431457Sminshall extern char **environ; 51531457Sminshall 51631457Sminshall ptr = environ; 51731457Sminshall nextenv = ourENVlist; 51831457Sminshall while (*ptr) { 51931457Sminshall if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) { 52031457Sminshall fprintf(stderr, "Too many environmental variables\n"); 52131457Sminshall break; 52231457Sminshall } 52331457Sminshall *nextenv++ = *ptr++; 52431457Sminshall } 52531457Sminshall whereAPI = nextenv++; 52631457Sminshall *nextenv++ = 0; 52731457Sminshall environ = ourENVlist; /* New environment */ 52831457Sminshall } 52931457Sminshall *whereAPI = sockNAME; 53031457Sminshall 53131457Sminshall child_died(); /* Start up signal handler */ 53231457Sminshall shell_active = 1; /* We are running down below */ 53331457Sminshall if (shell_pid = vfork()) { 53431457Sminshall if (shell_pid == -1) { 53531457Sminshall perror("vfork"); 53631457Sminshall (void) close(serversock); 53731457Sminshall } else { 538*31465Sminshall state = UNCONNECTED; 53931457Sminshall } 54031455Sminshall } else { /* New process */ 54131455Sminshall register int i; 54231455Sminshall 54331455Sminshall for (i = 3; i < 30; i++) { 54431455Sminshall (void) close(i); 54531455Sminshall } 54631455Sminshall if (argc == 1) { /* Just get a shell */ 54731455Sminshall char *cmdname; 54831457Sminshall extern char *getenv(); 54931455Sminshall 55031455Sminshall cmdname = getenv("SHELL"); 55131455Sminshall execlp(cmdname, cmdname, 0); 55231455Sminshall perror("Exec'ing new shell...\n"); 55331455Sminshall exit(1); 55431455Sminshall } else { 55531455Sminshall execvp(argv[1], &argv[1]); 55631455Sminshall perror("Exec'ing command.\n"); 55731455Sminshall exit(1); 55831455Sminshall } 55931455Sminshall /*NOTREACHED*/ 56031455Sminshall } 56131457Sminshall return shell_active; /* Go back to main loop */ 56231455Sminshall } 563