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