1*31457Sminshall #include <sys/types.h> 2*31457Sminshall #include <sys/socket.h> 3*31457Sminshall #include <netinet/in.h> 431455Sminshall #include <sys/wait.h> 531455Sminshall 6*31457Sminshall #include <errno.h> 7*31457Sminshall extern int errno; 8*31457Sminshall 9*31457Sminshall #include <netdb.h> 10*31457Sminshall #include <signal.h> 1131455Sminshall #include <stdio.h> 12*31457Sminshall #include <pwd.h> 1331455Sminshall 1431455Sminshall #include "../general/general.h" 1531455Sminshall #include "../api/api.h" 16*31457Sminshall #include "api_exch.h" 1731455Sminshall 1831455Sminshall #include "../general/globals.h" 1931455Sminshall 2031455Sminshall 2131455Sminshall static int shell_pid = 0; 2231455Sminshall 23*31457Sminshall static char *ourENVlist[200]; /* Lots of room */ 24*31457Sminshall 25*31457Sminshall static int sock = -1; 26*31457Sminshall 27*31457Sminshall static enum { DEAD, UNCONNECTED, CONNECTED } state; 28*31457Sminshall 2931455Sminshall static int 30*31457Sminshall storage_address, /* Address we have */ 31*31457Sminshall storage_length = 0, /* Length we have */ 32*31457Sminshall storage_must_send = 0, /* Storage belongs on other side of wire */ 33*31457Sminshall storage_accessed = 0; /* The storage is accessed (so leave alone)! */ 34*31457Sminshall 35*31457Sminshall static long storage[250]; 36*31457Sminshall 37*31457Sminshall union REGS inputRegs; 38*31457Sminshall struct SREGS inputSregs; 39*31457Sminshall 40*31457Sminshall kill_connection() 41*31457Sminshall { 42*31457Sminshall state = DEAD; 43*31457Sminshall (void) close(sock); 44*31457Sminshall sock = -1; 45*31457Sminshall } 46*31457Sminshall 47*31457Sminshall 48*31457Sminshall static int 4931455Sminshall child_died() 5031455Sminshall { 5131455Sminshall union wait *status; 52*31457Sminshall register int pid; 5331455Sminshall 54*31457Sminshall while ((pid = wait3(&status, WNOHANG, 0)) > 0) { 5531455Sminshall if (pid == shell_pid) { 56*31457Sminshall char inputbuffer[100]; 57*31457Sminshall 5831455Sminshall shell_active = 0; 59*31457Sminshall if (sock != -1) { 60*31457Sminshall (void) close(sock); 61*31457Sminshall sock = -1; 62*31457Sminshall printf("[Hit return to continue]"); 63*31457Sminshall fflush(stdout); 64*31457Sminshall (void) gets(inputbuffer); 65*31457Sminshall setconnmode(); 66*31457Sminshall ConnectScreen(); /* Turn screen on (if need be) */ 67*31457Sminshall } 6831455Sminshall } 6931455Sminshall } 7031455Sminshall signal(SIGCHLD, child_died); 7131455Sminshall } 7231455Sminshall 73*31457Sminshall static int 74*31457Sminshall nextchar() 75*31457Sminshall { 76*31457Sminshall unsigned char c; 77*31457Sminshall 78*31457Sminshall if (read(sock, &c, 1) != 1) { 79*31457Sminshall return -1; 80*31457Sminshall } else { 81*31457Sminshall return c; 82*31457Sminshall } 83*31457Sminshall } 84*31457Sminshall 85*31457Sminshall static int 86*31457Sminshall checktype(type) 87*31457Sminshall int type; 88*31457Sminshall { 89*31457Sminshall int was; 90*31457Sminshall 91*31457Sminshall if ((was = nextchar()) != type) { 92*31457Sminshall fprintf(stderr, "Wrong type of data. Should be 0x%02x, was 0x%02x.\n", 93*31457Sminshall type, was); 94*31457Sminshall return -1; 95*31457Sminshall } else { 96*31457Sminshall return 0; 97*31457Sminshall } 98*31457Sminshall } 99*31457Sminshall 100*31457Sminshall 101*31457Sminshall static int 102*31457Sminshall fill(where, length) 103*31457Sminshall char *where; 104*31457Sminshall int length; 105*31457Sminshall { 106*31457Sminshall while (length) { 107*31457Sminshall int i; 108*31457Sminshall 109*31457Sminshall if ((i = read(sock, where, length)) < 0) { 110*31457Sminshall perror("read"); 111*31457Sminshall return -1; 112*31457Sminshall } else { 113*31457Sminshall length -= i; 114*31457Sminshall where += i; 115*31457Sminshall } 116*31457Sminshall } 117*31457Sminshall } 118*31457Sminshall 119*31457Sminshall 120*31457Sminshall static int 121*31457Sminshall nextlength() 122*31457Sminshall { 123*31457Sminshall short length; 124*31457Sminshall 125*31457Sminshall if (fill(&length, sizeof length) == -1) { 126*31457Sminshall return -1; 127*31457Sminshall } else { 128*31457Sminshall return ntohs(length); 129*31457Sminshall } 130*31457Sminshall } 131*31457Sminshall 132*31457Sminshall 133*31457Sminshall static int 134*31457Sminshall nextaddress() 135*31457Sminshall { 136*31457Sminshall long address; 137*31457Sminshall 138*31457Sminshall return fill(&address, sizeof address); 139*31457Sminshall } 140*31457Sminshall 141*31457Sminshall 142*31457Sminshall 143*31457Sminshall static int 144*31457Sminshall nextbytes(type, where, length) 145*31457Sminshall int type; 146*31457Sminshall char *where; 147*31457Sminshall int length; 148*31457Sminshall { 149*31457Sminshall int was; 150*31457Sminshall 151*31457Sminshall if (checktype(type) == -1) { 152*31457Sminshall return -1; 153*31457Sminshall } 154*31457Sminshall if ((was = nextlength()) != length) { 155*31457Sminshall fprintf(stderr, "Type 0x%02x had bad length. Should be %d, was %d.\n", 156*31457Sminshall type, length, was); 157*31457Sminshall return -1; 158*31457Sminshall } else { 159*31457Sminshall return fill(where, length); 160*31457Sminshall } 161*31457Sminshall } 162*31457Sminshall 163*31457Sminshall static int 164*31457Sminshall nextstore() 165*31457Sminshall { 166*31457Sminshall if (nextchar() != EXCH_HEREIS) { 167*31457Sminshall fprintf(stderr, "Bad data from other side.\n"); 168*31457Sminshall fprintf(stderr, "(Encountered at %s, %s.)\n", __FILE__, __LINE__); 169*31457Sminshall return -1; 170*31457Sminshall } 171*31457Sminshall if ((storage_address = nextaddress()) == -1) { 172*31457Sminshall storage_length = 0; 173*31457Sminshall return -1; 174*31457Sminshall } 175*31457Sminshall if ((storage_length = nextlength()) > sizeof storage) { 176*31457Sminshall fprintf(stderr, "API client tried to send too much storage (%d).\n", 177*31457Sminshall storage_length); 178*31457Sminshall return -1; 179*31457Sminshall } 180*31457Sminshall return fill((char *)storage, storage_length); 181*31457Sminshall } 182*31457Sminshall 183*31457Sminshall 184*31457Sminshall static int 185*31457Sminshall doreject(message) 186*31457Sminshall char *message; 187*31457Sminshall { 188*31457Sminshall int length = strlen(message); 189*31457Sminshall char buffer[100]; 190*31457Sminshall 191*31457Sminshall length = htons(length); 192*31457Sminshall sprintf(buffer, "%c%c%c%s", EXCH_REJECTED, length>>8, length&0xff, buffer); 193*31457Sminshall if (write(sock, buffer, length+3) != length+3) { 194*31457Sminshall perror("writing API socket"); 195*31457Sminshall return -1; 196*31457Sminshall } 197*31457Sminshall return 0; 198*31457Sminshall } 199*31457Sminshall 200*31457Sminshall 20131455Sminshall /* 202*31457Sminshall * doconnect() 203*31457Sminshall * 204*31457Sminshall * Negotiate with the other side and try to do something. 205*31457Sminshall */ 206*31457Sminshall 207*31457Sminshall static int 208*31457Sminshall doconnect() 209*31457Sminshall { 210*31457Sminshall struct passwd *pwent; 211*31457Sminshall char 212*31457Sminshall promptbuf[100], 213*31457Sminshall buffer[200]; 214*31457Sminshall int promptlen, passwdlen; 215*31457Sminshall int length; 216*31457Sminshall int was; 217*31457Sminshall 218*31457Sminshall if ((pwent = getpwuid(geteuid())) == 0) { 219*31457Sminshall return -1; 220*31457Sminshall } 221*31457Sminshall sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name); 222*31457Sminshall promptlen = strlen(promptbuf); 223*31457Sminshall passwdlen = strlen(pwent->pw_name); 224*31457Sminshall sprintf(buffer, "%c%c%c%s%c%c%s", EXCH_SEND_AUTH, 225*31457Sminshall promptlen>>8, promptlen&0xff, promptbuf, 226*31457Sminshall passwdlen>>8, passwdlen&0xff, pwent->pw_name); 227*31457Sminshall length = strlen(buffer); 228*31457Sminshall if (write(sock, buffer, length) != length) { 229*31457Sminshall perror("write to API socket"); 230*31457Sminshall return -1; 231*31457Sminshall } 232*31457Sminshall if ((was = nextchar()) != EXCH_AUTH) { 233*31457Sminshall fprintf(stderr, 234*31457Sminshall "API client sent command 0x%02x when EXCH_AUTH expected.\n", was); 235*31457Sminshall } 236*31457Sminshall if ((length = nextlength()) > sizeof buffer) { 237*31457Sminshall doreject("Password entered was too long"); 238*31457Sminshall return 0; 239*31457Sminshall } 240*31457Sminshall if (fill(buffer, length) == -1) { 241*31457Sminshall return -1; 242*31457Sminshall } 243*31457Sminshall buffer[length] = 0; 244*31457Sminshall 245*31457Sminshall /* Is this the correct password? */ 246*31457Sminshall if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) == 0) { 247*31457Sminshall char code = EXCH_CONNECTED; 248*31457Sminshall if (write(sock, &code, 1) != 1) { 249*31457Sminshall perror("writing to API socket"); 250*31457Sminshall return -1; 251*31457Sminshall } 252*31457Sminshall } else { 253*31457Sminshall doreject("Invalid password"); 254*31457Sminshall sleep(10); /* Don't let us do too many of these */ 255*31457Sminshall } 256*31457Sminshall return 0; 257*31457Sminshall } 258*31457Sminshall 259*31457Sminshall 260*31457Sminshall void 261*31457Sminshall freestorage() 262*31457Sminshall { 263*31457Sminshall int i, j; 264*31457Sminshall char buffer[40]; 265*31457Sminshall 266*31457Sminshall if (storage_accessed) { 267*31457Sminshall fprintf(stderr, "Internal error - attempt to free accessed storage.\n"); 268*31457Sminshall fprintf(stderr, "(Enountered in file %s at line %s.)\n", 269*31457Sminshall __FILE__, __LINE__); 270*31457Sminshall quit(); 271*31457Sminshall } 272*31457Sminshall if (storage_must_send == 0) { 273*31457Sminshall return; 274*31457Sminshall } 275*31457Sminshall storage_must_send = 0; 276*31457Sminshall i = htonl(storage_address); 277*31457Sminshall j = htonl(storage_length); 278*31457Sminshall sprintf(buffer, "%c%c%c%c%c%c%c", 279*31457Sminshall EXCH_HEREIS, i>>24, i>>16, i>>8, i, j>>8, j); 280*31457Sminshall if (write(sock, buffer, 5) != 5) { 281*31457Sminshall perror("writing to API socket"); 282*31457Sminshall kill_connection(); 283*31457Sminshall return; 284*31457Sminshall } 285*31457Sminshall if (write(sock, (char *)storage, storage_length) != storage_length) { 286*31457Sminshall perror("writing to API socket"); 287*31457Sminshall kill_connection(); 288*31457Sminshall return; 289*31457Sminshall } 290*31457Sminshall } 291*31457Sminshall 292*31457Sminshall 293*31457Sminshall void 294*31457Sminshall getstorage(address, length) 295*31457Sminshall { 296*31457Sminshall int i, j; 297*31457Sminshall char buffer[40]; 298*31457Sminshall 299*31457Sminshall freestorage(); 300*31457Sminshall if (storage_accessed) { 301*31457Sminshall fprintf(stderr, 302*31457Sminshall "Internal error - attempt to get while storage accessed.\n"); 303*31457Sminshall fprintf(stderr, "(Enountered in file %s at line %s.)\n", 304*31457Sminshall __FILE__, __LINE__); 305*31457Sminshall quit(); 306*31457Sminshall } 307*31457Sminshall if (storage_must_send == 0) { 308*31457Sminshall return; 309*31457Sminshall } 310*31457Sminshall storage_must_send = 0; 311*31457Sminshall i = htonl(storage_address); 312*31457Sminshall j = htonl(storage_length); 313*31457Sminshall sprintf(buffer, "%c%c%c%c%c%c%c", 314*31457Sminshall EXCH_GIMME, i>>24, i>>16, i>>8, i, j>>8, j); 315*31457Sminshall if (write(sock, buffer, 5) != 5) { 316*31457Sminshall perror("writing to API socket"); 317*31457Sminshall kill_connection(); 318*31457Sminshall return; 319*31457Sminshall } 320*31457Sminshall if (nextstore() == -1) { 321*31457Sminshall kill_connection(); 322*31457Sminshall return; 323*31457Sminshall } 324*31457Sminshall } 325*31457Sminshall 326*31457Sminshall void 327*31457Sminshall movetous(local, es, di, length) 328*31457Sminshall char 329*31457Sminshall *local; 330*31457Sminshall int 331*31457Sminshall es, 332*31457Sminshall di; 333*31457Sminshall int 334*31457Sminshall length; 335*31457Sminshall { 336*31457Sminshall if (length > sizeof storage) { 337*31457Sminshall fprintf(stderr, "Internal API error - movetous() length too long.\n"); 338*31457Sminshall fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 339*31457Sminshall quit(); 340*31457Sminshall } else if (length == 0) { 341*31457Sminshall return; 342*31457Sminshall } 343*31457Sminshall getstorage(di, length); 344*31457Sminshall memcpy(local, storage+(di-storage_address), length); 345*31457Sminshall } 346*31457Sminshall 347*31457Sminshall void 348*31457Sminshall movetothem(es, di, local, length) 349*31457Sminshall int 350*31457Sminshall es, 351*31457Sminshall di; 352*31457Sminshall char 353*31457Sminshall *local; 354*31457Sminshall int 355*31457Sminshall length; 356*31457Sminshall { 357*31457Sminshall if (length > sizeof storage) { 358*31457Sminshall fprintf(stderr, "Internal API error - movetothem() length too long.\n"); 359*31457Sminshall fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 360*31457Sminshall quit(); 361*31457Sminshall } else if (length == 0) { 362*31457Sminshall return; 363*31457Sminshall } 364*31457Sminshall freestorage(); 365*31457Sminshall memcpy((char *)storage, local, length); 366*31457Sminshall storage_length = length; 367*31457Sminshall storage_address = di; 368*31457Sminshall storage_must_send = 1; 369*31457Sminshall } 370*31457Sminshall 371*31457Sminshall 372*31457Sminshall char * 373*31457Sminshall access_api(location, length) 374*31457Sminshall int 375*31457Sminshall location, 376*31457Sminshall length; 377*31457Sminshall { 378*31457Sminshall if (storage_accessed) { 379*31457Sminshall fprintf(stderr, "Internal error - storage accessed twice\n"); 380*31457Sminshall fprintf(stderr, "(Encountered in file %s, line %s.)\n", 381*31457Sminshall __FILE__, __LINE__); 382*31457Sminshall quit(); 383*31457Sminshall } else if (length != 0) { 384*31457Sminshall storage_accessed = 1; 385*31457Sminshall freestorage(); 386*31457Sminshall getstorage(location, length); 387*31457Sminshall } 388*31457Sminshall return (char *) storage; 389*31457Sminshall } 390*31457Sminshall 391*31457Sminshall unaccess_api(location, local, length) 392*31457Sminshall int location; 393*31457Sminshall char *local; 394*31457Sminshall int length; 395*31457Sminshall { 396*31457Sminshall if (storage_accessed == 0) { 397*31457Sminshall fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n"); 398*31457Sminshall fprintf(stderr, "(Encountered in file %s, line %s.)\n", 399*31457Sminshall __FILE__, __LINE__); 400*31457Sminshall quit(); 401*31457Sminshall } 402*31457Sminshall storage_accessed = 0; 403*31457Sminshall storage_must_send = 1; /* Needs to go back */ 404*31457Sminshall } 405*31457Sminshall 406*31457Sminshall 407*31457Sminshall /* 40831455Sminshall * shell_continue() actually runs the command, and looks for API 40931455Sminshall * requests coming back in. 41031455Sminshall * 41131455Sminshall * We are called from the main loop in telnet.c. 41231455Sminshall */ 41331455Sminshall 41431455Sminshall int 41531455Sminshall shell_continue() 41631455Sminshall { 417*31457Sminshall switch (state) { 418*31457Sminshall case DEAD: 419*31457Sminshall pause(); /* Nothing to do */ 420*31457Sminshall break; 421*31457Sminshall case UNCONNECTED: 422*31457Sminshall if (nextchar() != EXCH_CONNECT) { 423*31457Sminshall kill_connection(); 424*31457Sminshall } else { 425*31457Sminshall switch (doconnect()) { 426*31457Sminshall case -1: 427*31457Sminshall kill_connection(); 428*31457Sminshall break; 429*31457Sminshall case 0: 430*31457Sminshall break; 431*31457Sminshall case 1: 432*31457Sminshall state = CONNECTED; 433*31457Sminshall } 434*31457Sminshall } 435*31457Sminshall break; 436*31457Sminshall case CONNECTED: 437*31457Sminshall if (nextchar() == EXCH_REQUEST) { 438*31457Sminshall /* Eat up request packet. */ 439*31457Sminshall nextbytes(&inputRegs, sizeof inputRegs); 440*31457Sminshall nextbytes(&inputSregs, sizeof inputSregs); 441*31457Sminshall nextstore(); /* Initial storage sent */ 442*31457Sminshall handle_api(&inputRegs, &inputSregs); 443*31457Sminshall } else { 444*31457Sminshall kill_connection(); 445*31457Sminshall } 446*31457Sminshall } 44731455Sminshall return shell_active; 44831455Sminshall } 44931455Sminshall 45031455Sminshall 45131455Sminshall /* 45231455Sminshall * Called from telnet.c to fork a lower command.com. We 45331455Sminshall * use the spint... routines so that we can pick up 45431455Sminshall * interrupts generated by application programs. 45531455Sminshall */ 45631455Sminshall 45731455Sminshall 45831455Sminshall int 45931455Sminshall shell(argc,argv) 46031455Sminshall int argc; 46131455Sminshall char *argv[]; 46231455Sminshall { 463*31457Sminshall int serversock, length; 464*31457Sminshall struct sockaddr_in server; 465*31457Sminshall char sockNAME[100]; 466*31457Sminshall static char **whereAPI = 0; 467*31457Sminshall 468*31457Sminshall /* First, create the socket which will be connected to */ 469*31457Sminshall serversock = socket(AF_INET, SOCK_STREAM, 0); 470*31457Sminshall if (serversock < 0) { 471*31457Sminshall perror("opening API socket"); 472*31457Sminshall return 0; 473*31457Sminshall } 474*31457Sminshall server.sin_family = AF_INET; 475*31457Sminshall server.sin_addr.s_addr = INADDR_ANY; 476*31457Sminshall server.sin_port = 0; 477*31457Sminshall if (bind(serversock, &server, sizeof server) < 0) { 478*31457Sminshall perror("binding API socket"); 479*31457Sminshall return 0; 480*31457Sminshall } 481*31457Sminshall length = sizeof server; 482*31457Sminshall if (getsockname(serversock, &server, &length) < 0) { 483*31457Sminshall perror("getting API socket name"); 484*31457Sminshall (void) close(serversock); 485*31457Sminshall } 486*31457Sminshall listen(serversock, 1); 487*31457Sminshall /* Get name to advertise in address list */ 488*31457Sminshall strcpy(sockNAME, "API3270="); 489*31457Sminshall gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME)); 490*31457Sminshall if (strlen(sockNAME) > (sizeof sockNAME-10)) { 491*31457Sminshall fprintf(stderr, "Local hostname too large; using 'localhost'.\n"); 492*31457Sminshall strcpy(sockNAME, "localhost"); 493*31457Sminshall } 494*31457Sminshall sprintf(sockNAME+strlen(sockNAME), ":%d", ntohs(server.sin_port)); 495*31457Sminshall 496*31457Sminshall if (whereAPI == 0) { 497*31457Sminshall char **ptr, **nextenv; 498*31457Sminshall extern char **environ; 499*31457Sminshall 500*31457Sminshall ptr = environ; 501*31457Sminshall nextenv = ourENVlist; 502*31457Sminshall while (*ptr) { 503*31457Sminshall if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) { 504*31457Sminshall fprintf(stderr, "Too many environmental variables\n"); 505*31457Sminshall break; 506*31457Sminshall } 507*31457Sminshall *nextenv++ = *ptr++; 508*31457Sminshall } 509*31457Sminshall whereAPI = nextenv++; 510*31457Sminshall *nextenv++ = 0; 511*31457Sminshall environ = ourENVlist; /* New environment */ 512*31457Sminshall } 513*31457Sminshall *whereAPI = sockNAME; 514*31457Sminshall 515*31457Sminshall child_died(); /* Start up signal handler */ 516*31457Sminshall shell_active = 1; /* We are running down below */ 517*31457Sminshall if (shell_pid = vfork()) { 518*31457Sminshall if (shell_pid == -1) { 519*31457Sminshall perror("vfork"); 520*31457Sminshall (void) close(serversock); 521*31457Sminshall } else { 522*31457Sminshall fd_set fdset; 523*31457Sminshall int i; 524*31457Sminshall 525*31457Sminshall FD_ZERO(&fdset); 526*31457Sminshall FD_SET(serversock, &fdset); 527*31457Sminshall while (shell_active) { 528*31457Sminshall if ((i = select(serversock+1, &fdset, 0, 0, 0)) < 0) { 529*31457Sminshall if (errno = EINTR) { 530*31457Sminshall continue; 531*31457Sminshall } else { 532*31457Sminshall perror("in select waiting for API connection"); 533*31457Sminshall break; 534*31457Sminshall } 535*31457Sminshall } else { 536*31457Sminshall i = accept(serversock, 0, 0); 537*31457Sminshall if (i == -1) { 538*31457Sminshall perror("accepting API connection"); 539*31457Sminshall } 540*31457Sminshall sock = i; 541*31457Sminshall break; 542*31457Sminshall } 543*31457Sminshall } 544*31457Sminshall (void) close(serversock); 545*31457Sminshall /* If the process has already exited, we may need to close */ 546*31457Sminshall if ((shell_active == 0) && (sock != -1)) { 547*31457Sminshall (void) close(sock); 548*31457Sminshall sock = -1; 549*31457Sminshall setcommandmode(); /* In case child_died sneaked in */ 550*31457Sminshall } 551*31457Sminshall } 55231455Sminshall } else { /* New process */ 55331455Sminshall register int i; 55431455Sminshall 55531455Sminshall for (i = 3; i < 30; i++) { 55631455Sminshall (void) close(i); 55731455Sminshall } 55831455Sminshall if (argc == 1) { /* Just get a shell */ 55931455Sminshall char *cmdname; 560*31457Sminshall extern char *getenv(); 56131455Sminshall 56231455Sminshall cmdname = getenv("SHELL"); 56331455Sminshall execlp(cmdname, cmdname, 0); 56431455Sminshall perror("Exec'ing new shell...\n"); 56531455Sminshall exit(1); 56631455Sminshall } else { 56731455Sminshall execvp(argv[1], &argv[1]); 56831455Sminshall perror("Exec'ing command.\n"); 56931455Sminshall exit(1); 57031455Sminshall } 57131455Sminshall /*NOTREACHED*/ 57231455Sminshall } 573*31457Sminshall return shell_active; /* Go back to main loop */ 57431455Sminshall } 575