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