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