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