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