1 #include <sys/types.h> 2 #include <sys/socket.h> 3 #include <netinet/in.h> 4 #include <sys/wait.h> 5 6 #include <errno.h> 7 extern int errno; 8 9 #include <netdb.h> 10 #include <signal.h> 11 #include <stdio.h> 12 #include <pwd.h> 13 14 #include "../general/general.h" 15 #include "../api/api.h" 16 #include "../apilib/api_exch.h" 17 18 #include "../general/globals.h" 19 20 21 static int shell_pid = 0; 22 23 static char *ourENVlist[200]; /* Lots of room */ 24 25 static int 26 sock = -1, /* Connected socket */ 27 serversock; /* Server (listening) socket */ 28 29 static enum { DEAD, UNCONNECTED, CONNECTED } state; 30 31 static int 32 storage_location, /* Address we have */ 33 storage_length = 0, /* Length we have */ 34 storage_must_send = 0, /* Storage belongs on other side of wire */ 35 storage_accessed = 0; /* The storage is accessed (so leave alone)! */ 36 37 static long storage[1000]; 38 39 static union REGS inputRegs; 40 static struct SREGS inputSregs; 41 42 43 static void 44 kill_connection() 45 { 46 state = UNCONNECTED; 47 if (sock != -1) { 48 (void) close(sock); 49 sock = -1; 50 } 51 } 52 53 54 static int 55 nextstore() 56 { 57 struct storage_descriptor sd; 58 59 if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 60 storage_length = 0; 61 return -1; 62 } 63 storage_length = ntohs(sd.length); 64 storage_location = ntohl(sd.location); 65 if (storage_length > sizeof storage) { 66 fprintf(stderr, "API client tried to send too much storage (%d).\n", 67 storage_length); 68 storage_length = 0; 69 return -1; 70 } 71 if (storage_length != 0) { 72 if (api_exch_intype(EXCH_TYPE_BYTES, storage_length, (char *)storage) 73 == -1) { 74 storage_length = 0; 75 return -1; 76 } 77 } 78 return 0; 79 } 80 81 82 static int 83 doreject(message) 84 char *message; 85 { 86 struct storage_descriptor sd; 87 int length = strlen(message); 88 89 if (api_exch_outcommand(EXCH_CMD_REJECTED) == -1) { 90 return -1; 91 } 92 sd.length = htons(length); 93 if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 94 return -1; 95 } 96 if (api_exch_outtype(EXCH_TYPE_BYTES, length, message) == -1) { 97 return -1; 98 } 99 return 0; 100 } 101 102 103 /* 104 * doassociate() 105 * 106 * Negotiate with the other side and try to do something. 107 */ 108 109 static int 110 doassociate() 111 { 112 struct passwd *pwent; 113 char 114 promptbuf[100], 115 buffer[200]; 116 int length; 117 int was; 118 struct storage_descriptor sd; 119 120 if ((pwent = getpwuid(geteuid())) == 0) { 121 return -1; 122 } 123 sprintf(promptbuf, "Enter password for user %s:", pwent->pw_name); 124 if (api_exch_outcommand(EXCH_CMD_SEND_AUTH) == -1) { 125 return -1; 126 } 127 sd.length = htons(strlen(promptbuf)); 128 if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 129 return -1; 130 } 131 if (api_exch_outtype(EXCH_TYPE_BYTES, strlen(promptbuf), promptbuf) == -1) { 132 return -1; 133 } 134 sd.length = htons(strlen(pwent->pw_name)); 135 if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 136 return -1; 137 } 138 if (api_exch_outtype(EXCH_TYPE_BYTES, 139 strlen(pwent->pw_name), pwent->pw_name) == -1) { 140 return -1; 141 } 142 if (api_exch_incommand(EXCH_CMD_AUTH) == -1) { 143 return -1; 144 } 145 if (api_exch_intype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 146 return -1; 147 } 148 sd.length = ntohs(sd.length); 149 if (sd.length > sizeof buffer) { 150 doreject("Password entered was too long"); 151 return -1; 152 } 153 if (api_exch_intype(EXCH_TYPE_BYTES, sd.length, buffer) == -1) { 154 return -1; 155 } 156 buffer[sd.length] = 0; 157 158 /* Is this the correct password? */ 159 if (strlen(pwent->pw_name)) { 160 char *ptr; 161 int i; 162 163 ptr = pwent->pw_name; 164 i = 0; 165 while (i < sd.length) { 166 buffer[i++] ^= *ptr++; 167 if (*ptr == 0) { 168 ptr = pwent->pw_name; 169 } 170 } 171 } 172 if (strcmp(crypt(buffer, pwent->pw_passwd), pwent->pw_passwd) == 0) { 173 if (api_exch_outcommand(EXCH_CMD_ASSOCIATED) == -1) { 174 return -1; 175 } else { 176 return 1; 177 } 178 } else { 179 doreject("Invalid password"); 180 sleep(10); /* Don't let us do too many of these */ 181 return 0; 182 } 183 } 184 185 186 void 187 freestorage() 188 { 189 char buffer[40]; 190 struct storage_descriptor sd; 191 192 if (storage_accessed) { 193 fprintf(stderr, "Internal error - attempt to free accessed storage.\n"); 194 fprintf(stderr, "(Encountered in file %s at line %d.)\n", 195 __FILE__, __LINE__); 196 quit(); 197 } 198 if (storage_must_send == 0) { 199 return; 200 } 201 storage_must_send = 0; 202 if (api_exch_outcommand(EXCH_CMD_HEREIS) == -1) { 203 kill_connection(); 204 return; 205 } 206 sd.length = htons(storage_length); 207 sd.location = htonl(storage_location); 208 if (api_exch_outtype(EXCH_TYPE_STORE_DESC, sizeof sd, (char *)&sd) == -1) { 209 kill_connection(); 210 return; 211 } 212 if (storage_length != 0) { 213 if (api_exch_outtype(EXCH_TYPE_BYTES, storage_length, (char *)storage) 214 == -1) { 215 kill_connection(); 216 return; 217 } 218 } 219 } 220 221 222 static int 223 getstorage(address, length, copyin) 224 int 225 address, 226 length, 227 copyin; 228 { 229 struct storage_descriptor sd; 230 char buffer[40]; 231 232 freestorage(); 233 if (storage_accessed) { 234 fprintf(stderr, 235 "Internal error - attempt to get while storage accessed.\n"); 236 fprintf(stderr, "(Encountered in file %s at line %d.)\n", 237 __FILE__, __LINE__); 238 quit(); 239 } 240 storage_must_send = 0; 241 if (api_exch_outcommand(EXCH_CMD_GIMME) == -1) { 242 kill_connection(); 243 return -1; 244 } 245 storage_location = address; 246 storage_length = length; 247 if (copyin) { 248 sd.location = htonl(storage_location); 249 sd.length = htons(storage_length); 250 if (api_exch_outtype(EXCH_TYPE_STORE_DESC, 251 sizeof sd, (char *)&sd) == -1) { 252 kill_connection(); 253 return -1; 254 } 255 if (api_exch_incommand(EXCH_CMD_HEREIS) == -1) { 256 fprintf(stderr, "Bad data from other side.\n"); 257 fprintf(stderr, "(Encountered at %s, %d.)\n", __FILE__, __LINE__); 258 return -1; 259 } 260 if (nextstore() == -1) { 261 kill_connection(); 262 return -1; 263 } 264 } 265 return 0; 266 } 267 268 void 269 movetous(local, es, di, length) 270 char 271 *local; 272 int 273 es, 274 di; 275 int 276 length; 277 { 278 if (length > sizeof storage) { 279 fprintf(stderr, "Internal API error - movetous() length too long.\n"); 280 fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 281 quit(); 282 } else if (length == 0) { 283 return; 284 } 285 getstorage(di, length, 1); 286 memcpy(local, storage+(di-storage_location), length); 287 } 288 289 void 290 movetothem(es, di, local, length) 291 int 292 es, 293 di; 294 char 295 *local; 296 int 297 length; 298 { 299 if (length > sizeof storage) { 300 fprintf(stderr, "Internal API error - movetothem() length too long.\n"); 301 fprintf(stderr, "(detected in file %s, line %d)\n", __FILE__, __LINE__); 302 quit(); 303 } else if (length == 0) { 304 return; 305 } 306 freestorage(); 307 memcpy((char *)storage, local, length); 308 storage_length = length; 309 storage_location = di; 310 storage_must_send = 1; 311 } 312 313 314 char * 315 access_api(location, length, copyin) 316 int 317 location, 318 length, 319 copyin; /* Do we need to copy in initially? */ 320 { 321 if (storage_accessed) { 322 fprintf(stderr, "Internal error - storage accessed twice\n"); 323 fprintf(stderr, "(Encountered in file %s, line %d.)\n", 324 __FILE__, __LINE__); 325 quit(); 326 } else if (length != 0) { 327 freestorage(); 328 getstorage(location, length, copyin); 329 storage_accessed = 1; 330 } 331 return (char *) storage; 332 } 333 334 unaccess_api(location, local, length, copyout) 335 int location; 336 char *local; 337 int length; 338 { 339 if (storage_accessed == 0) { 340 fprintf(stderr, "Internal error - unnecessary unaccess_api call.\n"); 341 fprintf(stderr, "(Encountered in file %s, line %d.)\n", 342 __FILE__, __LINE__); 343 quit(); 344 } 345 storage_accessed = 0; 346 storage_must_send = copyout; /* if needs to go back */ 347 } 348 349 /* 350 * Accept a connection from an API client, aborting if the child dies. 351 */ 352 353 static int 354 doconnect() 355 { 356 fd_set fdset; 357 int i; 358 359 sock = -1; 360 FD_ZERO(&fdset); 361 while (shell_active && (sock == -1)) { 362 FD_SET(serversock, &fdset); 363 if ((i = select(serversock+1, &fdset, 0, 0, 0)) < 0) { 364 if (errno = EINTR) { 365 continue; 366 } else { 367 perror("in select waiting for API connection"); 368 return -1; 369 } 370 } else { 371 i = accept(serversock, 0, 0); 372 if (i == -1) { 373 perror("accepting API connection"); 374 return -1; 375 } 376 sock = i; 377 } 378 } 379 /* If the process has already exited, we may need to close */ 380 if ((shell_active == 0) && (sock != -1)) { 381 (void) close(sock); 382 sock = -1; 383 setcommandmode(); /* In case child_died sneaked in */ 384 } 385 } 386 387 /* 388 * shell_continue() actually runs the command, and looks for API 389 * requests coming back in. 390 * 391 * We are called from the main loop in telnet.c. 392 */ 393 394 int 395 shell_continue() 396 { 397 int i; 398 399 switch (state) { 400 case DEAD: 401 pause(); /* Nothing to do */ 402 break; 403 case UNCONNECTED: 404 if (doconnect() == -1) { 405 kill_connection(); 406 return -1; 407 } 408 if (api_exch_init(sock, "server") == -1) { 409 return -1; 410 } 411 while (state == UNCONNECTED) { 412 if (api_exch_incommand(EXCH_CMD_ASSOCIATE) == -1) { 413 kill_connection(); 414 return -1; 415 } else { 416 switch (doassociate()) { 417 case -1: 418 kill_connection(); 419 return -1; 420 case 0: 421 break; 422 case 1: 423 state = CONNECTED; 424 } 425 } 426 } 427 break; 428 case CONNECTED: 429 switch (i = api_exch_nextcommand()) { 430 case EXCH_CMD_REQUEST: 431 if (api_exch_intype(EXCH_TYPE_REGS, sizeof inputRegs, 432 (char *)&inputRegs) == -1) { 433 kill_connection(); 434 } else if (api_exch_intype(EXCH_TYPE_SREGS, sizeof inputSregs, 435 (char *)&inputSregs) == -1) { 436 kill_connection(); 437 } else if (nextstore() == -1) { 438 kill_connection(); 439 } else { 440 handle_api(&inputRegs, &inputSregs); 441 freestorage(); /* Send any storage back */ 442 if (api_exch_outcommand(EXCH_CMD_REPLY) == -1) { 443 kill_connection(); 444 } else if (api_exch_outtype(EXCH_TYPE_REGS, sizeof inputRegs, 445 (char *)&inputRegs) == -1) { 446 kill_connection(); 447 } else if (api_exch_outtype(EXCH_TYPE_SREGS, sizeof inputSregs, 448 (char *)&inputSregs) == -1) { 449 kill_connection(); 450 } 451 /* Done, and it all worked! */ 452 } 453 break; 454 case EXCH_CMD_DISASSOCIATE: 455 kill_connection(); 456 break; 457 default: 458 if (i != -1) { 459 fprintf(stderr, 460 "Looking for a REQUEST or DISASSOCIATE command\n"); 461 fprintf(stderr, "\treceived 0x%02x.\n", i); 462 } 463 kill_connection(); 464 break; 465 } 466 } 467 return shell_active; 468 } 469 470 471 static int 472 child_died() 473 { 474 union wait *status; 475 register int pid; 476 477 while ((pid = wait3(&status, WNOHANG, 0)) > 0) { 478 if (pid == shell_pid) { 479 char inputbuffer[100]; 480 481 shell_active = 0; 482 if (sock != -1) { 483 (void) close(sock); 484 sock = -1; 485 } 486 printf("[Hit return to continue]"); 487 fflush(stdout); 488 (void) gets(inputbuffer); 489 setconnmode(); 490 ConnectScreen(); /* Turn screen on (if need be) */ 491 (void) close(serversock); 492 } 493 } 494 signal(SIGCHLD, child_died); 495 } 496 497 498 /* 499 * Called from telnet.c to fork a lower command.com. We 500 * use the spint... routines so that we can pick up 501 * interrupts generated by application programs. 502 */ 503 504 505 int 506 shell(argc,argv) 507 int argc; 508 char *argv[]; 509 { 510 int length; 511 struct sockaddr_in server; 512 char sockNAME[100]; 513 static char **whereAPI = 0; 514 515 /* First, create the socket which will be connected to */ 516 serversock = socket(AF_INET, SOCK_STREAM, 0); 517 if (serversock < 0) { 518 perror("opening API socket"); 519 return 0; 520 } 521 server.sin_family = AF_INET; 522 server.sin_addr.s_addr = INADDR_ANY; 523 server.sin_port = 0; 524 if (bind(serversock, &server, sizeof server) < 0) { 525 perror("binding API socket"); 526 return 0; 527 } 528 length = sizeof server; 529 if (getsockname(serversock, &server, &length) < 0) { 530 perror("getting API socket name"); 531 (void) close(serversock); 532 } 533 listen(serversock, 1); 534 /* Get name to advertise in address list */ 535 strcpy(sockNAME, "API3270="); 536 gethostname(sockNAME+strlen(sockNAME), sizeof sockNAME-strlen(sockNAME)); 537 if (strlen(sockNAME) > (sizeof sockNAME-10)) { 538 fprintf(stderr, "Local hostname too large; using 'localhost'.\n"); 539 strcpy(sockNAME, "localhost"); 540 } 541 sprintf(sockNAME+strlen(sockNAME), ":%d", ntohs(server.sin_port)); 542 543 if (whereAPI == 0) { 544 char **ptr, **nextenv; 545 extern char **environ; 546 547 ptr = environ; 548 nextenv = ourENVlist; 549 while (*ptr) { 550 if (nextenv >= &ourENVlist[highestof(ourENVlist)-1]) { 551 fprintf(stderr, "Too many environmental variables\n"); 552 break; 553 } 554 *nextenv++ = *ptr++; 555 } 556 whereAPI = nextenv++; 557 *nextenv++ = 0; 558 environ = ourENVlist; /* New environment */ 559 } 560 *whereAPI = sockNAME; 561 562 child_died(); /* Start up signal handler */ 563 shell_active = 1; /* We are running down below */ 564 if (shell_pid = vfork()) { 565 if (shell_pid == -1) { 566 perror("vfork"); 567 (void) close(serversock); 568 } else { 569 state = UNCONNECTED; 570 } 571 } else { /* New process */ 572 register int i; 573 574 for (i = 3; i < 30; i++) { 575 (void) close(i); 576 } 577 if (argc == 1) { /* Just get a shell */ 578 char *cmdname; 579 extern char *getenv(); 580 581 cmdname = getenv("SHELL"); 582 execlp(cmdname, cmdname, 0); 583 perror("Exec'ing new shell...\n"); 584 exit(1); 585 } else { 586 execvp(argv[1], &argv[1]); 587 perror("Exec'ing command.\n"); 588 exit(1); 589 } 590 /*NOTREACHED*/ 591 } 592 return shell_active; /* Go back to main loop */ 593 } 594