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